Управление мотором, RC-Switch
- Войдите на сайт для отправки комментариев
Собираю робота на гусеницах. Основа - Arduino Uno. Предполагается управление моторами с 4-хкнопочного пульта, работающего на частоте 433 МГц. Приемник - MX-RM-5V. Для приема сигналов используется библиотека rc-switch. Для управления моторами используется Adafruit Motor Shield и библиотека AFMotor.
Стоит задача - крутить моторы, пока нажата кнопка (в зависимости от конкретной кнопки - конкретное кручение). При отпускании кнопки моторы должны остановиться.
Написал вот такой скетч (чтобы сократить текст, урезал его здесь до одного мотора и одной кнопки):
#include <AFMotor.h> #include <RCSwitch.h> RCSwitch mySwitch = RCSwitch(); unsigned long oldTime; unsigned long newTime; unsigned long oldValue; unsigned long newValue; const unsigned long btnA = 5592332; AF_DCMotor motor(4); //*********************** void setup() { Serial.begin(9600); motor.setSpeed(255); motor.run(RELEASE); mySwitch.enableReceive(0); //приемник на пине 2 (прерывание 0) } //*********************** void loop(){ newTime = millis(); if ((newTime - oldTime) >= 100) { if (mySwitch.available()){ newValue = mySwitch.getReceivedValue(); mySwitch.resetAvailable(); }else{ newValue = 0; } if (newValue == btnA) { Serial.print("Forward"); motor.run(FORWARD); }else if (newValue == 0) { Serial.print("Stop"); motor.run(RELEASE); } Serial.println(); oldTime = millis(); oldValue = newValue; } }
То есть, мысль была такая - раз в 100 миллисекунд (я экспериментировал со значениями от 10 мс до 10 с, но разницы нет, см.ниже) проверяется наличие посылки кода с пульта-передатчика. И если кнопка продолжает быть нажатой (код есть, и он нужный), то мотор крутится, либо продолжает крутиться. Если же кнопка отпущена, то кода нет (пришел 0), и мотор останавливается. Ну, и для контроля шлем в последовательный порт текст-описание команды ("Forward" или "Stop").
Ну так вот - вся эта конструкция прекрасно работает до того момента, пока к контактам мотор-шилда не подключен реальный двигатель и на шилд не подано напряжение - то есть, пока кнопка нажата, порт выдает строчки "Forward" с периодичностью 100 мс, а после отпускания кнопки - строчки "Stop" с той же периодичностью.
Но как только мы включили в работу реальный двигатель, то начинается полный бардак, а именно - несмотря на постоянно нажатую кнопку, двигатель работает рывками, а в выводе в порт между строчками "Forward" регулярно попадаются строчки "Stop". То есть, хоть кнопка и постоянно нажата, все равно эпизодически проскакивают "нулевые" сигналы.
Что можно сделать в такой ситуации? Как избавиться от паразитных нулевых сигналов?
схему выкладывайте.
От чего питатается ардуино (напряжение Бп и ток) и от чего питается мотор. Как они соединены
От чего питатается ардуино (напряжение Бп и ток) и от чего питается мотор. Как они соединены
Мотор-шилд в зависимости от ситуации питается либо от лабораторного БП (6-7 вольт подаю), либо от пары аккумуляторов 18650, соединенных последовательно.
Arduino так же в зависимости от ситуации питается либо от USB-порта ПК (джампер питания на мотор-шилде разомкнут), либо от упомянутых аккумуляторов (джампер замкнут).
Вариант питания на проявление проблемы на влияет.
Но вот, что интересно (причем, только сейчас заметил) - на проявление проблемы влияет направление вращения мотора. То есть, частота вылезания паразитных "нулевых" сигналов очень сильно разная, в зависимости от того, в какую сторону крутится ротор мотора.
Мое личное предположение - работающий мотор создает помехи, препятствующие прохождению радиосигнала на частоте 433 МГц.
Потребляемый ток от БП 6 вольт - 0,13 А при постоянно вращающемся моторе. При пуске скачки до 0,35 А.
А попробуйте на время отказаться от радиуправления и запрограммировать в коде. чтоб мотор крутился полминуты туда. полминуты обратно...
И посмотрите, будет ли работать такая программа устойчиво.
Естественно, я такие опыты проводил. Все работает штатно.
Попробуй керамический конденсатор 0.1 - 1uF поставить параллельно мотору (припаивать на выводы мотора).
Короче, кое-что прояснилось, но обо всем по-порядку. Сначала я решил использовать для RF-приема другую библиотеку - не RCSwitch, а RemoteSwitch. Там функции организованы несколько по другому. В частности, требуется явно указать процедуру, обслуживающую прерывание. ну и, соответственно, написать эту процедуру. Как следствие - отпала необходимость запускать вызов RF-приема в loop'е.
Немного пооптимизировав код, я перенес все процедуры запуска двигателей (а их 4 варианта) непосредственно в эту самую процедуру.
Получилось как-то так:
Как видим, здесь вообще нет обработки "нулевого" сигнала, поскольку раз прерывание сработало, то сигнал никак не может быть нулевым. Вместо этого (временно) был включен обработчик "неизвестного" сигнала, вызывающий "стоп" - т.е., останов двигателей. Получить с пульта "неизвестный" сигнал можно, нажав одновременно две или более кнопок (собственно говоря, 4-хкнопочный пульт может выдать 15 разных сигналов, если использовать еще и комбинации кнопок).
Ну так вот. Запускаю скетч, жму кнопку А (Forward), моторы заработали, последовательный порт выдает "Forward", и... на этом все. Никакой реакции на кнопки нет, новая строчка в порту не появляется, моторы продолжают крутиться.
И тут до меня доходит: во время работы моторов прерывания не работают. То есть, вообще, от слова "никак". Для проверки гипотезы прописываю запуск моторов в setup'е, загоняю скетч в Ардуину, запускаю. Моторы включились, последовательный порт молчит, хотя я жму на пульте кнопки по-всякому.
Теперь не знаю, куда рыть. То ли это AdaFruit со своим Мотор-шилдом и его библиотекой накосячили, то ли что-то еще.
Попробую вместо Мотор-шилда поставить HW95.
И тут до меня доходит: во время работы моторов прерывания не работают. То есть, вообще, от слова "никак".
простите, не ясно, откуда вы это взяли. В библиотеке AFMotor.h я ничего подобного не вижу, да и ваш опыт со скетчем из первого сообщения говорит об обратном - там у вас RC-приемник работал во время запуска моторов, так что никакие прерывания моторы не выключают.
Другой вопрос, что сама идея засунуть всю программу в прерывание - тупиковая. Внутри одного прерывания не работают никакие другие, а значит у вас остановятся почти все системные функции ардуины - таймер миллис, работа с Сериал и прочее и прочее
Попробуйте переписать последнюю программу, обрабатывая внутри прерывания только получение кода с приемника, а все действия делать в основной программе
То есть, если было прерывание, и его функция вернула ненулевое значение (а она может возвращать по определению как раз только ненулевые значения), то переменная newValue принимает это значение. А если прерывания не было (в заданный промежуток времени), то переменная принимает нулевое значение.
Вот, собственно, и получается - если мотор работает, то он "отсекает" прослушивание прерывания, затем проходит заданный тайм-аут, значение из функции прерывания не получено, и поэтому переменная newValue обнуляется.
вы ошибаетесь. Откройте код библиотеки моторов и покажите мне место. где она отключает прерывания на время движения. Я ничего подобного не нашел.. А то, что у вас не проходят сигналы - может быть вызвано десятком других причин
А если прерывания не было (в заданный промежуток времени), то переменная принимает нулевое значение.
Если бы были запрещены ВСЕ прерывания, то перестало бы считаться millis и вы никгда бы не попали в блок
if ((newTime - oldTime) >= 100) {
Ну, не знаю. Тогда единственное, что мне остается делать - это надеяться, что кто-нибудь из здесь присутствующих напишет правильный код.