2017-01-31 9 views
1

Я пытаюсь сделать роботизированное «водосточное устройство» для школьного проекта. Я решил использовать Arduino Uno для управления двигателями. Это только двигатель с прямым/обратным движением и, следовательно, имеет только один двигатель, управляющий движением робота. Есть еще один мотор, управляющий «лезвиями» (из-за отсутствия лучшего слова), выходящими спереди, чтобы вырвать грязь из желоба.Arduino Uno Timing Issues

Я использую модуль Bluetooth HC-05 для приема ввода с смартфона и H-моста L9110 для управления двигателями отдельно. Есть пять функций: движение вперед, обратное движение, лезвия, остановка и «автономность». Автономный включает в себя лезвия, которые идут с роботом, двигающимся вперед в течение 20 секунд, назад в течение 10 секунд, повторяя, пока не будет вызвана функция остановки.

Проблема заключается в том, что, когда я вызываю функцию для автономной системы, HC-06, похоже, прекращает прием данных, а отладка println("auto fwd") спамает серийный монитор. Код отладки кода «auto rev» даже не достигнут. Функция остановки не может работать, поскольку, как представляется, данные не принимаются, поэтому создается бесконечный цикл.

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

#include <SoftwareSerial.h> //Include the "SoftwareSerial" software in the program 

#define M1A 5 //tells the software compiler to assign these varibales to these outputs on the Arduino board 
#define M1B 9 //M1 motors are controlling the motion 
#define M2A 4 //M2 motors control the blades 
#define M2B 10 

SoftwareSerial BT(3, 2); //Tells the program to assign pins 2 and 3 on the Arduino to send and receive data 

void fw(); //Denoting Functions to be used 
void bw(); 
void Stop(); 
void autonomous(); 
void bladesOn(); 

boolean autonom = false; //Variables 
boolean blades = false; 
unsigned long currentMillis = millis(); 
unsigned long previousMillis = 0; 
const long fwdTime = 20000; 
const long revTime = fwdTime/2; 

void setup() { 
    // put your setup code here, to run once: 
    TCCR1B = (TCCR1B & 0b11111000) | 0x04; 
    BT.begin(9600); 
    Serial.begin(9600); 
    pinMode(M1A, OUTPUT); 
    pinMode(M1B, OUTPUT); 
    pinMode(M2A, OUTPUT); 
    pinMode(M2B, OUTPUT); 
} 

void loop() { 
    if (BT.available()) { 
    char input = BT.read(); //Read the incoming BlueTooth signal 
    Serial.println(input); //Print the BT signal to the memory 
    switch (input) { //IF input is 1, do this, IF input is 2, do that 
     case '1': 
     fw(); 
     break; 
     case '2': 
     bw(); 
     break; 
     case '3': 
     autonomous(); 
     blades = 1; 
     autonom = true; 
     break; 
     case '4': 
     bladesOn(); 
     blades = true; 
     break; 
     case '0': 
     Stop(); 
     autonom = false; 
     blades = false; 
     break; 
    } 
    } 
} 

void bw() { 
    digitalWrite(M1A, 0); //Give an output to the M1A pin 
    analogWrite(M1B, 255); //Give an output to the M1B pin 
    digitalWrite(M2A, 0); 
    analogWrite(M2B, 255); 
    Serial.println("Backwards"); 
} 

void fw() { 
    digitalWrite(M1A, 1); 
    analogWrite(M1B, (255 - 255)); 
    digitalWrite(M2A, 1); 
    analogWrite(M2B, (255 - 255)); 
    Serial.println("Forwards"); 
} 

void Stop() { 
    digitalWrite(M1A, 0); 
    analogWrite(M1B, 0); 
    digitalWrite(M2A, 0); 
    analogWrite(M2B, 0); 
    Serial.println("Stop"); 
} 

void autonomous() { 
    while (autonom == true) { 
    if (currentMillis - previousMillis <= fwdTime) { 
     //When time between last repeat of forwards/reverse and now is less than Time1, go forward 
     digitalWrite(M1A, 1); 
     analogWrite(M1B, (255 - 255)); 
     digitalWrite(M2A, 1); 
     analogWrite(M2B, (255 - 255)); 
     Serial.println("auto fwd"); 
    } 
    if (currentMillis - previousMillis <= revTime) { 
     //When time between last repeat of forwards/reverse and now is less than Time2, go reverse 
     digitalWrite(M1A, 0); 
     analogWrite(M1B, 255); 
     digitalWrite(M2A, 0); 
     analogWrite(M2B, 255); 
     Serial.println("auto rev"); 
    } 
    if (currentMillis - previousMillis == revTime) { //Set previoustime to currenttime 
     previousMillis = currentMillis; 
    Serial.println("Autonom"); 
    } 
    } 
} 

void bladesOn() { 
    blades = true; 
    digitalWrite(M2A, 1); 
    analogWrite(M2B, 0); 
    Serial.println("Blades"); 
} 

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

PS. Я использую «Arduino BT Joystick» в качестве приложения Android для управления роботом, если это помогает.

Спасибо,

Крейг.

+0

Возможно, это не все ваши проблемы, но я думаю, что вы имели в виду и должны иметь строки 'autonom = true;' и 'blades = 1;' перед вызовом 'автономный();'. В первый раз, когда 'автономный()' называется, он не будет выполнять автономию, потому что 'autonom' будет false. – DigitalNinja

+0

Как именно вы ожидаете, что ваш робот не застрянет ** в ** бесконечном цикле ** внутри 'autonomous()', так как есть ** никакой шанс выхода ** из 'while (autonom == true) {...} 'цикл содержит? Вы должны установить 'autonom' в' false' в этом цикле в какой-то момент или, что еще лучше, полностью избавиться от цикла и отрегулировать остальную часть вашего кода соответственно. –

+0

Кроме того, вы забыли обновить значение 'currentMillis'. Что еще более важно, условие 'currentMillis - previousMillis == revTime' является ** опасностью **: никогда не используйте' == 'для переменных времени, так как это очень маловероятно, что такое условие будет когда-либо сохранено. Вместо этого используйте '<=' and '> =' соответственно. Вы также должны попытаться отделить понятие * направления движения * от движения * длины движения *, имея две переменные 'revTime' и' fwdTime' - ненужное усложнение. –

ответ

1

Ваша логика для функции autonomous() неправильная. Ардуино застрянет в цикле while во втором вызове функции, как отмечает DigitalNinja, поскольку переменная autonom обновляется только за пределами этого цикла.

Даже если бы это было не так, переменная currentMillis не обновляется нигде в коде, поэтому тест currentMillis - previousMillis <= fwdTime всегда будет правдой.

(Ps: жаль, чтобы ответить, как это, у меня нет достаточной репутации прокомментировать.)

0

Проблемы:

  1. autonom() содержит цикл while(autonom == true) { ... }, который не делает никогда не прекратить, потому что autonom никогда не устанавливается в false внутри цикла, поэтому управление никогда не возвращается к вызывающему абоненту void loop() { ... }, и вы никогда не слушаете bluetooth команд снова.

  2. Вы не обновляют currentMillis в любом месте, при этом ваш робот закончится застрял, пытаясь идти вперед /назад навсегда.

  3. Нецелесообразно писать currentMillis - previousMillis == revTime, потому что, вообще говоря, currentMillis может стать большеpreviousMillis + revTime никогда не будучи равной. Вместо этого вы должны написать currentMillis - previousMillis >= revTime.


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

Обратите внимание, что в этом примере '1' устанавливает автономное движение вперед и '2' устанавливает автономное движение назад, а '3' больше не используется. Это связано с тем, что я считаю, что ваш коммуникационный протокол должен быть обогащен, чтобы дать возможность параметры команды, например: продолжительность движения. Обратите внимание, что вы можете легко воспроизвести предыдущее поведение для '1' и '2', установив time = 0.

enum { 
    STAY_STILL, 
    MOVE_FORWARD, 
    MOVE_BACKWARD, 
} 

#define FORWARD_TIME 20000 
#define BACKWARD_TIME (FORWARD_TIME/2) 

byte state = STAY_STILL; 
unsigned long startMillis; 

void loop() { 

    currentMillis = millis(); 

    if (BT.available()) { 

     char input = BT.read(); 

     switch (input) { 
     case '1': 
      state = MOVE_FORWARD; 
      time = FORWARD_TIME; 
      startMillis = currentMillis; 
      break; 
     case '2': 
      state = MOVE_BACKWARD; 
      time = BACKWARD_TIME; 
      startMillis = currentMillis; 
      break; 
     // case '3' is pointless: instead of duplicating functionality 
     // you should modify your communication protocol so to allow 
     // setting both a direction and the amount of time you want 
     // the robot to move in such direction. A value of 0 could 
     // stand for 'forever', all other values could be interpreted 
     // as seconds. 
     case '4': 
      start_blades(); 
      break; 
     case '5': 
      stop_blades(); 
      break; 
     case '0': 
      state = STAY_STILL; 
      break; 
     } 
    } 

    if (state == MOVE_FORWARD || state == MOVE_BACKWARD) { 
     move_robot(); 
    } else if (state == STAY_STILL) { 
     stop_blades(); 
     stop_robot(); 
    } 

    delay(10); 
} 

void start_blades() { 
    digitalWrite(M2A, 1); 
    analogWrite(M2B, 0); 
    Serial.println("start blades"); 
} 

void stop_blades() { 
    digitalWrite(M2A, 0); 
    analogWrite(M2B, 0); 
    Serial.println("stop blades"); 
} 

void stop_robot() { 
    digitalWrite(M1A, 0); 
    analogWrite(M1B, 0); 
    Serial.println("stop wheels"); 
} 

void move_robot() { 
    // time == 0 : move forever in one direction 
    // else  : move up until deadline 
    if (time == 0 || currentMillis - startMillis <= time) { 
     if (state == MOVE_FORWARD) { 
      fw(); 
     } else if (state == MOVE_BACKWARD) { 
      bw(); 
     } 
    } else { 
     // this will turn off both blades and 
     // wheels at the next iteration of the loop() 
     state = STAY_STILL; 
    } 
} 

... 
// your fw() and bw() functions 
... 

В заключение, незначительное предложение. На вашем месте я бы сменил функции, такие как fw(), bw(), start_blades(), stop_blades(), stop_robot(), чтобы выполнить действие только тогда, когда это необходимо, вместо того, чтобы без особых усилий устанавливать значения и печатать. В дополнение к сокращению накладных расходов при длинных функциях он также избегает печати тонны сообщений через серийный, что делает отладкой проще. Это может быть достигнуто за счет обогащения состояния робота с дополнительной информацией, но оно выходит за рамки вопроса и этого ответа.

0

Ну, в конце концов, у меня была переменная, которая сама включалась и выключалась, по-видимому, сама по себе. Поэтому, когда наступил проект, я полностью выполнил функцию Auto. Спасибо всем за помощь, я, возможно, не получил этого, но я узнал немного.

+0

Не могли бы вы указать, какая именно часть кода не работала? Как в, какая это была переменная? – JustCarty

+0

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