Arduino: void loop() дает неожиданный результат

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

Робот движется с помощью 4 двигателей постоянного тока, установленных на колесах его основания, а рука управляется отдельным двигателем постоянного тока.

Я хочу, чтобы:

Робот должен двигаться вперед, пока не обнаружит объект.
Когда объект обнаружен, он должен остановить колеса и запустить рычаг, чтобы поднять объект вверх.
Затем он должен двигаться вперед, пока не обнаружит второй объект, то есть контейнер.
При обнаружении второго объекта (контейнера) колеса должны быть остановлены, а рычаг должен быть активирован, чтобы поместить объект в контейнер.

Для этого я написал следующий код

#define mp1 3
#define mp2 4
#define m2p1 5
#define m2p2 6

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED

#define armPin1 9  // Pin 1 of arm
#define armPin2 10  // Pin 2 of arm

int maximumRange = 200; // Maximum range needed
int minimumRange = 18; // Minimum range needed
long duration, distance; // Duration used to calculate distance

int first = 0;

void setup()
{
  Serial.begin(9600);

 //Setting the pins of motors
 pinMode(mp1, OUTPUT);
 pinMode(mp2, OUTPUT);
 pinMode(m2p1, OUTPUT);
 pinMode(m2p2, OUTPUT);

 //Setting the pins of distance sensor
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);

 pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)

 pinMode(armPin1, OUTPUT);
 pinMode(armPin2, OUTPUT);
}// end setup method

long calculateDistance(){
  //Code of distance sensor
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2); 

  digitalWrite(trigPin, HIGH);
  delayMicroseconds(20); 

  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);

 //Calculate the distance (in cm) based on the speed of sound.
 return duration/58.2;
}

void loop()
{
  distance = calculateDistance();

  while(distance > minimumRange) {
    forward();
    distance = calculateDistance();
  }

  while(distance <= minimumRange && first == 0){
    stopMotors();

    pickObject();

    distance = calculateDistance();
  }

  while(distance > minimumRange) {
    forward();
    distance = calculateDistance();
  }

  while(distance <= minimumRange && first == 1){
    stopMotors();

    putObject();

    distance = calculateDistance();
  }// end second while copied 

  first = 1;

}// end loop function

void pickObject(){
  digitalWrite(armPin1, LOW);
  digitalWrite(armPin2, HIGH);
}

void putObject(){
  digitalWrite(armPin1, HIGH);
  digitalWrite(armPin2, LOW);
}

void stopMotors(){
  digitalWrite(mp1, LOW);
  digitalWrite(mp2, LOW);
  digitalWrite(m2p1, LOW);
  digitalWrite(m2p2, LOW);
}

void forward(){
  digitalWrite(mp1, LOW);
  digitalWrite(mp2, HIGH);
  digitalWrite(m2p1, HIGH);
  digitalWrite(m2p2, LOW);
}

Но код не работает так, как я хочу. Это фактически перемещает руку в направлении вниз. Это может быть потому, что я не понял поток функции loop().

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


person swdeveloper    schedule 10.09.2013    source источник
comment
Прошло некоторое время с тех пор, как я написал код Arduino, но я попробую. Вы не указали, что он делает неправильно. Я предполагаю, что он просто движется без остановки? В любом случае, пожалуйста, отредактируйте свой вопрос, чтобы включить эту информацию.   -  person mikołak    schedule 10.09.2013
comment
@TheTerribleSwiftTomato: он останавливается, когда чувствует какой-либо объект, но затем каждый раз перемещает руку вниз.   -  person swdeveloper    schedule 10.09.2013


Ответы (4)


Мой первоначальный ответ совпал с ответом @Bmoore в его диагнозе, но теперь я считаю, что ваш алгоритм в loop() по существу правильный. Вот что происходит:

  1. Мы находимся в первой итерации, first==0. Вы вводите while(distance > minimumRange), в котором остаетесь до тех пор, пока условие не нарушится. distance теперь <= minimumRange и first == 0.
  2. Вы вводите while(distance <= minimumRange && first == 0). Вы остаетесь там, постоянно останавливая приводные двигатели и проводя замеры, пока объект не окажется на расстоянии от ультразвукового датчика. distance теперь > minimumRange и first == 0.
  3. Вы вводите while(distance > minimumRange). Вы остаетесь в нем, пока состояние не сломается. distance теперь <= minimumRange и first == 0.
  4. Вы не вводите while(distance <= minimumRange && first == 1), потому что first == 0.
  5. Вы устанавливаете first = 1 и заканчиваете итерацию.
  6. Теперь вы находитесь во второй итерации. Опять же, distance теперь <= minimumRange и first == 1. Из-за этого вы не вводите первые три while.
  7. Вы вводите while(distance <= minimumRange && first == 1) и остаетесь в этом while до тепловой смерти Вселенной (или пока не закончится мощность вашего Arduino, в зависимости от того, что произойдет раньше).

Итак, алгоритм верный. Следовательно, должно быть что-то не так в другом месте. Вот что я вижу подозрительно:

  • pickObject() и putObject() меняются местами. Вы остаетесь во втором while. Это может сочетаться с недопустимым начальным положением: если ваш робот может двигать рукой вверх и вниз из начального состояния, возможно, что-то не так с вашими предположениями.
  • по какой-то причине distance всегда меньше, чем minimumRange после того, как он встречает первый объект (сбой датчика, слишком короткое время ожидания между триггерным импульсом и эхом и т. д.). Затем вы остаетесь в первой итерации, во второй while. Обратите внимание, что для этого требуется, чтобы предыдущее условие ошибки соответствовало наблюдению.

Есть также несколько вещей, которые не совсем корректны в вашем коде:

  • digitalWrite() фиксируется, т. е. если вы установите LOW или HIGH на штифте, значение останется установленным, пока вы его не измените. Вы продолжаете записывать эти значения без необходимости.
  • как указывают другие ответы, loop() - это... цикл. Это повторяется. Вы должны переписать свои whiles в ifs (конечно, обновив условия).
  • вы также ставите свой алгоритм в зависимость от подхода ожидание занятости, постоянно измеряя расстояние до тех пор, пока не рука движется, посылая импульсы снова и снова. Электроэнергия не бесплатна, особенно на встроенной платформе. В таких случаях следует добавить delay().

Могут быть и другие неисправности (я, конечно, надеюсь, что вы не глушите свой ручной двигатель, так как вы никогда его не останавливаете!).

Поэтому в целом такие задачи следует решать так:

  1. Добавьте в свой код операторы Serial.Write(), сделайте их информативными, опишите, какие шаги были выполнены и с какими значениями решающие параметры.
  2. Подключите Arduino к IDE через USB или используйте экран регистрации, который, например, работает с SD-картой.
  3. Основываясь на этих журналах, определите, где ошибка в алгоритме.

Использование ведения журнала таким образом избавит вас от многих головных болей.

person mikołak    schedule 10.09.2013
comment
Не приведет ли задержка () к остановке всех других процессов (например, движения колес, рычага и т. д.)? - person swdeveloper; 11.09.2013
comment
@swdeveloper: Нет, как я уже сказал, контакты остаются на значении, которое вы установили ранее, на самом деле вы можете проверить это с помощью эскиза Blink. Прочтите второй абзац раздела Предостережение (а также остальные ;)). - person mikołak; 11.09.2013

Вот ваша проблема:

Функция цикла работает постоянно, каждый раз, когда она заканчивается, она снова запускается. Сначала вы устанавливаете значение 1, но никогда не сбрасываете его на 0, поэтому каждый цикл, который он проходит первым, равен 1.

while(distance <= minimumRange && first == 1){
    stopMotors();

    putObject();

    distance = calculateDistance();
  }// end second while copied 

  first = 1;
person Bmoore    schedule 10.09.2013

Метод loop повторяется снова и снова, пока у вас не разрядится батарея или вы не выключите робота.

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

Для моих роботов я иду behavior-based. Каждый цикл (сотни раз в секунду) робот задает вопросы об окружающей среде и о своем внутреннем состоянии. Используя ответы, он выбирает правильное поведение.

Методы, которые вы используете, являются хорошим началом робототехники, основанной на поведении. Вот несколько слайдов, объясняющих все это: роботы, основанные на поведении.

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

person ladislas    schedule 10.09.2013

Функция цикла работает постоянно, каждый раз, когда она заканчивается, она снова запускается. Сначала вы устанавливаете значение 1, но никогда не сбрасываете его на 0, поэтому каждый цикл, который он проходит первым, равен 1.

while(distance <= minimumRange && first == 1){
    stopMotors();

    putObject();

    distance = calculateDistance();
}// end second while copied 

first = 1;
person Faisal Fana    schedule 17.09.2013