Странный вывод ультразвукового датчика Arduino

Итак, я только что подключился к Arduino, купил комплект автомобильного робота Elegoo v3 и собрал его, но когда я поставил робота на «избегание объектов», он постоянно вращается, как будто перед ним находится объект. Я попытался изменить код, и мне не повезло, поэтому я подумал, что это может быть сам датчик, когда подключил его и запустил:

void loop() {
   a=sr04.Distance();
   Serial.print(a);
   Serial.println("cm");
   delay(1000);
}

Он отображал правильные расстояния, поэтому я решил, что это не может быть датчик. Любопытная вещь произошла, когда я добавил несколько строк в код автомобиля, чтобы он также печатал расстояние, которое он видел, и когда датчик подключен к машине по какой-либо причине, все, что он видит, составляет 18 см независимо от фактического расстояния, что объясняет, почему он постоянно вращается. Я нашел проблему, но теперь моя проблема в том, что я не могу понять, почему он постоянно определяет только 18 см, когда подключен к машине.

#include <SR04.h>

/*
 * @Description: Rocker_Control
 * @Author: HOU Changhua
 * @Date: 2019-08-12 18:00:25
 * @LastEditTime: 2019-08-27 10:45:29
 * @LastEditors: Please set LastEditors
 */
#include <Servo.h>
#include <stdio.h>
#include "HardwareSerial.h"
#include "ArduinoJson-v6.11.1.h" //ArduinoJson

/*Driving Interface for Ultrasound Ranging*/
#define ECHO_PIN A4
#define TRIG_PIN A5

/*Motor Drive Interface*/
#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11

/*Driving Interface for Infrared Pipeline Patrol*/
#define LineTeacking_Pin_Right 10
#define LineTeacking_Pin_Middle 4
#define LineTeacking_Pin_Left 2
#define LineTeacking_Read_Right !digitalRead(10)
#define LineTeacking_Read_Middle !digitalRead(4)
#define LineTeacking_Read_Left !digitalRead(2)

#define carSpeed 180 //ШИМ (то есть: скорость двигателя/скорость автомобиля)

Servo servo;
unsigned long IR_PreMillis;
unsigned long LT_PreMillis;

enum FUNCTIONMODE
{
  IDLE,
  LineTeacking,
  ObstaclesAvoidance,
  Bluetooth,

} func_mode = IDLE; /*Functional model*/

enum MOTIONMODE
{
  STOP,
  FORWARD,
  BACK,
  LEFT,
  RIGHT
} mov_mode = STOP; /*Motion model*/

void delays(unsigned long t)
{

  for (unsigned long i = 0; i < t; i++)
  {
    getBTData_Plus();
    delay(1);
  }
}

/*Acquisition Distance: Ultrasound*/
unsigned int getDistance(void)
{
  static unsigned int tempda = 0;
  unsigned int tempda_x = 0;
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  tempda_x = ((unsigned int)pulseIn(ECHO_PIN, HIGH) / 58);
  if (tempda_x < 150)
  {
    tempda = tempda_x;
  }
  else
  {
    tempda = 30;
  }
  return tempda;
}
/*Control motor: */
void forward(bool debug, int16_t in_carSpeed)
{

  analogWrite(ENA, in_carSpeed);
  analogWrite(ENB, in_carSpeed);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  if (debug)
    Serial.println("Go forward!");
}

/*Control motor: */
void back(bool debug, int16_t in_carSpeed)
{

  analogWrite(ENA, in_carSpeed);
  analogWrite(ENB, in_carSpeed);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  if (debug)
    Serial.println("Go back!");
}
/*Control motor:*/
void left(bool debug, int16_t in_carSpeed)
{
  analogWrite(ENA, 250);
  analogWrite(ENB, 250);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);

  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  if (debug)
    Serial.println("Go left!");
}
/*Control motor:*/
void right(bool debug, int16_t in_carSpeed)
{
  analogWrite(ENA, 250);
  analogWrite(ENB, 250);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  if (debug)
    Serial.println("Go right!");
}
/*Control motor:*/
void stop(bool debug = false)
{
  digitalWrite(ENA, LOW);
  digitalWrite(ENB, LOW);
  if (debug)
    Serial.println("Stop!");
}
/*
  Bluetooth serial port data acquisition and control command parsing
*/
void getBTData_Plus(void)
{
  String comdata = "";

  while ((Serial.available() > 0) && (false == comdata.endsWith("}")))
  {
    comdata += char(Serial.read());
    delay(3);
  }
  if ((comdata.length() > 0) && (comdata != "") && (true == comdata.endsWith("}")))
  {
    StaticJsonDocument<200> doc;                                //Создаем объект JsonDocument
    DeserializationError error = deserializeJson(doc, comdata); //Десериализовать данные JSON
    if (!error)                                                 //Проверяем успешность десериализации
    {
      int control_mode_N = doc["N"];
      char buf[3];
      uint8_t temp = doc["H"];
      sprintf(buf, "%d", temp);
      String CommandSerialNumber = buf; //Получить серийный номер новой команды

      switch (control_mode_N)
      {
      case 5: /*Clear mode  processing <command:N 5>*/
        func_mode = Bluetooth;
        mov_mode = STOP;
        Serial.print('{' + CommandSerialNumber + "_ok}");
        break;
      case 3:               /*Remote switching mode  processing <command:N 3>*/
        if (1 == doc["D1"]) // Режим сдвига строки
        {
          func_mode = LineTeacking;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        else if (2 == doc["D1"]) //Режим обхода препятствий
        {
          func_mode = ObstaclesAvoidance;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        break;
      case 2: /*Remote switching mode  processing <command:N 2>*/

        if (1 == doc["D1"])
        {
          func_mode = Bluetooth;
          mov_mode = LEFT;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        else if (2 == doc["D1"])
        {
          func_mode = Bluetooth;
          mov_mode = RIGHT;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        else if (3 == doc["D1"])
        {
          func_mode = Bluetooth;
          mov_mode = FORWARD;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        else if (4 == doc["D1"])
        {
          func_mode = Bluetooth;
          mov_mode = BACK;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        else if (5 == doc["D1"])
        {
          func_mode = Bluetooth;
          mov_mode = STOP;
          Serial.print('{' + CommandSerialNumber + "_ok}");
        }
        break;
      default:
        break;
      }
    }
  }
}

/*Bluetooth remote control mode*/
void bluetooth_mode()
{
  if (func_mode == Bluetooth)
  {
    switch (mov_mode)
    {
    case FORWARD:
      forward(false, carSpeed);
      break;
    case BACK:
      back(false, carSpeed);
      break;
    case LEFT:
      left(false, carSpeed);
      break;
    case RIGHT:
      right(false, carSpeed);
      break;
    case STOP:
      stop();
      break;
    default:
      break;
    }
  }
}
/*
  Line Teacking Mode
*/
void line_teacking_mode(void)
{
  if (func_mode == LineTeacking)
  {
    if (LineTeacking_Read_Middle)
    {                           //Обнаружение в средней инфракрасной трубке
      forward(false, carSpeed); //Управляющий двигатель: автомобиль движется вперед
      LT_PreMillis = millis();
    }
    else if (LineTeacking_Read_Right)
    {                         //Обнаружение в правой инфракрасной трубке
      right(false, carSpeed); //Управляющий мотор: машина движется вправо
      while (LineTeacking_Read_Right)
      {
        getBTData_Plus(); //Сбор данных Bluetooth
      }
      LT_PreMillis = millis();
    }
    else if (LineTeacking_Read_Left)
    {                        // Обнаружение в левой инфракрасной трубке
      left(false, carSpeed); //Управляющий мотор: автомобиль движется влево
      while (LineTeacking_Read_Left)
      {
        getBTData_Plus(); //Сбор данных Bluetooth
      }
      LT_PreMillis = millis();
    }
    else
    {
      if (millis() - LT_PreMillis > 150)
      {
        stop(); // Остановить управление двигателем: отключить режим привода двигателя
      }
    }
  }
}
/*f(x) int */
static boolean function_xxx(long xd, long sd, long ed) //f(x)
{
  if (sd <= xd && xd <= ed)
    return true;
  else
    return false;
}
/*Obstacle avoidance*/
void obstacles_avoidance_mode(void)
{
  static uint16_t ULTRASONIC_Get = 0;
  static unsigned long ULTRASONIC_time = 0;
  static boolean stateCar = false;
  static boolean CarED = false;
  static uint8_t switc_ctrl = 0x00;
  static boolean timestamp = true;
   Serial.print(A4);
   Serial.println("cm");
   delay(1000);

  if (func_mode == ObstaclesAvoidance)
  {
    servo.attach(3);
    if (millis() - ULTRASONIC_time > 100)
    {
      ULTRASONIC_Get = getDistance(); //Измерение расстояния до препятствия
      ULTRASONIC_time = millis();
      if (function_xxx(ULTRASONIC_Get, 0, 30)) //Если расстояние меньше Xсм препятствий
      {
        stateCar = true;
        stop(); //останавливаться
      }
      else
      {
        stateCar = false;
      }
    }
    if (false == CarED)
    {
      if (stateCar == true)
      {
        timestamp = true;
        CarED = true;
        switc_ctrl = 0x00;
        stop();          //останавливаться
        servo.write(30); //устанавливает положение сервопривода в соответствии со значением
        delays(500);
        if (function_xxx(getDistance(), 0, 25)) //Сколько см впереди есть препятствия?
        {
          switc_ctrl |= 0x01;
          //идти к
        }
        else
        {
          switc_ctrl &= (~0x01);
        }
        servo.write(150); //устанавливает положение сервопривода в соответствии со значением
        delays(500);
        if (function_xxx(getDistance(), 0, 25)) //Сколько см впереди есть препятствия?
        {
          switc_ctrl |= 0x02;
          //идти к
        }
        else
        {
          switc_ctrl &= (~0x02);
        }
        servo.write(90); // сообщаем сервоприводу перейти в позицию в переменной 30
        delays(500);
        if (function_xxx(getDistance(), 0, 25)) //Сколько см впереди есть препятствия?
        {
          switc_ctrl |= 0x04;
          //идти к
        }
        else
        {
          switc_ctrl &= (~0x04);
        }
      }
      else
      {
        forward(false, 180); //Управляющий двигатель: автомобиль движется вперед
        CarED = false;
      }
    }

    if (true == CarED)
    {
      // Получить процессорное время
      static unsigned long MotorRL_time;
      if (timestamp == true || millis() - MotorRL_time > 420)
      {
        timestamp = false;
        MotorRL_time = millis();
      }
      if (function_xxx((millis() - MotorRL_time), 0, 400))
      {
        switch (switc_ctrl)
        {
        case 0 ... 1:
          left(false, 150); //Управляющий двигатель: автомобиль движется вперед и влево
          break;
        case 2:
          right(false, 150); //Управляющий двигатель: автомобиль движется вперед и вправо
          break;
        case 3:
          forward(false, 150); //Управляющий двигатель: автомобиль движется вперед
          break;
        case 4 ... 5:
          left(false, 150); //Управляющий двигатель: автомобиль движется вперед и влево
          break;
        case 6:
          right(false, 100); //Управляющий двигатель: автомобиль движется вперед и вправо
          break;
        case 7:
          back(false, 150); //Управляющий двигатель: автомобиль движется назад
          break;
        }
      }
      else
      {
        CarED = false;
      }
    }
  }
  else
  {
    servo.detach();
    ULTRASONIC_Get = 0;
    ULTRASONIC_time = 0;
  }
}
void setup(void)
{
  Serial.begin(9600);         //инициализация
  servo.attach(3, 500, 2400); //500: 0 градусов 2400: 180 градусов
  servo.write(90);            // устанавливает положение сервопривода в соответствии с 90 (средним)

  pinMode(ECHO_PIN, INPUT); //Инициализация ультразвукового модуля
  pinMode(TRIG_PIN, OUTPUT);

  pinMode(IN1, OUTPUT); // Конфигурация моторизованного порта
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);

  pinMode(LineTeacking_Pin_Right, INPUT); // Конфигурация порта модуля инфракрасного слежения
  pinMode(LineTeacking_Pin_Middle, INPUT);
  pinMode(LineTeacking_Pin_Left, INPUT);
}

void loop(void)
{
  getBTData_Plus();           //Сбор данных Bluetooth
  bluetooth_mode();           //Удаленный режим Bluetooth
  line_teacking_mode();       //Режим линейного тикинга
  obstacles_avoidance_mode(); //Режим обхода препятствий
}

Новая отладка:

/*Acquisition Distance: Ultrasound*/
unsigned int getDistance(void)
{
  static unsigned int tempda = 0;
  unsigned int tempda_x = 0;
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  tempda_x = ((unsigned int)pulseIn(ECHO_PIN, HIGH) / 58);
  if (tempda_x < 150)
  {
    tempda = tempda_x;
  }
  else
  {
    tempda = 30;
  }
  Serial.print(tempda);
  Serial.println("cm");
  delay(1000);
  return tempda;
}

, 👍2

Обсуждение

Вы уже поняли, что это не аппаратная проблема, а программная. Но вы не показали нам свой код. Мы не можем волшебным образом увидеть это. Пожалуйста, отредактируйте свой вопрос, чтобы включить фактический проблемный код (пожалуйста, полный рабочий пример)., @chrisl

Я пытаюсь опубликовать код, но когда я его копирую и вставляю, формат портится, и у меня возникают проблемы с тем, чтобы он оставался в блоке., @Jordan

Вставьте код. Затем выделите код и щелкните значок stackexchange.com для кода. (О, я вижу, вы смогли вставить код в свой вопрос, хорошо.) Кстати, угадайте, у вас, вероятно, проблема с источником питания / батареей. Что вы используете? А если более одного типа источника питания, то когда вы их используете?, @st2000

Источником питания является литиевая батарея 7,4 В емкостью 4000 мАч., @Jordan

Мне также наконец удалось отформатировать код, спасибо!, @Jordan

Проголосуйте за то, что заботитесь о читаемости списка программ, не спрашивая об этом, @jsotola


3 ответа


0

Serial.print(A4) не имеет смысла, он просто напрямую считывает контакт GPIO (0 или 1). Возможно, это утверждение на самом деле искажает конфигурацию GPIO и искажает измерение расстояния. Вам нужно использовать функцию getDistance(). Для отладки попробуйте напечатать возвращаемое значение tempda непосредственно перед оператором return. Тем не менее, вам может понадобиться преобразовать время эхо-сигнала в расстояние в сантиметрах.

,

Я удалил строку Serial.print и добавил код отладки, но, поскольку я очень новичок в этом, я считаю, что что-то напутал, поскольку он больше не показывает мне расстояние в последовательном мониторе., @Jordan

Я поместил новую отладку выше, так как не могу отформатировать ее в форме комментария., @Jordan


0

Я использую ультразвуковой датчик для определения уровня воды в резервуаре для воды моей системы орошения. Следующий фрагмент кода для измерения расстояния у меня отлично работает. Я бы предложил заменить:

tempda_x = ((unsigned int)pulseIn(ECHO_PIN, HIGH) / 58);

(Кстати, что такое 58?) со следующим:

long duration;
duration = pulseIn(ECHO_PIN, HIGH);
tempda_x = duration*0.034029/2;

0,034029 — скорость звука в секунду (м/с). Умноженное на время, необходимое для возврата звука, деленное на 2, дает нам расстояние от объекта.

Надеюсь, это поможет.

,

Не совсем уверен, что такое 58, так как это в основном код робота-автомобиля Elegoo v3. Однако, когда я заменяю эту строку на вашу, она говорит мне, что "длительность не была объявлена в этой области", @Jordan

Упс, моя ошибка. Я забыл упомянуть, что нужно объявить продолжительность в верхней части вашего скрипта как большая продолжительность; или просто в функции getDistance..., @iHelp


1

Добро пожаловать в удивительный мир программирования и робототехники Arduino!

Как вы уже поняли, иногда магия не работает с первым заклинанием, поэтому требуется некоторая работа, чтобы правильно произнести заклинание ;-).

При устранении неполадок со сложной системой, такой как комплект Elegoo, который у вас есть, полезно начать с радикального упрощения, чтобы установить рабочий базовый план, а затем постепенно усложнять, пока не возникнет проблемное поведение. Затем вы можете сосредоточиться на (надеюсь) меньшем фрагменте кода, вызвавшем проблему, без необходимости пробираться через строки и строки ненужного программирования.

Похоже, что вы начали в правильном направлении с вашей простой программой для отображения расстояния один раз в секунду, так что у вас есть правильное представление. Если вы еще этого не сделали, я предлагаю вам создать совершенно новый скетч Arduino, используя только ваши измерения один раз в секунду как всю программу (плюс #include, необходимый для доступа к датчику). После того, как вы запустите его изолированно, добавьте только функцию obstacles_avoidance_mode(void) вместе с некоторыми операторами печати для инструментирования различных деревьев решений функции. Например, я мог бы упростить функцию примерно так:

void obstacles_avoidance_mode(void)
{
  static uint16_t ULTRASONIC_Get = 0;
  static unsigned long ULTRASONIC_time = 0;
  ULTRASONIC_Get = getDistance(); //Измерение расстояния до препятствия
  ULTRASONIC_time = millis();
  Serial.print("time = ");Serial.print(ULTRASONIC_time);
  Serial.print(", dist = ");Serial.println(ULTRASONIC_Get);
 }

Затем добавьте требуемую функцию getDistance() в конец новой тестовой программы и вызывайте obstacles_avoidance_mode(void) один раз в секунду. После того, как вы удовлетворите эту работу, начните добавлять небольшие части «obstacles_avoidance_mode(void)» по одному вместе с любыми предварительными условиями, необходимыми для принудительного выполнения каждой небольшой секции, поскольку вы вызываете изменение сообщаемого датчиком расстояния, перемещая руку к датчику и от него. Не беспокойтесь обо всех двигателях и/или сервоприводах; вы можете подключить их позже по мере необходимости.

Сделав это, вы должны очень быстро понять, как программа принимает решения, не увязая во всех других вещах, происходящих в полном коде робота.

Надеюсь, это поможет,

Фрэнк

,