Управление радиомоделью

val674
Offline
Зарегистрирован: 01.02.2015

Здравствуйте уважаемые форумчане ! Сразу хочу предупредить - в программировании я ноль (ну может ноль с плюсом) 

Моя радиоуправляемая модель, управляется через блютуз.

используется Arduino и Adafruit Motor Shield + bluetooth HC-06

Схема модели такая: 

двигатель 1 - (управляет поворотом передних колес - влево/вправо) 

двигатель 2 - (управляет задними колесами - вперед/назад)

Управляется модель с помощью приложения Bluetooth RC Controller (Android).

По сусекам на просторах интернета собрал скетч. Ну вот тут возникла проблема с управлением.

И так: Нажимаем "вперед" - начинает вращение задний двигатель (пока держим кнопку едем вперед, когда отпускаем он останавливается), не отпуская кнопки вперед нажимаем влево - и вот тут проблема - двигатель нажинает движение, а при отпускании кнопки влево моторчик не останавливается, а останавливается только при отпускании кнопки вперед. Картина с точностью до наоборот если сначала поворачиваем, а потом едем вперед.

#include <AFMotor.h>  // Подключаем библиотеку для работы с шилдом 
const int TIMEOUT_TIME_MS = 150;
unsigned long lastPilotSymbolTime;
char symbol;

int val;
// Подключаем моторы к клеммникам M3, M4
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);
int LED = 13; // используем встроенный светодиод для индикации работы

enum States
{
  WAITING,
  READING,
  RUNNING,
  ERROR,
  TIMEOUT
};

States state;
States onWait();
States onRead();
States onRun();
States onError();

States onTimeout();

void setup()
{
  Serial.begin(9600);
  lastPilotSymbolTime = 0;
  // Задаем максимальную скорость вращения моторов (аналог работы PWM) 
  motor3.setSpeed(255);
  motor3.run(RELEASE);
  motor4.setSpeed(255);
  motor4.run(RELEASE);
  //используем 13 пин как индикатор включённой ардуины
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
}

void loop()
{
  switch (state)
  {
  case WAITING:
    state = onWait();
    break;
  case READING:
    state = onRead();
    break;
  case RUNNING:
    state = onRun();
    break;
  case TIMEOUT:
    state = onTimeout();
    break;
  default:
    state = onError();
  }
}

States onWait()
{
  if (Serial.available() > 0)
  {
    return READING;
  }
  if (lastPilotSymbolTime && (millis() - lastPilotSymbolTime > TIMEOUT_TIME_MS))
  {
    return TIMEOUT;
  }
  return WAITING;
}

States onRead()
{
  symbol = Serial.read();
  return RUNNING;
}

States onRun()
{
  switch (symbol)
  {

case 'F':
    //начало действий при полученном символе 'F' (вперед)
    motor4.run(BACKWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break;

case 'G':
    //начало действий при полученном символе 'G' (вперед-влево)
    motor3.run(FORWARD);
    motor3.setSpeed(255);
    motor4.run(BACKWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break;
    
case 'I':
    //начало действий при полученном символе 'F' (вперед-вправо)
    motor3.run(BACKWARD);
    motor3.setSpeed(255); // Задаем скорость движения
    motor4.run(BACKWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break; 
    
case 'B':
    //начало действий при полученном символе 'B' (назад)
    motor4.run(FORWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break;
 
case 'H':
    //начало действий при полученном символе 'B' (назад-влево)
    motor3.run(FORWARD);
    motor3.setSpeed(255); // Задаем скорость движения
    motor4.run(FORWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break;

case 'J':
    //начало действий при полученном символе 'B' (назад-вправо)
    motor3.run(BACKWARD);
    motor3.setSpeed(255); // Задаем скорость движения
    motor4.run(FORWARD);
    motor4.setSpeed(255); // Задаем скорость движения
    break;
    
case 'R':
    //начало действий при полученном символе 'R' (вправо)
    motor3.run(BACKWARD);
    motor3.setSpeed(255); // Задаем скорость движения
    break;

case 'L':
    //начало действий при полученном символе 'L' (влево)
    motor3.run(FORWARD);
    motor3.setSpeed(255); // Задаем скорость движения
    break;
    
case 'S':
    //начало действий при полученном символе 'S' (остановка)
    //[ДОБАВИТЬ СВОЙ КОД НИЖЕ]
    motor3.run(RELEASE);
    motor4.run(RELEASE);
    break;

case 'P':
    //получили контрольный символ, не изменяйте этот код
    lastPilotSymbolTime = millis();
    break;
    default:
  return ERROR;
}
  return WAITING;
}

States onError()
{
  //Получены неоговоренные символы. Очищаем ввод и продолжаем.
   while (Serial.available())
  {
    Serial.read();
  }
  return WAITING;
}

States onTimeout()
{
  //Действия при таймауте.
  //Вероятно, связь утеряна,
  //но при получении контрольного символа она будет восстановлена.
  //Здесь, например, уместно выключить двигатели
  //[ДОБАВИТЬ СВОЙ КОД НИЖЕ]
  motor3.run(RELEASE); // останавливаем двигатели
  motor4.run(RELEASE);
  if (Serial.available())
  {
    return READING;
  }
  return TIMEOUT;
}

Вообще я собирал свою модель на модуле L298N и все работало, Вот хотел попробовать с шилдом собрать, тут возникла проблема.

Помогите пожайлуста решить проблему.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

По коду так и должно работать. Нажимаем F и держим включается и работает ходовой движок. Нажимаем и держим L включается и работает движок поворота. При отпускании L мотор поворота не остановится, т.к. он останавливается в двух случаях, либо S пришло либо 150 мс НИЧЕГО не приходило, а так как F остается зажатая то всё и продолжает работать.

val674
Offline
Зарегистрирован: 01.02.2015

Дело в том, что мне необходимо сделать так, чтобы при движении вперед нажимая например влево - модель поворачивала, при отпускании кнопки влево - модель движется прямо.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Это понятно, но тогда надо не просто читать символы и выполнять условия, а надо еще анализировать что там за символ был и когда он пропал. Т.е. в буфере будет например FFFLFLFLFFFFFF получается что надо поворотный двигатель выключить как тоьлко перестали L идти, например так же через таймаут. Если 150мс не приходит L а до этого была, то гасить поворотный мотор.

Ну это один из возможных вариантов, думаю если подольше подумать то придумается что-то более красивое

val674
Offline
Зарегистрирован: 01.02.2015

Посоветуйте,  может мне добавить условие , которое будет выполнятся при отпускании кнопки? - т.е отпускаем кнопку моторчик останавливается.  

Получается что при нажатии - 'L' , а при отпускании 'l' . Просто думаю, что необходимо будет дорабатывать приложение по управлению, т.к. про 'L' приложение знает , а про 'l' - не знает.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Я не знаю как верхний уровень устроен (само приложение на аедроиде) Если бы оно при нажатии влево слало L а при отпускании слало что-то еще признак какой-то, например Z, по которому можно остановить мотор, тогда бы было совсем хорошо и доработок было бы минимум. I это же у вас вправо-вперед написано. Моторы у вас останавливаются тоьлко если пришло S или вообще ничего не приходит.

Если дорабатывать приложение на андроиде то как вариант при нажатии один раз послать L при отпускании снова послать L, а в скетче ввести флаг состояния мотора. Тогда при получении L если мотор стоит то крутим, если крутится то останавливаем. Так можно одним символом и вклучать и выключать мотор. Ну это как вариант, я думаю таких вариантов море можно придумать.