Последовательная связь с HC-05 - Arduino UNO
Я новичок на сайте, и это мой первый вопрос. Я постараюсь описать свою проблему как можно лучше.
Я получил следующий код для своего проекта, который в основном состоит в том, чтобы заставить автомобиль иметь 2 режима вождения, автоматический и ручной.
Насколько я могу судить, у меня все работает, за исключением того, что это не так. Я получил HC-05, подключенный к моему двигателю L293D (подключенному к Arduino UNO), а также 2 двигателя постоянного тока, ультразвуковой датчик HC-SR04 и светодиод. Часть схемы не является проблемой, мне удалось подключить все это, и оно работает (я протестировал часть, избегающую препятствий, сам по себе, прежде чем добавить код выбора режима, поэтому я знаю, что двигатели и датчик выполняют свою работу). Я также должен упомянуть, что я отправляю информацию через BT из приложения, которое я создал в APP Inventor. Приложение работает нормально, и я действительно получаю правильные данные на последовательном мониторе.
Что меня озадачивает, так это то, почему я не могу присвоить значение Serial.read(); моей переменной ответа (соотв.). Я попытаюсь объяснить это немного подробнее. В моем последовательном мониторе я получаю нужные символы с кнопок приложения, однако моя переменная “resp”, похоже, не получает никакого значения от Serial.read(); по какой-то причине, потому что, когда она переходит к оператору switch, даже если символ напечатан на мониторе, например, дела не начинаются, и я могу полностью отключиться, как только я получу " 1 " на мониторе, я также должен начать печатать измерение расстояния на мониторе, а это не так.
Насколько я понимаю, я полагаю, что проблема заключается между Serial.write() и Serial.println()/.read(); поскольку serial.write (), похоже, имеет приоритет над всеми остальными, поскольку установка этих строк в качестве комментариев не влияет на запись на мониторе:
if(Serial.available()>0){
//resp = Serial.read();
//Serial.println(resp);
У меня нет идей, так что любая помощь или руководство в правильном направлении будут высоко оценены.
//Incluir librerias para controlar motor shield y sensor ultrasonico.
#include <AFMotor.h>
#include <NewPing.h>
#include <SoftwareSerial.h>
//Definir constantes y variables.
#define TRIG_P A4
#define ECHO_P A5
#define MAX_DIST 300
#define MAX_Vel 200
int led = A0;
int speedSet;
int iteraciones = 5;
float distancia, duracion;
char resp;
//Inicializar objetos del sensor y motores.
NewPing sonar(TRIG_P, ECHO_P, MAX_DIST);
AF_DCMotor motorD(2);
AF_DCMotor motorI(1);
SoftwareSerial BTSerial(A1, A2); // RX | TX
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
BTSerial.begin(9600);
}
void loop() {
//Lee información del BT y la escribe en el monitor serial.
if (BTSerial.available()){
Serial.write(BTSerial.read());
Serial.write('\n');
}
delay(24); //Tiempo maximo que tarda en recibir una medición.
/*Calcular la distancia frente al sensor utilizando la duración de la señal,
la cual mide ida y vuelva por lo cual se divide entre 2
y se multiplica por la velocidad del sonido (343 m/s).
*/
duracion = sonar.ping_median(iteraciones);
distancia = (duracion/2)*0.0343;
if(Serial.available()>0){
resp = Serial.read();
Serial.println(resp);
switch(resp){
case '1':
delay(24); //Tiempo maximo que tarda en recibir una medición.
/*Calcular la distancia frente al sensor utilizando la duración de la señal,
la cual mide ida y vuelva por lo cual se divide entre 2
y se multiplica por la velocidad del sonido (343 m/s).
*/
duracion = sonar.ping_median(iteraciones);
distancia = (duracion/2)*0.0343;
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.println(" cm");
if(distancia!=0 && distancia<=20){
digitalWrite(led,HIGH);
ALTO();
delay(100);
REVERSA();
delay(400);
IZQUIERDA();
delay(100);
}else
digitalWrite(led,LOW);
ADELANTE();
break;
case '2':
ALTO();
switch(resp){
case 'A':
ADELANTE();
break;
case 'R':
REVERSA();
break;
case 'I':
IZQUIERDA();
break;
case 'D':
DERECHA();
break;
case 'O':
ALTO();
break;
}
break;
}
}
}
// Inician metodos que definen las acciones del carro.
void ADELANTE(){
motorD.run(FORWARD);
motorI.run(FORWARD);
for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
motorD.setSpeed(speedSet + 20);
motorI.setSpeed(speedSet - 20);
}
}
void REVERSA(){
motorD.run(BACKWARD);
motorI.run(BACKWARD);
for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
motorD.setSpeed(speedSet + 20);
motorI.setSpeed(speedSet - 20);
}
}
void DERECHA() {
motorD.run(RELEASE);
motorI.run(FORWARD);
delay(300);
motorD.run(FORWARD);
motorI.run(FORWARD);
}
void IZQUIERDA() {
motorD.run(FORWARD);
motorI.run(RELEASE);
delay(300);
motorD.run(FORWARD);
motorI.run(FORWARD);
}
void ALTO(){
motorD.run(RELEASE);
motorI.run(RELEASE);
}
Вот изображение того, что я получаю на своем последовательном мониторе.
ОБНОВЛЕНИЕ:
Как предложил @chrisl, теперь я смотрю на это с другой точки зрения.
Я отправлял информацию BT на последовательный монитор, когда идея, в первую очередь, заключалась в том, чтобы автомобиль ездил без подключения к компьютеру вообще.
Поэтому вместо того, чтобы отправлять информацию на последовательный монитор и пытаться извлечь ее оттуда, я просто перенес значение из BTSerial в свою переменную, и теперь это работает так, как задумывалось.
"Автоматический режим" работает, моя инструкция switch распознает значение resp и начинает измерять и печатать расстояние, однако, как только я нажимаю "2", активируется первая команда и двигатели останавливаются, но все остальные инструкции не работают. Я даже изменил свой второй статус переключения на "если", но это тоже не помогло.
Вот мой новый последовательный вывод (9600 / Новая строка / COM5):
1
Distancia: 46.84 cm
Distancia: 154.74 cm
Distancia: 154.33 cm
Distancia: 154.68 cm
Distancia: 154.33 cm
Distancia: 155.70 cm
Distancia: 13.09 cm
Distancia: 12.74 cm
Distancia: 155.16 cm
Distancia: 155.77 cm
Distancia: 155.22 cm
Distancia: 154.81 cm
Distancia: 155.29 cm
Distancia: 155.22 cm
Distancia: 155.22 cm
2
A
R
I
@
D
O
1
Distancia: 155.43 cm
Distancia: 155.50 cm
Distancia: 155.57 cm
Distancia: 155.50 cm
Distancia: 155.09 cm
Distancia: 155.50 cm
Distancia: 155.09 cm
Distancia: 156.32 cm
Distancia: 155.57 cm
Distancia: 155.16 cm
Distancia: 155.09 cm
Distancia: 155.09 cm
Distancia: 155.50 cm
2
И мой обновленный код:
//Incluir librerias para controlar motor shield y sensor ultrasonico.
#include <AFMotor.h>
#include <NewPing.h>
#include <SoftwareSerial.h>
//Definir constantes y variables.
#define TRIG_P A4
#define ECHO_P A5
#define MAX_DIST 300
#define MAX_Vel 200
int led = A0;
int speedSet;
int iteraciones = 5;
float distancia, duracion;
char resp;
//Inicializar objetos del sensor y motores.
NewPing sonar(TRIG_P, ECHO_P, MAX_DIST);
AF_DCMotor motorD(2);
AF_DCMotor motorI(1);
SoftwareSerial BTSerial(A1, A2); // RX | TX
void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
BTSerial.begin(9600);
}
void loop() {
//Lee información del BT y la escribe en el monitor serial.
if (BTSerial.available()){
resp = BTSerial.read();
Serial.println(resp);
}
// if(Serial.available()>0){
// resp = Serial.read();
// Serial.println(resp);
switch(resp){
case '1':
delay(24); //Tiempo maximo que tarda en recibir una medición.
/*Calcular la distancia frente al sensor utilizando la duración de la señal,
la cual mide ida y vuelva por lo cual se divide entre 2
y se multiplica por la velocidad del sonido (343 m/s).
*/
duracion = sonar.ping_median(iteraciones);
distancia = (duracion/2)*0.0343;
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.println(" cm");
if(distancia!=0 && distancia<=20){
digitalWrite(led,HIGH);
ALTO();
delay(100);
REVERSA();
delay(400);
IZQUIERDA();
delay(100);
}else
digitalWrite(led,LOW);
ADELANTE();
break;
case '2':
ALTO();
if(resp == 'A'){
ADELANTE();
} else if (resp == 'R'){
REVERSA();
} else if (resp == 'I'){
IZQUIERDA();
} else if (resp == 'D'){
DERECHA();
} else if (resp == 'O'){
ALTO();
}
break;
}
}
// }
// Inician metodos que definen las acciones del carro.
void ADELANTE(){
motorD.run(FORWARD);
motorI.run(FORWARD);
for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
motorD.setSpeed(speedSet + 20);
motorI.setSpeed(speedSet - 20);
}
}
void REVERSA(){
motorD.run(BACKWARD);
motorI.run(BACKWARD);
for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
motorD.setSpeed(speedSet + 20);
motorI.setSpeed(speedSet - 20);
}
}
void DERECHA() {
motorD.run(RELEASE);
motorI.run(FORWARD);
delay(300);
motorD.run(FORWARD);
motorI.run(FORWARD);
}
void IZQUIERDA() {
motorD.run(FORWARD);
motorI.run(RELEASE);
delay(300);
motorD.run(FORWARD);
motorI.run(FORWARD);
}
void ALTO(){
motorD.run(RELEASE);
motorI.run(RELEASE);
}
@Genaro Basoria, 👍0
1 ответ
Я предполагаю, что основная проблема в том, что вы пишете свои команды из приложения Bluetooth, но модуль HC-05 подключен к BTSerial
. Здесь вы считываете с него и пересылаете данные на последовательный
(последовательный монитор на вашем ПК):
if (BTSerial.available()){
Serial.write(BTSerial.read());
Serial.write('\n');
}
Вы больше ничего не делаете с последовательными данными bluetooth, поэтому вы не можете изменить переменную resp
по Bluetooth. Вместо этого вы делаете это с помощью Serial
(не BTSerial
). Но до тех пор, пока вы не введете команды в последовательный монитор, этот код никогда не будет запущен. Таким образом, код расстояния никогда не будет выполнен.
Если вы хотите управлять программой из приложения bluetoooth, вам нужно фактически работать с данными из правильного последовательного интерфейса.
Кстати: Ваш последовательный монитор настроен для новой строки в качестве символа окончания строки. Ваш серийный
код не отбрасывает их, поэтому вы можете получить нежелательное поведение там, когда resp
станет \n
.
О вашей новой проблеме: Эта проблема действительно существовала и со старым кодом, но вы не могли ее увидеть, потому что вы читали с неправильного последовательного интерфейса. Попробуйте прочитать этот (сжатый) фрагмент вашего (старого) кода:
switch(resp){
case '1':
...
break;
case '2':
switch(resp){
case 'A':
...
С помощью первого оператора switch вы проверяете значение resp
. Если это "2"
, вы войдете во второй случай. Там вы снова проверяете значение resp
для значений "A"
,.... Но когда вы уже знаете, что значение resp
равно "2"
, как оно может быть равно " A "
или одной из других подкоманд, поскольку вы не меняете соотношение между ними. Таким образом, код внутри второго оператора switch недоступен.
Что теперь делать? Я предполагаю, что вы хотите, чтобы первый оператор switch обрабатывал режимы, а второй-команды перемещения, находясь во втором режиме. Для этого вам нужно перестроить свой код, в лучшем случае на FSM (конечный автомат). Я уже однажды написал хорошее описание того, как работает FSM, в своем ответе на этот вопрос.
Введите переменную состояния, которая используется в первом операторе switch, и переменную команды, которая используется во втором. Я бы предложил такую структуру:
enum State {AUTOMATIC_MODE, MANUAL_MODE};
State state = AUTOMATIC_MODE;
char command = 0;
void loop(){
if(BTSerial.available()){
resp = BTSerial.read();
Serial.println(resp);
switch(resp){
case '1':
state = AUTOMATIC_MODE;
break;
case '2':
state = MANUAL_MODE;
break;
case 'A':
case 'R':
case 'I':
case 'D':
case 'O':
command = resp;
break;
}
}
switch(state){
case AUTOMATIC_MODE:
...
break;
case MANUAL_MODE:
switch(command){
case 'A':
...
}
break;
}
}
Здесь последовательный ввод будет введен в переменную состояния
или команды
, в зависимости от того, что именно было отправлено. После этого следует часть с основным кодом. В зависимости от состояния выполняется соответствующий код. В ручном режиме код будет просматривать переменную команды
, чтобы проверить, какую функцию следует выполнить.
- AT-команда не отвечает на последовательный монитор
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- Ардуино для чтения с преобразователя RS232 в последовательный модуль TTL
- Как связаться с ESP8266 ESP01, отправив данные через программный сериал на Arduino Uno?
- myserial.available() возвращает нулевой байт
- Последовательная связь от Arduino до ESP8266 NodeMCU работает, но от NodeMCU до Arduino не работает
- SoftwareSerial данные недоступны
- последовательная передача данных на GPS-экране duinopeak
Я понимаю, что, возможно, тогда я все неправильно понял, потому что намерение состоит в том, чтобы машина работала без подключения к ПК и, следовательно, не была подключена к последовательному монитору в первую очередь. Итак, должен ли я просто записать полученную информацию в свою переменную resp, не записывая ее на последовательный монитор вообще?, @Genaro Basoria
При последовательном (UART) запись и чтение независимы. Вы можете увидеть данные Bluetooth на последовательном мониторе, если запишете их в "Serial", но это не значит, что вы можете прочитать их оттуда. Вы можете читать только из
Последовательного
, что активно посылается последовательным монитором. Вы читаете важные командные данные изBTSerial
, поэтому вы должны использовать эти данные для назначенияresp
. Вы все еще можете дополнительно отправить данные на последовательный монитор для отладки., @chrisl@GenaroBasoria Я добавил часть к своему ответу о проблеме с ручным режимом, @chrisl