Программа робота для поворота при обнаружении припятствия
- Войдите на сайт для отправки комментариев
Здравствуйте, подскажите пожалуйста как реализовать программу, при который робот при обнаружении препятствия изменял курс движения.
При моей программе он почему-то долго соображает что перед ним что-то есть (оклоло 2-3 секунд) хотя датчик обновляется раз 5 в секунду.
И как сделать, чтобы при обнаружании препятствия двигатели вращались в разные стороны определенное время, т.е. delay это не то как я понял. Просто робот провернувшись немного расстояние тут же может измениться и датчик отошлет сигнал и он снова прямо поедет, а мне не надо это, т.к. он всеравно врежется потому что не довернул.
Датчик у меня ультразвуковой HC-RS04, который вращается на серве. И можно ли сделать так, что бы робот объезжал предмет. Т.е. в зависимости от того на какой угол повернута серва и при значении, что показание с датчика будет меньше 20 он уже будет поварачивать соответственно. Например в момент поворота сервы на угол при котором серва смотрит влево и показании датчика меньше 20 робот проедет немного вправо, и наоборот. И вообще серва наверно не сможет отослать сигнал в каком она положении, т.е. нужен шаговик?
Есть вот такой шаговик ST28
Как вот по этой ссылке в самом низу, он сможет отослать сигнал о своем положении, или он только тоже поворачивает на заданный угол?
http://freeduino.ru/arduino/mshield.html
#include <Servo.h> #include <AFMotor.h> Servo LexaServo; int servoPin = 9; AF_DCMotor motor1(1); //правый AF_DCMotor motor2(2); //Левый const int Trig = 2; const int Echo = 12; void setup() { pinMode(Trig, OUTPUT); pinMode(Echo, INPUT); LexaServo.attach(servoPin); Serial.begin(9600); } unsigned int time_us=0; unsigned int distance_sm=0; void loop() { { for (int i=40; i<=120; i=i+10) // от 40 до 120 градусов { LexaServo.write(i); // говорим серве куда идти delay(200); digitalWrite(Trig, HIGH); // Подаем сигнал на выход микроконтроллера // delayMicroseconds(10); // Удерживаем 10 микросекунд digitalWrite(Trig, LOW); // Затем убираем time_us=pulseIn(Echo, HIGH); // Замеряем длину импульса distance_sm=time_us/58; // Пересчитываем в сантиметры Serial.println(distance_sm); // Выводим на порт } } if (distance_sm<20) // Если расстояние менее 20 сантиметром { motor1.run(FORWARD); motor2.run(BACKWARD); motor1.setSpeed(254); motor2.setSpeed(254); } else { motor1.run(FORWARD); motor2.run(FORWARD); motor1.setSpeed(254); motor2.setSpeed(254); } }
Это потому что у вас 120 циклов с задержкой по 200 миллисекунд.
Вот может, что-то полезное там найдете Робот "Объезжайка-1"
Спасибо, посмотрю.
А как тогда отделить цикл сервы, там в любом случае мне задержка нужна?
И как сделать чтоб движки вращались определенное время? Какая функция нужна?
PS классный робот), а у меня только УЗ дальнометр
>>> А как тогда отделить цикл сервы, там в любом случае мне задержка нужна?
Задержка нужна, решается это так Мигаем светодиодом.
>>> И как сделать чтоб движки вращались определенное время?
Значением ШИМа подаваемым на двигатель я регулировал усилие/обороты двигателей, тем самым менял траэкторию движения. Но можно и временем работы двигатей изменять траэкторию, это уже как вам больше нравится.
>>> а у меня только УЗ дальнометр
Без разницы чем сканировать пространство.
Спасибо, посмотрю.
А как тогда отделить цикл сервы, там в любом случае мне задержка нужна?
Самой серве - задержка не нужна. Вы дале ей команду "занять положение" и дальше можете заниматся своими делами. Крутится она будет сама. Сама и остановится, когда займет "скомандованное" положение.
Задеркжа становится нужна, когда дальнейшая логика подразумевает что серва "уже стоит в новом положении".
Но опять-таки использовать задержку для этого - лобовой и не самый лучший путь (она останавлиавет скетч и сбивает все "паралельные" процессы).
Гораздо лучше "влючили серву", "запомнили время когда мы это сделали", а потом, регулярно смотрим на часы "прошло ли достаточно времени" с момента включения сервы.
Примерно так:
И как сделать чтоб движки вращались определенное время? Какая функция нужна?
Зайдите в раздел "Программирование" и посмотрите примиер "Мигаем диодом без delay()"
Спасибо, буду разбираться.
А как можно посмотреть через сам процессинг диаграмму при сканировании пространства, т.е. как тут
http://we.easyelectronics.ru/part/eksperimenty-s-uz-dalnomerom-proekt-vy...
У меня просто была такая задумка:
Робот едет, датчик снимает показания расстояния, серва вращает датчик на угол градусов 60 туда/обратно, не много, чтобы только видеть перед собой что находится. Все нормально препятствия нет.
Как только что-то появляется, т.е. в какой-то момент времени серва находится например в левом положении при каком-то угле и значение датчика показывает меньше 20, т.е. нужно поворачивать, и тут как раз в зависимости куда смотрит серва, в противоположную сторону подвернуть роботу чтобы не врезаться. Как то так
Спасибо, буду разбираться.
А как можно посмотреть через сам процессинг диаграмму при сканировании пространства, т.е. как тут
http://we.easyelectronics.ru/part/eksperimenty-s-uz-dalnomerom-proekt-vy...
Открывать туториалы по процессингу. Научится на нем что-нибудь присовть програмно. Научится в нем общатся с радуиной через Serial. Ну а дальше "все просто". Ардуиной отсылаем в Serial положение сервы и показания сонара, в процессинге читаем и в соотвествии с полученынми данными, с помощью drawLine, drawBox и т.п. рисуем диаграмму.
Возможно, для этого, прийдется еще и школьную немного геометрию повсмоинать. ЧТо такое синус и косинус :) Как найти координаты отрезка, если известны координаты одного конца (центр экрана), его длина (показания сонара), и угол поворота относительно оси координат (положение сервы). дальше drawLine с высчитаными координатами и дело в шляпе :)
У меня просто была такая задумка:
Попробуйте поискать на форуме. Месяц-два назад. Ну просто "один в один" задачу решали (не помню чем закончилось).
Спасибо, посмотрю.
А как тогда отделить цикл сервы, там в любом случае мне задержка нужна?
Самой серве - задержка не нужна. Вы дале ей команду "занять положение" и дальше можете заниматся своими делами. Крутится она будет сама. Сама и остановится, когда займет "скомандованное" положение.
Задеркжа становится нужна, когда дальнейшая логика подразумевает что серва "уже стоит в новом положении".
Но опять-таки использовать задержку для этого - лобовой и не самый лучший путь (она останавлиавет скетч и сбивает все "паралельные" процессы).
Гораздо лучше "влючили серву", "запомнили время когда мы это сделали", а потом, регулярно смотрим на часы "прошло ли достаточно времени" с момента включения сервы.
Примерно так:
Если я правильно понял, то код должен выглядить следующим образом, еслия только сервой управляю и все:
Только не компилируется, поправьте пожалуйста. Еще плохо разбираюсь.
Где в коментарии вы писали время, достаточное для поворота "ВРЕМЯ_ДОСТАТОЧНОЕ_ДЛЯ ПОВОРОТА"
это время промежутков между поворотом в 10 градусов, или это полный цикл сервы?
Только не компилируется, поправьте пожалуйста. Еще плохо разбираюсь.
Не обижайтесь, но принципиально даже смотреть код не буду. Раз "не компилируется", значит выдает какую-то ошибку. Почему ее не сообщить тут, что-бы гадать не приходилось? К тому же прочитав эту ошибку очень не нулевая вероятсно что и сами поймете в чем проблема. Написание кода на 80% и состоит в попытках объяснить "че ты хочешь" компилятору, а он пытается сказать "что ему не нравится".
Вообщем как максимум - попытайтесь сами понять что оно хочет (можно со словариком), как минимум - копипастайте сюда ошибку. Тогда будем смотреть.
Где в коментарии вы писали время, достаточное для поворота "ВРЕМЯ_ДОСТАТОЧНОЕ_ДЛЯ ПОВОРОТА"
Это тоже самое время которое вы использовали в delay().
Откуда вы эту цифру брали? И главное "зачем"?
А затем что серва не умеет "поворачиватся моментально". У нее есть какая-то конечная скорость поворота. Чем на больше угол поворачиваем - тем дольше это займет.
Если нам достаточно того что "повернулось", то собственно кроме myServ.write ничего и не нужно вообще.
Если же мы хотим что-то сделать когда серва стала в новую позицию - либо delay() либо вот тот подход что я дал выше.
К сожалению докладывать "я вышла на позицию" - серва не умеет. Поэтому приходится давать ей время на исполнение команды. Тупо скомандовали "крутись", подождали какое-то время и надеемся что она уже заняла нужную позицию.
Какое время? Ну можно час подождать. За час - точно докрутится :) Если не хочется за час - можем посмотреть в спецификацию сервы, там обычно пишут какая у нее скорость в "градусы в минуту".
Если "серва кровей неизвестных". Ну тупо говорим ей "повернись от 0 до 180" и с помощью секундомера замеряем сколько это заняло :)
Если нам "торопится некуда". То можно после любой команды ждать вот это замерянное время. Если она предположим 0 до 180 крутится 2 сек., то если мы скомандуем поворот "от 40 до 45 градусов" и подождем 2 секунды, она, к этому времени уже точно будет стоять на 45-градусах.
Если мы "торопимся" и не хотим ждать "впустую". Ну значит вычисляем сколько занимает поворот на один градус (время_полного_поворота/180). Вычисляем на сколько нам нужно повернуть серву (старая_позиция - новая_позиция).
Ну а зная "время поворота на 1 градус" и "на сколько грудусов поворачиваем" - не трудно вычислить и "сколько времени нужно ждать" (только не забываем взять модуль от вычесленного. Отрицательного времени не бывает).
Ну и можно добавить к "вычесленному" еще некоторое время "про запас". На всяк случай (ну питание там подсело и серва стала медленей крутится и т.п.)
И почитайте
http://arduino.ru/Reference/If
http://arduino.ru/Reference/For
Эта строчка millis()=servoOnTime; вряд-ли скомпилируется. millis()
Эта строчка millis()=servoOnTime; вряд-ли скомпилируется. millis()
Не угадали :) Все навернется раньше. Причем не один раз :( До этой строчки еще добраться нужно.
Так я не гадал, это еще одна ошибка, на которую стоит обратить внимание. Ну а что раньше или позже это не важно, результат один - если не исправить в том числе эту строку компиляции не будет.
Спасибо за развернутые ответы), буду искать
Спасибо за развернутые ответы), буду искать
Что вы искать собрались-то? Нуежели я всех так запугал посылками в гугл ? :)
Искать ничег не нужно. Компилятор же вам сам говорит
И что ему не нравится (в оранжевой строке) и где (подсвечивает строку). Осталось только взять словарик и перевести. Попытатся понять и исправить. Компилируем. Если угадали "что оно хотело" - "споткнется" на следующей ошибке. С ней - опять тоже самое. Если не выходит - сообщить тут. "Вот оно мне выдает такую ошибку", а не абстрактное "ой, не работает".
В разделе "дополнительная инфа" - самая важная - первая ошибка. На остальные часто можно не обращать внимания, так как они часто является "эхом" первой ошибки.
ну да, глупая ошибка)
А еще не поскажете,возможно ли реализовать с помощью одного УЗ датчика объезд предмета, и чтоб он восстановил свою траекторию движения. Вот он ехал прямо, встретил препятствие, обвернул его и дальше прямо поехал? Можно конечно просто задать так чтобы он при появлении значения с датчика меньше 20 делал полуокружность там с каким-нибудь радиусом, но а если стена будет, то уже не очень хорошее решение. Я как раз для этого и спрашивал можно ли так :
"Робот едет, датчик снимает показания расстояния, серва вращает датчик на угол градусов 60 туда/обратно, не много, чтобы только видеть перед собой что находится. Все нормально препятствия нет.
Как только что-то появляется, т.е. в какой-то момент времени серва находится например в левом положении при каком-то угле и значение датчика показывает меньше 20, т.е. нужно поворачивать, и тут как раз в зависимости куда смотрит серва, в противоположную сторону подвернуть роботу чтобы не врезаться. Как то так"
ну да, глупая ошибка)
Почему глупая? Обычная. Такую ошибку любой программист 5-ть раз в час делает. Просто "правит" ее, благодаря опыту, за 2 сек.
А еще не поскажете,возможно ли реализовать с помощью одного УЗ датчика объезд предмета, и чтоб он восстановил свою траекторию движения.
Теретически - можно. Практически - очень сложно. Банально потому что трудно повернуть, к примеру "ровно на 90%", трудно проехать скажем "ровно 20 см" (или узнать сколько мы проехали). На "идеальной подвеске", идеально ровном полу, с идеальными моторами - без проблем. С реальными - не реально :)
Но, прежде чем дальше ехать/менять тему. Вы со следующими ошибками разберитесь. Это же была только "первая в ряду". И синтаксических там еще пара, и логические есть. Или уже "все поправили, все заработало, переходим к следующей задаче"?
вот код, компилируется, но серва очень быстро без всяких задержек поворачивает туда сюда, непойму что не так
наверно все-таки не нужно было цикл for ставить, вы писали там if
>наверно все-таки не нужно было цикл for ставить, вы писали там if
Верно. Что у вас вышло? Попробуйте в голове выполнить все что вы скомандовли ардуине.
Вначали вы ее сказали стань в 40 (запомнили время), потом, сразу, сказали стань в 50 (запомнили время), потом в 60ть....
вообщем "пробежались по всему ряду" без каких либо пауз.
И только ПОСЛЕ ВСЕГО этого решили подождать две секунды и сделали "непонятно что" хоть и синтаксически верно.
В чем смысл строки 22 если в 23 вы обнуляете переменную? Вообщем "плохо от этого не будет", но и пользы - никакой.
В 22 два вы должны делать полезное. То что нужно было сделать через две секунды после начала выполненения сервой команды.
Например сделать замер замер своего сенсора или выдать на серву новую команду-угол (намек!).
Вместо замера сенсора, пока, можно "мигнул диодом" ("условно измерил").
Вообщем попробуйте пройти по каждой строчке и понято "что она делает". Ответить на вопрос "зачем она". Не нужно брать мой код как "магию которая работает" (или нет :)
Нужно "понять идею" и уж "подгонять к своей задаче".
Вот смотрите. Раз вы решили стартовать серву сразу от включения микроконтроллера, а не по какому-то условию (нажатие кнопки или еще что).
То... может первую(!) команду на поворот сервы (и запоминание когда) стоит выдавать в setup а не loop()?
Да и раз раз вы хотите "начинать крутить как только так сразу", то ведь и условие не нужно? Логично?
Напомню, на всяк случай, что setup() - эта функция которая вызывается один раз при запуске. А loop() - "крутится бесконечно"
То есть как только функция loop() доходит до конца - опять начинается ее выполнение с начала.
Вот при такоом решении движки дергаются, не могу понять почему, серва крутится как надо.
Может и правда в setup() сделать, но как, тем более вы сами сказали что она выполнится только один раз.
Очень похоже на правду.
Но смотрите.
Строка 31.
Вы дали команду серве "крутись".
И сразу, без паузы, в строке 32 начали работать с датчиком растояния.
Но ведь серва в этот моменту крутится. Мы же не выждали время.
Вы померяли растояние, а потом "ждете".
Мне кажется логичней было-бы, внутри этого
if ((millis()-prevServoTime)>200)
Вначале провести замеры (этот if нам говорит о том, что с последнего поворота сервы прошло достаточно времени и она уже стоит в нужном положении), а уж потом "крутить серву".
Далее, 200 - не маловато? Попрбуйте, для тестовых целей сделать там что-то "явно большое". Что-бы эти остановки сервы вы видили прямо на глаз.
Когда отладите - потом уменьшите. Что-бы "не дуплил"
Next:
Вы вначале даете моторам команду на включение, а потом говорите "с какой скоростью".
Вы пробовали "сами в голове" попытатся выполнить эти команды?
Да и вообще непонятно, раз эти скорости всегда одинаковы, зачем они попали внутрь обоих вариантов if-а из строки 39?
Зачем это дублирование? Раз скорость моторов не зависит от дистанции, то может стоить вынести их за пределы if?
А если еще глубже глянуть и увидить что мы никогда не меняем эту скорость, то может ее вообще в setup() один раз установить и все?
Next. Оформление кода. Для читабильность, обычно "то что внутри фигурных скобок", пробелами или табами чуть-чуть смещают вправо. Делают отступы. Так четче видно "кто в кого вложен", где if начался, а где закончился.
Можете, в ArduinoIDE нажать Ctrl-T и она сама попытается "красиво отформатировать".
Примерно так:
Ведь легче же понять логику, правда?
Но лично я, предпочитаю "сам руками". Еще при написании. Tab-ами отодвигать.
А если нужно "поправить", то выделяем несколько строк. И нажимаем Tab, что бы их все сразу сместить вправо
и Shift-Tab - влево.
И еще. Вы начали хорошие начинание по поводу выводя дистанции в Serial. Для отладки.
Я бы добавил, перед строчкой 36.
Serial.print(millis(),DEC);Serial.print(" dist: ");
Тогда вы будете видить еще и время "когда сделали замер".
И при включении моторов, тоже сделал
Serial.print(millis(),DEC);Serial.print(" motors: ");
Serial.println(" F B") // и " F F" для второго случая
Тогда вы в логе будуте видиеть все что и когда происходит у вас внутри скетча.
и самому понимать/искать логические ошибки легче. И на форуме можно не словами рассказыать-описывать, а просто дать лог. По коротому видно как оно у вас работает.
P.S. А вообще прогресс у вас - просто замечательный. Такими темпами, через пару недель, вы уже сами сможете новичков консультировать :)
Конечно понятнее если отступы делать) пропустил я этот момент. А код тоже помогли), сам я что-то тупил.
Осмыслил, вроде все ясно, только вод дигатели дергаются( Может токи скачут, незнаю. Наверно шаговый двигатель задействую вместо сервы, там и задержек нету.
На счет повторов скорости да, вообще планировал движение вперед на 200, а разворот уже 254, где условие, один движок вперед, а другой назад.
Спасибо еще раз за ценные пояснения и советы), так проще разбираться
Конечно понятнее если отступы делать) пропустил я этот момент. А код тоже помогли), сам я что-то тупил.
Осмыслил, вроде все ясно, только вод дигатели дергаются( Может токи скачут, незнаю. Наверно шаговый двигатель
Попробуйте выяснить в чем именно у вас проблема. "В логике" или "в железе". Напишите отдельный скетч. Без серв, без сонаров и проч. Который только "крутит движки" и больше ничего. Разделяй и властвуй :)
И, как правильно заметил Максим, с шаговиками вы, наоборот, еще больше проблем огребете. И мощности у них меньше, иногда "плавно разгонять нужно" да и стандартная библа "блокирует скетч". Есть, альтернативные библиотеки, но не видно смысла в этих гиморах.
Вообщем выясните для начала "в какой области проблема" (железо или логика), а уж потом можно будет думать как ее устранить.
Ок, буду эксперементировать
Здравствуйте, вот вобщем я решил под себя доработать программу с этой темы:
http://arduino.ru/forum/proekty/arduino-robot-dlya-nachinayushchikh
Решил использовать еще одну библиотеку по причине того что я не знаю какие пины задействованы для работы через мотор шилд.
В общем двигатели рывками синхронно с сервой делают примерно четверть оборота колесами и поворачивают серву на 10 градусов. Дальнометр выдает нули.
Что не так подскажите пожалуйста