arduino самостоятельно устанавливает положение сервов при запуске.

Тема в разделе "Arduino & Shields", создана пользователем d00m, 9 дек 2012.

  1. d00m

    d00m Гик

    привет.

    у меня ардуинка подключена к linux (openwrt на mr3020) по USB.
    к ней подключено два серва.
    я обнаружил, что при открытии порта, чтобы передать ей команду, она зачемто выставляет на обоих сервах 93 градуса..

    вот мой скетч:
    Код (Text):
    #include <Servo.h>
    Servo h_servo, v_servo;
    String readString;
    char c;
    int ang,pos;
    int hr, vr;
     
    void setup()
    {
      h_servo.attach(9);
      v_servo.attach(10);
      Serial.begin(115200);
    }
     
    void loop() {
    while (Serial.available()) {
      c = Serial.read(); //gets one byte from serial buffer
      switch (c) {
     
        case 't': //////////////////////////////////////////////////////////////////
          Serial.print("ttYes! "); Serial.println(ang);
     
          hr = h_servo.read();
          Serial.print("hr1 "); Serial.println(hr);
          vr = v_servo.read();
          Serial.print("vr1 "); Serial.println(vr);
     
          v_servo.write(60);
          delay(500);
          h_servo.write(20);
          delay(500);  
          h_servo.write(60);
          readString = "";
          ang = 0;
          c = '0';
          delay(1000);
          break;
     
      }
          readString += c; //makes the string readString
     
          delay(2);  //slow looping to allow buffer to fill with next character
          ang = readString.toInt();  //convert readString into a number
    }
    }
    команды даю ему в screen (чтобы избежать проблемы авторесета - так порт остается открытым)

    # screen /dev/ttyACM0 115200

    и после нажатия кнопки t получаю такой вывод
    ttYes! 0
    hr1 93
    vr1 93

    ну а последующие нажатия t приводят к ожидаемому:

    ttYes! 0
    hr1 60
    vr1 60
    ttYes! 0
    hr1 60
    vr1 60


    почему он вначале центрирует сервы ? как это отключить ?
     
  2. d00m

    d00m Гик

    даже если открыть порт по другому:
    tail -f /dev/ttyACM0
    или
    cat /dev/ttyACM0

    я вижу что сервы устанавливаются в свои центральные значения - камера, что установлена на них направляется на одну точку..
     
  3. Mactep8

    Mactep8 Нерд

    Доброго времени суток.

    На мой взгляд все закономерно. Серва управляется при помощи PWM(ШИМ). Т.е. когда Вы привязываете серву на какой-нибудь пин, туда начинает поступать сигнал с некоторой шириной импульса.
    Среднестатистическая китайская серва имеет угол поворота 120градусов(+/-60). Ширина управляющего импульса при этом варьируется от 1000 до 2000 микросекунд.
    Судя по коду, сервы Вы привязываете, но не инициализируете. Библиотека servo рассчитана на управление сервой в пределах 0-180 градусов. И чтобы не повредить серву, загнав ее в такое положение, которое она не в состоянии воспроизвести, библиотека начинает работать с сервой с среднего положения.
    Т.е. выдает на пин импульсы с шириной 1500мкс.
    Хотите запустить серву с другого положения - сделайте в setup сразу после servo.attach() servo.write() с указанием стартовой позиции.
     
  4. d00m

    d00m Гик

    спасибо, значит это "виновата" библиотека servo.. и как выход, можно инициализировать положение сервов в секции setup.
    но у меня такой случа, что даже в секции setup выставлять свои init значения не вариант.
    вся эта ерунда выявилась уже на тестах php скрипта, который при отработке как раз таки _открывает порт_ и происходит вначале "центрирование" камеры, и только потом уже поворот на указанную команду..
    тоесть в случае управления с веб-морды нужно както научится избегать этого центрирования (или инициализирования в setup), а то всегда при обновлении веб страницы с видео с камеры и контролами для управления ею, изображение всегда будет смещаться на дефолтное стартовое состояние.
    мне же нужно, чтобы при управлении с web морды камера оставалась там где была и сервы реагировали только на команды write поступившие с контролов на страничке..
     
  5. Mactep8

    Mactep8 Нерд

    Порт и php совсем не при чем. Дело в том, что пока нет управляющего сигнала, серва может находиться в любом положении. При отсутствии питания ее хоть руками повернуть можно.
    В то же время, комманда
    Код (Text):
    hr = h_servo.read();
    не вернет Вам реального положения сервы. Она возвращает последнее выставленное
    значение управляющего сигнала из микроконтроллера(В общем случае после
    инициализации они друг другу соответствуют). Типовая китайская серва вообще
    ничего никогда не возвращает. Если уж так хочется узнать реальное положение сервы,
    водрузите на нее гироскоп. Далее считываете его показания и инициализируете серву
    в соответствии с ними. Но это как-то "из пушки по воробушкам".
    Вариант 2: перед выключением сохраняем положение сервы в энергонезависимую память
    EERPOM, а при старте - достаем оттуда сохраненное значение и им инициализируем серву.
     
  6. Unixon

    Unixon Оракул

    Откуда следует вывод: питанием сервы нужно управлять с МК, т.е. не включать серве питание до тех пор, пока не будет выставлен ШИМ выход.
     
  7. d00m

    d00m Гик

    что значит ни причем ?
    вот php код
    Код (Text):
    <?php
    include "php_serial.class.php";
     
    $serial = new phpSerial;
    //sleep(2);
     
    $serial->deviceSet("/dev/ttyACM0");
    $serial->confBaudRate(115200);
     
    $serial->deviceOpen();
    sleep(2);
     
    $serial->sendMessage("t");
    //sleep(2);
    //$read = $serial->readPort();
     
    //print $read;
     
    $serial->deviceClose();
     
    ?>
     
    при запуске его в браузере или из консоли - происходит открытие порта и следовательно - инициализация сервов значением из либы == 1500 или из секции setup если там чтото будет.
    при этом камера крутится из своего прежнего положения в стартовое.
    мне это НЕ нужно.


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




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

    вот это совершенно непонятнои поэтому может быть полезно.
    можете объяснить подробнее ?
    я насколько понимаю питание подается на серв в момент инита скетча в секции setup
    h_servo.attach(9);
    v_servo.attach(10);


    как же по другому сделать то ?
     
  8. Mactep8

    Mactep8 Нерд

    Вы похоже не очень хорошо понимаете как работает МК и сервы. Эти команды выставляют ШИМ, а не питание. Питание поступает на серву вместе с МК. Если у Вас конечно не отдельное питание для серв...
    Вы бы подробнее задачу описали: что именно Вы хотите сделать? Авось что-то и придумаем...
     
  9. Unixon

    Unixon Оракул

    Включаете питание сервы через N-канальный полевой транзистор.
    Затвор транзистора на свободную ногу МК и через 1-10кОм к земле.
    Сначала делаете
    h_servo.attach(9);
    h_servo.write(60);
    v_servo.attach(10);
    v_servo.write(60);
    а потом
    digitalWrite(11,HIGH); // на 11-й ноге висит затвор транзистора.
    Когда серва включится, у нее на управляющем входе уже будет правильный сигнал.
     
  10. d00m

    d00m Гик

    Mactep8: Вы похоже не внимательно читаете мои сообщения.. я уже раза три сказал чего я хочу сделать - управлять сервами из веб морды, но чтобы не проиходило этой постоянной инициализации при обновлении страницы.
    ну и в самом первом было сказано что сервы подключены к arduino напрямую..

    Unixon:
    ну эт почти черная магия..
    какой еще транзистор искать.. я ниче в этом не понимаю.
    но
    разве при этом она не крутанется в свое среднее положение (из-за servo либы) ?
     
  11. Mactep8

    Mactep8 Нерд

    При инициализации выхода МК, на серве питания не будет.
    А когда появится, на управляюшем контакте МК будет нужный Вам сигнал.
     
  12. d00m

    d00m Гик

    не пойму - какой сигнал там будет ? откуда он берется и почему он нужный для меня ?
     
  13. Mactep8

    Mactep8 Нерд

    Все по порядку:
    при запуске МК первым делом выполняется Setup(). МК на этот момент не знает где и что к нему подключено.
    В этой функции Вы делаете servo.attach(). Этот вызов говорит МК, что на указанный Вами пин надо подать ШИМ. Тут же встает вопрос: а с какой шириной импульса будет этот сигнал? По-умолчанию подставляется 1500 мкс и серва дергается в среднее положение.
    Далее выполняется ф-ция loop(). Она выполняется по кругу пока у МК есть питание и не вызван RESET.
    Что спрашиваете Вы: как сделать так, чтоб при запуске МК серва не дергалась. Немного перефразирую: как угадать ширину импульса, соответствующую текущему положению сервы? Ответы выше...

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

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

    d00m Гик

    спасибо за подробный ответ.
    я не вижу проблем в алгоритме. вижу только одну проблему. который вы очень удачно сформулировали:
    в ваших ответах выше, которые я смог понять, было два варианта:
    1 - гироскоп
    2 - сохранять значения сервов перед выключением.
    1-й вариант отпадает по дефолту, 2-й - выше я уже высказал свои сомнения на этот счет.

    напрашивается вывод - в общем случае, используя веб страничку с которой происходит управление сервами, НЕ удастся избежать постоянной стартовой инициализации сервов. Это будет происходить или за счет либы servo или за счет кода в секции setup..
     
  15. d00m

    d00m Гик

    правда может вы имели вввиду ответ Unixon-а насчет использования транзистора..
    я его до сих пор не догоняю если чесно.. (
    неужели, если я подключу транзистор, так как он сказал, то при выполнении команды
    digitalWrite(11,HIGH);
    сервы останутся на месте ? чтото не понятно..
    и кастати, вижу что это его сообщение отредактировано.
    там добавились строчки
    h_servo.attach(9);
    h_servo.write(60); --- new
    v_servo.attach(10);
    v_servo.write(60); --- new

    что тоже вносит непонятку.. зачем подключать какойто транзистор, если и просто так можно написать тоже самое в секции setup и при включении сервы крутануться на 60..

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

    Корней Гик

    Тогда вам нужены генераторы PWM с автономным питанием (на сервы же вам все равно придется подавать питание, что бы положение камеры сохранялось). Управляемый генератор PWM собирается по даташиту из 556 сдвоенного таймера или двух 555. Самым дорогим компонентом будет цифровой потенциометр или ЦАП.
    Возможно, проще всего будет использовать второй ардуин, общающийся с первым через SoftwareSerial. Или найдите ардуино-клон с отключаемым ресетом при открытии последовательного порта.
    Еще вариант - использовать тормоза. :)
     
  17. Unixon

    Unixon Оракул

    Дело в том, что между сбросом контроллера и выполнением команды инициализации пройдет некоторое время, в течение которого серва будет получать питание, но не будет получать корректный управляющий ШИМ сигнал. Вот в этом промежутке она и будет дергаться, с этим вы и боретесь. Мое предложение состоит в том, чтобы заставить серву сохранять прежнее положение в промежутке времени между подачей питания и выхода программы на готовность управлять сервой. При небольших механических нагрузках серва будет сохранять положение в отсутствие питания. Отсюда следует решение - не давать серве питания, чтобы она не имела возможности отреагировать на неправильный управляющий сигнал во время инициализации МК. Сделать это можно подавая питание через программно управляемый ключ. В идеале, управляющий сигнал тоже нужно пропускать через ключ. Т.е. у сервы будет не 3 сигнала VCC, GND, PWM, а 4 сигнала: VCC, GND, PWM и еще ENABLE. Пока ENABLE=0, VCC и PWM тоже = 0V и серва не получает вообще ничего. А потом когда у вас программа уже стартовала и готова отдать серве ее положение, то сначала устанавливается PWM, а уже потом подается ENABLE=1 и тогда серва одновременно получает и питание и сигнал на поворот. Но поскольку изменения положения не было, то вместо поворота серва будет просто удерживать ранее заданный угол. Все, задача решена.
     
  18. Mactep8

    Mactep8 Нерд

    Вот только мне кажется дальше встанет вопрос в том, какое значение PWM передать серве, чтоб она на месте осталась... :)
    Странно другое: мне кажется или Setup() отрабатывает каждый раз с открытием порта извне.
    Позвольте спросить: а откуда МК берет свое питание и Вы уверены, что на МК есть питание пока порт закрыт извне?
     
  19. d00m

    d00m Гик

    Unixon
    спасибо за столь подробное объяснение.
    хотя и не понял до конца этой магии, но все же идея в целом мне стала понятна..
    пока не сформирован ШИМ - питания на сервы не подавать.
    единственно не ясно, когда и откуда возьмется нужный ШИМ ? или раз сервы не крутились после открытия порта (ресета МК) то достаточно будет ДОЖДАТЬСЯ окончания этого "промежутка между сбросом контроллера и выполнением команды инициализации" ?
    и где же нужно вводить эту команду
    digitalWrite(11,HIGH);
    ?
    в setup ?

    Mactep8
    если эти вопросы адресованы мне то:
    и с учетом
    http://chiolina.wordpress.com/2012/11/23/51/
    где сказано:
    как раз в случае подключения МК к linux платформе и происходит такое ресет МК - МК ждет данные для перепрошивки таким образом..
    видимо в это время и дергаются сервы..
     
  20. Unixon

    Unixon Оракул

    Ну вы же сами выдаете команды на серве на поворот. Вот от них то нужный ШИМ и возьмется. Ну а питание подаете сразу следующей командой или с небольшой задержкой. А где она там в программе будет стоять - дело десятое.