ArduinoNano/Spektrum DX8/AR8000 - переключение между ручным и автоматическим управлением сервами.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Приветствую!

Имеется ардуина нано, спектрумовский приемник(AR8000) и передатчик(DX8). Также имеется 3-х осевой подвес для аэрофотосъемки. Сейчас в управлении задействованы только две оси pan и tilt, ну и плюс ИК диод для фото.

Хотелось на свободный канал повесить возможность выбора (изменением положения свободного тумблера на пульте) ручного управления сервами либо запуск автоматического цикла ардуины. С приемника выходит только ШИМ - как его обработать чтоб ардуина поняла включен тумблер на пульте или выключен?

Вот код который работает сейчас

#include <Servo.h>              
#include <multiCameraIrControl.h>

///////////////////////////////////////////////////////////////////
// Номера входов и выходов
///////////////////////////////////////////////////////////////////

int servo_gor_pin    = 7;                   // пин для сервы горизонтального поворота камеры
int servo_vert_pin   = 6;                   // пин для сервы вертикального поворота камеры

int manual_pin       = 10;                   // пин включающий ручное управление с пульта
int manual_gor_pin   = 12;                   // вход сигнала с приёмника для горизонтальной сервы
int manual_vert_pin  = 11;                  // вход сигнала с приёмника для вертикальной сервы

///////////////////////////////////////////////////////////////////
// Объекты программы
///////////////////////////////////////////////////////////////////

Servo servo_gor;                            // создаём объект для контроля сервы горизонтального поворота
Servo servo_vert;
Sony nex(9);

///////////////////////////////////////////////////////////////////
// Переменные программы
///////////////////////////////////////////////////////////////////

boolean servo_gor_go = LOW;
int posv1 = 70;
int posv2 = 100;
int posv3 = 50;
int posr = 92;

///////////////////////////////////////////////////////////////////
// Инициализация
///////////////////////////////////////////////////////////////////

void setup() 
{ 

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  pinMode(manual_vert_pin, INPUT);
  pinMode(manual_gor_pin, INPUT);
  pinMode(manual_pin, INPUT);
  servo_vert.attach(servo_vert_pin);
  servo_gor.attach(servo_gor_pin);
  Serial.begin(115200);
  Serial.println("Starting up!");

  digitalWrite(manual_pin, HIGH);  
} 


///////////////////////////////////////////////////////////////////
// Автоматическое управление
///////////////////////////////////////////////////////////////////

void ServoGor(boolean g)                           // функция поворота сервы горизонта
{
  int p;
  if(g==HIGH)
  {
    servo_gor_go = HIGH;
    servo_gor.attach(servo_gor_pin);               // подключаем серву горизонтальную
    for(p=1525; p<=1600; p++)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
  }
  if(g==LOW)
  {
    servo_gor_go = LOW;
    for(p=1600; p>=1525; p--)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
    servo_gor.detach();                             //отключаем серву горизонтальную
  }
}

void cycle()
{
  servo_gor.write(posr);
  servo_vert.write(posv2);
  delay(800);
  shutter(); 
  delay(800);
  servo_vert.write(posv1);
  delay(800);
  shutter(); 
  delay(800);
  ServoGor(HIGH);
  delay(400);
  ServoGor(LOW);
}

void shutter()
{
  nex.shutterNow();
}

void auto_loop()
{
  for (int i=0;i<9;i++)
    cycle();

  servo_vert.write(posv3);
  delay(800);
  shutter(); 
  delay(800);
}


///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{
  digitalWrite(servo_gor_pin, digitalRead(manual_gor_pin));
  digitalWrite(servo_vert_pin, digitalRead(manual_vert_pin));
}
///////////////////////////////////////////////////////////////////
// Основной цикл
///////////////////////////////////////////////////////////////////

int is_manual = 0;

void loop()
{
  if (digitalRead(manual_pin) == HIGH)
  {
    if (is_manual != 1)
    {
      Serial.println("Manual mode is on\r\n");

      // Detach servo drivers
      if (servo_vert.attached() == true) 
        servo_vert.detach();

      if (servo_gor.attached() == true)
        servo_gor.detach();

      is_manual = 1;
    }

    manual_loop();
  }
  else
  {
    if (is_manual != 0)
    {
      Serial.println("Automatic mode is on\r\n");

      if (servo_vert.attached() == false) 
        servo_vert.attach(servo_vert_pin);

      if (servo_gor.attached() == false)
        servo_gor.attach(servo_gor_pin);

      is_manual = 0;
    }

    auto_loop();
  }
}

Сейчас переключение между ручным и автоматическим управлением осуществляется с помощью минисервы, которая замыкает manual_pin на землю. Серва в свою очередь подключена на свободный канал AUX. Реально ли это осуществить программно?

Буду благодарен любой помощи, ибо сам в этом смыслю поверхностно :) 

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

И еще в догонку - при ручном управлении подергиваются все сервы. Из-за чего это может быть?

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Народ, может я как-то не точно выразился? А то никакой реакции нет...

У меня на подвесе сейчас пины на землю вот так замыкаются:

Ну согласитесь - это жесть)

Сложно ардуину научить длинну импульса считать? Ну чтоб она понимала когда тумблер переключается на пульте?

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Ладно.... тогда вот так поставлю вопрос:

можно ли прочитать ШИМ сигнал идущий от приемника к серве с помощью Ардуины?

Дайте хоть какуюто зацепку)

 

step962
Offline
Зарегистрирован: 23.05.2011

можно...

С определенной периодичностью считываете логический (т.е. 0/1) уровень сигнала на вашей ШИМ-линии, на основе полученных данных определяете длительность импульса и длительность паузы. На основании полученных данных получаете частоту ШИМ сигнала (что-то в диапазоне 450-500 Гц, вроде бы), рассчитываете скважность... А больше там и определять-то нечего.

Опроса с частотой 200-300 кГц (частота ШИМ грубо 500 Гц, да по 2 опроса на каждый из 255 шагов изменения скважности - это если ШИМ той-же Ардуинкой генерируется) хватит для вполне приличной точности.

Это если совсем просто. Захочется сложности - можете с помощью прерываний ловить фронты, а с помощью счетчиков рассчитывать длительности пульсов/пауз. На это меньше ресурсов мк потребуется, но больше ваших.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Благодарю за ответ. Мдя, для меня не просто это все...  честно говоря не представляю как реализовать это программно.

Может где-нибудь встречали похожие реализации - чтоб посмотреть так сказать на примере? 

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

 

 

 

 

 

step962
Offline
Зарегистрирован: 23.05.2011

trypel пишет:

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

Первое, что приходит в голову - выбросить к чертям собачьим ардуину и передавать ШИМ-сигнал с приемника прямо на сервы.

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

digitalWrite(pinOUT,digitalRead(pinIN)); 

Частоты сканирования в пару сотен кГц с лихвой хватит для трансляции ШИМ-сигнала с приемника через Ардуину на серву(-ы). Практически без искажений.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Первое, что приходит в голову - выбросить к чертям собачьим ардуину и передавать ШИМ-сигнал с приемника прямо на сервы.

К сожалению не получится - ардуина должна в случае чего перехватывать управление и фигашить сама сервами.

 

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

digitalWrite(pinOUT,digitalRead(pinIN)); 

Так именно так у меня и сделано :)

///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{
  digitalWrite(servo_gor_pin, digitalRead(manual_gor_pin));
  digitalWrite(servo_vert_pin, digitalRead(manual_vert_pin));
}

Но дерганья страшные.. получается же передается не ШИМ а значение HI или LOW, я правильно понимаю? А тут нужно через analogRead подходить?

Подрубил управляющий провод с канала элеватора приемника на нулевой пин дуины чтоб посмотреть какие данные он передает

int val; 
void setup() { 
            Serial.begin(115200);        // полученные данные будем записывать в COM-порт     
} 

void loop() { 
      val = analogRead(0);    // считываем значение с потенциометра           
            Serial.println(val);        // передаём значение на монитор компьютера     
}

Крутил стиком, крутил - по барабану, никак не реагирует... выдает периодично вот такие данные

 

Частоты сканирования в пару сотен кГц с лихвой хватит для трансляции ШИМ-сигнала с приемника через Ардуину на серву(-ы). Практически без искажений.

Вот тут куча вопросов - эта частота сканирования где,как и когда задается?)) Где про это почитать? 

Наткнулся на интересные статьи, кстати

http://rcarduino.blogspot.co.uk/2012/04/how-to-read-multiple-rc-channels-draft.html

http://rcarduino.blogspot.ru/2012/01/how-to-read-rc-receiver-with.html

http://rcarduino.blogspot.ru/2012/11/how-to-read-rc-channels-rcarduinofastlib.html

Сижу, перевариваю потихоньку

maksim
Offline
Зарегистрирован: 12.02.2012

trypel пишет:

Народ, может я как-то не точно выразился? А то никакой реакции нет...

У меня на подвесе сейчас пины на землю вот так замыкаются:

Ну согласитесь - это жесть)

Сложно ардуину научить длинну импульса считать? Ну чтоб она понимала когда тумблер переключается на пульте?

 

Роботизированный панорамная головка? 

Вместо "этого" можно было оптроны использовать. Ну на крайни случай реле.

А с IRcontrol не заработало?

maksim
Offline
Зарегистрирован: 12.02.2012

Это частота, с которой обновляется ваша функция manual_loop(), после того как вы вызываете функцию servo_gor.detach(); вывод скорее всего конфигурируется на вход, попробуйте сделать так в 144 строке:

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  is_manual = 1;
}

На выходе получается, то что на входе, а по вашему ШИМ - это не HIGH и LOW? погуглите что такое ШИМ.

Если хотите считывать ШИМ и потом его генерить, то нужна не analogRead() (вообще можно и ее если добавить RC-цепь, но нафиг надо цифровой сигнал превращать в аналоговый, а потом оьратно), а функция например pulseIn() но больше чем уверен, что получится полная ж..а, так как pulseIn() блокирующая функция.

 

maksim
Offline
Зарегистрирован: 12.02.2012

Если все равно дергается и у вас дуина Нана, то можно попробовать увеличить частоту опроса, замените свою функцию manual_loop(), вот на эту:

///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{ 
  DDRD |= (1<<PD6) | (1<<PD7);                  // Настраиваем 6 и 7 выводы на выход
  while(PINB&1<<PB2){                           // Цикл пока на 10 выводе 1
    PINB&1<<PB4?PORTD|=1<<PD7:PORTD&=~(1<<PD7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<PB3?PORTD|=1<<PD6:PORTD&=~(1<<PD6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////

 

step962
Offline
Зарегистрирован: 23.05.2011

trypel пишет:

Вот тут куча вопросов - эта частота сканирования где,

в вашей программе, естественно
Цитата:
как

Разными способами:
- можно настроить таймер на определенную частоту и в соответствующем прерывании таймера запускать АЦ-преобразование;
- можно следить за "часами" мк (millis(), micros()) и в определенные моменты времени запускать АЦ-преобразование;
- можно вызывать АЦ-преобразование в цикле: сканирование будет производиться с частотой, которую может обеспечить ваш цикл.
Как узнать, с какой частотой выполняется сканирование? В первых двух случаях вопрос не имеет смысла. В третьем случае запомните время перед циклом, выполните 1000 опросов, опять считайте значение времени, поделите разницу значений на 1000 и получите длительность одного цикла сканирования. Обратное этой величине значение будет частотой сканирования.
Цитата:
и когда задается?))

когда требуется
Цитата:
Где про это почитать?

Интернет, книжки...

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

maksim пишет:

Роботизированный панорамная головка? 

Вместо "этого" можно было оптроны использовать. Ну на крайни случай реле.

А с IRcontrol не заработало?

Можно сказать и так :) Точнее летающая роботизированная головка :)

О, оптроны, точно ... можно заморочиться)

IRcontrol это что - библиотека, устройство?

maksim пишет:

вывод скорее всего конфигурируется на вход, попробуйте сделать так в 144 строке:

Сделал, дергается также..

maksim пишет:

На выходе получается, то что на входе, а по вашему ШИМ - это не HIGH и LOW?

Не ну понятно что HIGH и LOW, но там же скважность еще - дуинка ее не "гробит" при такой передаче?))

maksim пишет:

но нафиг надо цифровой сигнал превращать в аналоговый, а потом оьратно

Золотые слова! Я тоже так думаю - но вот не знаю как реализовать

maksim пишет:

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

Прошу прощения, дуинка ругается на имена портов - что не так?

Спасибо за помощь! ;)

<span>step962</span> пишет:

Разными способами:

Спасибо, буду копать)

 

maksim
Offline
Зарегистрирован: 12.02.2012

Версия IDE причиной тому может быть.

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

///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{ 
  DDRD |= (1<<6) | (1<<7);                  // Настраиваем 6 и 7 выводы на выход
  while(PINB&1<<2){                           // Цикл пока на 10 выводе 1
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////

И кстати, как раз вот таким способом и получится добиться тех самых пары сотен кГц и еще раз повторюсь, так работать будет, только на Нане, Уне, Демеланове (на всех с ATmega328/168), на Меге, Леонарде и т.д. работать не будет.

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Вот это да! Все заработало идеально, спасибо maksim 

Когда от usb питание идет - вообще нет подергиваний, а вот когда от липошки с беком тогда дергаться опять начинают... пересмотрю цепь питания - может от бека наводки идут %)

 

maksim
Offline
Зарегистрирован: 12.02.2012

 

trypel пишет:

IRcontrol это что - библиотека, устройство?

Это ваша библиотека multiCameraIrControl.h (я просто сократил) с ней я так понял не заработало и вы поставили серву на фокусировку и спуск.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Почему, работает - серва замыкает пин и пошла команда ИК диоду)) просто опять же - мне нужно чтоб можно было с пульта спуск осуществлять и чтоб автоматом шло. В панорамном цикле отлично ИК отрабатывает. А так - стик рудера вправо и фоткает) стик влево - панорама пошла) Вот такой колхоз)

maksim
Offline
Зарегистрирован: 12.02.2012

Что я не пойму что у вас серва зымыкает?

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

На землю замыкает пин - на фотограии контактная площадка перед сервой, к ней ноль подведен, а к качельке подведены провода с пинов ардуины (через 1,2 кОм резисторы)

10 пин - включение панорамного цикла

4 пин - включение диода (в этом коде его нет)

maksim
Offline
Зарегистрирован: 12.02.2012

Жесть, тогда оптроны не помогут, я думал этой сервой дуина управляет. 

maksim
Offline
Зарегистрирован: 12.02.2012

А зачем диод подключать?

На пульте ДУ есть настройки каналов? Можно канал настроить как цифровой? 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

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

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Диод нужен для спуска затвора, а изменить канал на просто цифру вроде нельзя, сейчас покопаюсь в настройках

maksim
Offline
Зарегистрирован: 12.02.2012

Так а что в описании написано? что идет с приемника на канале AUX 1 ? тоже ШИМ? и вы как раз к нему серву подключили?

maksim
Offline
Зарегистрирован: 12.02.2012

trypel пишет:

Диод нужен для спуска затвора, а изменить канал на просто цифру вроде нельзя, сейчас покопаюсь в настройках

Опять ничего не понял, вы же для спуска затвора используете библиотеку ...IRcontrol зачем диод физически отключать от дуины?

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Ну вообще идет ШИМ - так как серву просто включаешь в приемник и все, можно тумблером рулить. Положение 1 - примерно 30 градусный поворот сервы, положение 2 - еще на 30 градусов повернулась

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

сейчас доку поищу по пульту

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Смотрите, диод подключен к дуине на 9 пин (в коде прописан)

Он работает нормально, дуина им управляет когда отщелкивает панорамы

Но когда ручное управление подвесом, мне нужно чтоб я мог с пульта фотографировать. У меня идет видео с борта через видеопередатчик, полностью ручное управление - чтоб сделать кадр, мне нужно отдать команду ардуине. Т.е. я корочу 4 пин для того чтоб ардуина поняла что нужно делать цикл shutter()

maksim
Offline
Зарегистрирован: 12.02.2012

С сервой понятно, а попробуйте настроить углы побольше, есть такая возможность?

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

да углы можно побольше настроить - а что это даст?

maksim
Offline
Зарегистрирован: 12.02.2012

trypel пишет:

Смотрите, диод подключен к дуине на 9 пин (в коде прописан)

Он работает нормально, дуина им управляет когда отщелкивает панорамы

Но когда ручное управление подвесом, мне нужно чтоб я мог с пульта фотографировать. У меня идет видео с борта через видеопередатчик, полностью ручное управление - чтоб сделать кадр, мне нужно отдать команду ардуине. Т.е. я корочу 4 пин для того чтоб ардуина поняла что нужно делать цикл shutter()

 

Тот вариант, который я вам предложил в ручном режиме будет управлять только двумя сервами, shutter()'а не будет. Если конечно вы не засунули его в тот же цикл, где ручное управление сервами.

Код покажите весь.

maksim
Offline
Зарегистрирован: 12.02.2012

trypel пишет:

да углы можно побольше настроить - а что это даст?

Это даст больший разброс в микросекундах при считывании сигнала с приемника дуиной.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Код с ручным управлением ИК диода на другой машине, и фота с ИК нет чтоб проверить но вроде так работает.

В цикле loop прописываем

void loop()
{
  if (digitalRead(photo_pin) == HIGH)
  {
    shutter();
  }

Вот полный код, который сейчас, с вашими правками

#include <Servo.h>              
#include <multiCameraIrControl.h>

///////////////////////////////////////////////////////////////////
// Номера входов и выходов
///////////////////////////////////////////////////////////////////

int servo_gor_pin    = 7;                   // пин для сервы горизонтального поворота камеры
int servo_vert_pin   = 6;                   // пин для сервы вертикального поворота камеры

int photo_pin       = 4;                    // пин включающий ИКдиод
int manual_pin       = 10;                   // пин включающий автоматическое управление с пульта
int manual_gor_pin   = 12;                   // вход сигнала с приёмника для горизонтальной сервы
int manual_vert_pin  = 11;                  // вход сигнала с приёмника для вертикальной сервы

///////////////////////////////////////////////////////////////////
// Объекты программы
///////////////////////////////////////////////////////////////////

Servo servo_gor;                            // создаём объект для контроля сервы горизонтального поворота
Servo servo_vert;
Sony nex(9);

///////////////////////////////////////////////////////////////////
// Переменные программы
///////////////////////////////////////////////////////////////////

boolean servo_gor_go = LOW;
int posv1 = 70;
int posv2 = 100;
int posv3 = 50;
int posr = 92;

///////////////////////////////////////////////////////////////////
// Инициализация
///////////////////////////////////////////////////////////////////

void setup() 
{ 

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  pinMode(manual_vert_pin, INPUT);
  pinMode(manual_gor_pin, INPUT);
  pinMode(manual_pin, INPUT);
  servo_vert.attach(servo_vert_pin);
  servo_gor.attach(servo_gor_pin);
  Serial.begin(115200);
  Serial.println("Starting up!");

  digitalWrite(manual_pin, HIGH);  
} 


///////////////////////////////////////////////////////////////////
// Автоматическое управление
///////////////////////////////////////////////////////////////////

void ServoGor(boolean g)                           // функция поворота сервы горизонта
{
  int p;
  if(g==HIGH)
  {
    servo_gor_go = HIGH;
    servo_gor.attach(servo_gor_pin);               // подключаем серву горизонтальную
    for(p=1525; p<=1600; p++)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
  }
  if(g==LOW)
  {
    servo_gor_go = LOW;
    for(p=1600; p>=1525; p--)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
    servo_gor.detach();                             //отключаем серву горизонтальную
  }
}

void cycle()
{
  servo_gor.write(posr);
  servo_vert.write(posv2);
  delay(800);
  shutter(); 
  delay(800);
  servo_vert.write(posv1);
  delay(800);
  shutter(); 
  delay(800);
  ServoGor(HIGH);
  delay(400);
  ServoGor(LOW);
}

void shutter()
{
  nex.shutterNow();
}

void auto_loop()
{
  for (int i=0;i<9;i++)
    cycle();

  servo_vert.write(posv3);
  delay(800);
  shutter(); 
  delay(800);
}


///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{ 
  DDRD |= (1<<6) | (1<<7);                  // Настраиваем 6 и 7 выводы на выход
  while(PINB&1<<2){                           // Цикл пока на 10 выводе 1
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////
// Основной цикл
///////////////////////////////////////////////////////////////////

int is_manual = 0;

void loop()
{
  if (digitalRead(photo_pin) == HIGH)
  {
    shutter();
  }
  if (digitalRead(manual_pin) == HIGH)
  {
    if (is_manual != 1)
    {
      Serial.println("Manual mode is on\r\n");

      // Detach servo drivers
      if (servo_vert.attached() == true) 
        servo_vert.detach();

      if (servo_gor.attached() == true)
        servo_gor.detach();
  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);

      is_manual = 1;
    }

    manual_loop();
  }
  else
  {
    if (is_manual != 0)
    {
      Serial.println("Automatic mode is on\r\n");

      if (servo_vert.attached() == false) 
        servo_vert.attach(servo_vert_pin);

      if (servo_gor.attached() == false)
        servo_gor.attach(servo_gor_pin);

      is_manual = 0;
    }

    auto_loop();
  }
}

 

maksim
Offline
Зарегистрирован: 12.02.2012

Подключаете вывод приемника к 2 выводу дуины (учтите, что у приемника и дуины должна быть общая земля) и заливаете это и смотрите в сериал мониторе как меняется значение при разных положениях тумблера.

volatile unsigned long time = 0, micros_prev = 0;

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, Mode, CHANGE);
  digitalWrite(2, 1);
}

void loop() {
  Serial.println(time);
}

void Mode(){
  if(PIND&1<<2){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

нули только выдает

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

прошу прощения! 

1900/1500/1100

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

круто! :)

maksim
Offline
Зарегистрирован: 12.02.2012

Ну и остается только добавить это дело в код:

#include <Servo.h>              
#include <multiCameraIrControl.h>

///////////////////////////////////////////////////////////////////
// Номера входов и выходов
///////////////////////////////////////////////////////////////////

int servo_gor_pin    = 7;                   // пин для сервы горизонтального поворота камеры
int servo_vert_pin   = 6;                   // пин для сервы вертикального поворота камеры

int manual_pin       = 2;                    // пин включающий автоматическое/ручного управление и спуск затвора с пульта
int manual_gor_pin   = 12;                   // вход сигнала с приёмника для горизонтальной сервы
int manual_vert_pin  = 11;                  // вход сигнала с приёмника для вертикальной сервы

///////////////////////////////////////////////////////////////////
// Объекты программы
///////////////////////////////////////////////////////////////////

Servo servo_gor;                            // создаём объект для контроля сервы горизонтального поворота
Servo servo_vert;
Sony nex(9);

///////////////////////////////////////////////////////////////////
// Переменные программы
///////////////////////////////////////////////////////////////////

boolean servo_gor_go = LOW;
int posv1 = 70;
int posv2 = 100;
int posv3 = 50;
int posr = 92;
unsigned long  micros_prev = 0;
volatile unsigned int time = 0;

///////////////////////////////////////////////////////////////////
// Инициализация
///////////////////////////////////////////////////////////////////

void setup() 
{ 

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  pinMode(manual_vert_pin, INPUT);
  pinMode(manual_gor_pin, INPUT);
  pinMode(manual_pin, INPUT);
  servo_vert.attach(servo_vert_pin);
  servo_gor.attach(servo_gor_pin);
  Serial.begin(115200);
  Serial.println("Starting up!");

  digitalWrite(manual_pin, HIGH);  
  attachInterrupt(0, Mode, CHANGE);
} 

void Mode()
{
  if(PIND&1<<2){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}
///////////////////////////////////////////////////////////////////
// Автоматическое управление
///////////////////////////////////////////////////////////////////

void ServoGor(boolean g)                           // функция поворота сервы горизонта
{
  int p;
  if(g==HIGH)
  {
    servo_gor_go = HIGH;
    servo_gor.attach(servo_gor_pin);               // подключаем серву горизонтальную
    for(p=1525; p<=1600; p++)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
  }
  if(g==LOW)
  {
    servo_gor_go = LOW;
    for(p=1600; p>=1525; p--)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
    servo_gor.detach();                             //отключаем серву горизонтальную
  }
}

void cycle()
{
  servo_gor.write(posr);
  servo_vert.write(posv2);
  delay(800);
  shutter(); 
  delay(800);
  servo_vert.write(posv1);
  delay(800);
  shutter(); 
  delay(800);
  ServoGor(HIGH);
  delay(400);
  ServoGor(LOW);
}

void shutter()
{
  nex.shutterNow();
}

void auto_loop()
{
  for (int i=0;i<9;i++)
    cycle();

  servo_vert.write(posv3);
  delay(800);
  shutter(); 
  delay(800);
}


///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////
void manual_loop()
{ 
  DDRD |= (1<<6) | (1<<7);                // Настраиваем 6 и 7 выводы на выход
  while(time > 1700){                   
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////
// Основной цикл
///////////////////////////////////////////////////////////////////

int is_manual = 0;

void loop()
{
  if (time < 1300)
    shutter();
  else if (time > 1700)
  {
    if (is_manual != 1)
    {
      Serial.println("Manual mode is on\r\n");

      // Detach servo drivers
      if (servo_vert.attached() == true) 
        servo_vert.detach();

      if (servo_gor.attached() == true)
        servo_gor.detach();
      is_manual = 1;
    }

    manual_loop();
  }
  else
  {
    if (is_manual != 0)
    {
      Serial.println("Automatic mode is on\r\n");

      if (servo_vert.attached() == false) 
        servo_vert.attach(servo_vert_pin);

      if (servo_gor.attached() == false)
        servo_gor.attach(servo_gor_pin);

      is_manual = 0;
    }

    auto_loop();
  }
}

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Огромное спасибо за помощь, maksim

С утра доберусь до ардуины, заодно захвачу фот с ИК и все проверю.

Честно, я долго ковырял инет по этому вопросу - в рунете вообще голяк, а на забугорных аналогичного решения я не нашел (хотя может и хреново искал - с моим то знанием инглиша) - очень благодарен вам что уделили время. Думаю многим это очень пригодится!

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Еще один нюанс! :)

После некоторых раздумий, все же решил разнести на разные каналы переключение режима съемки и спуск затвора.

Потому что можно случайно перещелкнуть не туда и пойдет цикл автосъемки - а когда снимаешь с коптера то каждая секунда на счету :)

Так вот, maksim, сейчас попробывал по вашей аналогии опросить AUX 1 четвертым пином ардуины, полезли страшные цифры, я испугался и выключил :))

volatile unsigned long time = 0, micros_prev = 0;

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, Mode, CHANGE);
  digitalWrite(4, 1);
}

void loop() {
  Serial.println(time);
}

void Mode(){
  if(PIND&1<<4){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}

Проблема в том что я не правильно обратился к порту или к этому порту вообще нельзя обращаться таким образом?

Вроде согласно вот этому  описанию, 4 пину соответствует PD4..

Опрашивал вторым пином - выдает данные идентичные AUX 2

 

 

maksim
Offline
Зарегистрирован: 12.02.2012

Дело в том, что внешние прерывания есть только на 2 и 3 выводах.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

ага! теперь понятно, спасибо) Сейчас попробую задействовать 3-й пин

maksim
Offline
Зарегистрирован: 12.02.2012

То-есть вам нужно копировать функцию Mode назвав например Mode1, поменяв в ней на PIND&1<<3. В сетапе сконфигурировать прерывание 1, указав функцию Mode1 и объявить свои переменные например time1 и time_prev1.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

maksim пишет:

То-есть вам нужно копировать функцию Mode назвав например Mode1, поменяв в ней на PIND&1<<3. В сетапе сконфигурировать прерывание 1, указав функцию Mode1 и объявить свои переменные например time1 и time_prev1.

ага, ясно

Странно, подключил 3-ий пин - нули возвращает

Вроде же негде ошибиться?

volatile unsigned long time = 0, micros_prev = 0;

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, Mode, CHANGE);
  digitalWrite(3, 1);
}

void loop() {
  Serial.println(time);
}

void Mode(){
  if(PIND&1<<3){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}

 

maksim
Offline
Зарегистрирован: 12.02.2012

А изменить номер прерывания? Еще раз внимательно прочтите первый обзац по выше указанной ссылке.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Прошу прщения - подумал это относится только к общей программе :)

Изменил, все заработало. Сейчас доделаю программу)

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Не хочет нормально скетч фунциклировать :(

По логике в основном цикле нужно просто переменную time заменить на time1 перед вызовом shutter() и все... но почему-то начинает отрабатываться автоматическое управление при подаче питания. Оба тумблера на пульте в положении 1900.

#include <Servo.h>              
#include <multiCameraIrControl.h>

///////////////////////////////////////////////////////////////////
// Номера входов и выходов
///////////////////////////////////////////////////////////////////

int servo_gor_pin    = 7;                   // пин для сервы горизонтального поворота камеры
int servo_vert_pin   = 6;                   // пин для сервы вертикального поворота камеры

int manual_photo_pin = 2;                    //пин включающий ИК (канал AUX1 на передатчике)
int manual_pin       = 3;                    // пин включающий автоматическое/ручного управление и спуск затвора с пульта (канал AUX2 на передатчике)

int manual_gor_pin   = 12;                   // вход сигнала с приёмника для горизонтальной сервы
int manual_vert_pin  = 11;                   // вход сигнала с приёмника для вертикальной сервы

///////////////////////////////////////////////////////////////////
// Объекты программы
///////////////////////////////////////////////////////////////////

Servo servo_gor;                            // создаём объект для контроля сервы горизонтального поворота
Servo servo_vert;                           //создаём объект для контроля сервы вертикального поворота
Nikon nex(9);                               // ИК диод для управления затвором

///////////////////////////////////////////////////////////////////
// Переменные программы
///////////////////////////////////////////////////////////////////

boolean servo_gor_go = LOW;
int posv1 = 70; //позиции вертикальной сервы
int posv2 = 100;
int posv3 = 50;
int posr = 92;
unsigned long  micros_prev = 0;      ////канал AUX2
volatile unsigned int time = 0;
unsigned long  micros_prev1 = 0;     ////канал AUX1
volatile unsigned int time1 = 0;

///////////////////////////////////////////////////////////////////
// Инициализация
///////////////////////////////////////////////////////////////////

void setup() 
{ 

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  pinMode(manual_vert_pin, INPUT);
  pinMode(manual_gor_pin, INPUT);
  pinMode(manual_pin, INPUT);
  
  servo_vert.attach(servo_vert_pin);
  servo_gor.attach(servo_gor_pin);
  
  digitalWrite(manual_pin, HIGH);        ///AUX2
  attachInterrupt(0, Mode, CHANGE);
  
  digitalWrite(manual_photo_pin, HIGH);  ////AUX1
  attachInterrupt(1, Mode1, CHANGE);
} 

void Mode()  ////чтение канала AUX2 (переключение между авто\ручным управлением)
{
  if(PIND&1<<2){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}

void Mode1()    ////чтение канала AUX1 (спуск затвора)
{
  if(PIND&1<<3){
    micros_prev1 = micros();
  }
  else{
    time1 = micros() - micros_prev1;
  }
}

///////////////////////////////////////////////////////////////////
// Автоматическое управление
///////////////////////////////////////////////////////////////////

void ServoGor(boolean g)                           // функция поворота сервы горизонта
{
  int p;
  if(g==HIGH)
  {
    servo_gor_go = HIGH;
    servo_gor.attach(servo_gor_pin);               // подключаем серву горизонтальную
    for(p=1525; p<=1600; p++)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
  }
  if(g==LOW)
  {
    servo_gor_go = LOW;
    for(p=1600; p>=1525; p--)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
    servo_gor.detach();                             //отключаем серву горизонтальную
  }
}

void cycle()    //панорамный цикл
{
  servo_gor.write(posr);
  servo_vert.write(posv2);
  delay(800);
  shutter(); 
  delay(800);
  servo_vert.write(posv1);
  delay(800);
  shutter(); 
  delay(800);
  ServoGor(HIGH);
  delay(400);
  ServoGor(LOW);
}

void shutter()   // спуск затвора
{
  nex.shutterNow();
}

void auto_loop() //полный цикл автоматического управления
{
  for (int i=0;i<9;i++)
    cycle();

  servo_vert.write(posv3); //съемка надира
  delay(800);
  shutter(); 
  delay(800);
}


///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////

void manual_loop() //цикл ручного управления сервами с передатчика
{ 
  DDRD |= (1<<6) | (1<<7);                // Настраиваем 6 и 7 выводы на выход
  while(time > 1700){                   
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////
// Основной цикл
///////////////////////////////////////////////////////////////////

int is_manual = 0;

void loop()
{
 if (time1 < 1300) 
    shutter();
  else if (time > 1700)
   {
    if (is_manual != 1)
    {
      
      // Detach servo drivers
      if (servo_vert.attached() == true) 
        servo_vert.detach();

      if (servo_gor.attached() == true)
        servo_gor.detach();
      is_manual = 1;
    }
    manual_loop();
  
  }
  else if (is_manual != 0)
    {
        if (servo_vert.attached() == false) 
        servo_vert.attach(servo_vert_pin);

      if (servo_gor.attached() == false)
        servo_gor.attach(servo_gor_pin);

      is_manual = 0;
    }
    auto_loop();
  }

 

maksim
Offline
Зарегистрирован: 12.02.2012

Смотрите что получается. У нас в ручном режиме замкнутый цикл, в котором проверяется только переменная time и не проверяется time1, тоесть shutter() будет выполняться только тогда когда мы выйдем из ручного режима, поэтому проверку time1 нужно засунуть в цикл ручного управления. 

void manual_loop() //цикл ручного управления сервами с передатчика
{ 
  DDRD |= (1<<6) | (1<<7);                // Настраиваем 6 и 7 выводы на выход
  while(time > 1700){ 
    if(time1 < 1300) shutter();  
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}

Еще очень много if'ов в основном цикле что можно запутаться. Можно избавиться от проверки подключена серва или нет, так как ручное управление это цикл, то до этого цикла и после код будет выполняться один раз и поэтому можно не проверять подключение сервы.

void loop()
{
  
  if (time > 1700)
  {
    servo_vert.detach();
    servo_gor.detach();
    manual_loop();
    servo_vert.attach(servo_vert_pin);
    servo_gor.attach(servo_gor_pin);
  }
  else
    auto_loop();
}

Чтобы не начаналось с автоматического цикла при объявлении переменных time и time1 присвойте им сразу значение 1900, иначе дуина еще не успевает их расчетать, а в условии они уже проверяется.

volatile unsigned int time = 1900;
volatile unsigned int time1 = 1900;

И еще по поводу shutter'а в цикле ручного управления - может происходить так, что shutter выполняется давольно продолжительное время и сервы могут из-за этого дергаться.

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

 

Maksim
Благодарю за пояснения, сделал все правки и добавил еще немного других...
Заработал старт в ручном режиме (при добавлении задержки в void loop()) и плюс добавилось прерывание автоматического режима тумблером.
Но шаттер так и не заработал - при включении тумблера пропадает питание серв и срабатывает только фокусировка на фоте и то примерно один раз из десяти щелканий тумблером... уже голову сломал почему это происходит.
 


#include <Servo.h>              
#include <multiCameraIrControl.h>

///////////////////////////////////////////////////////////////////
// Номера входов и выходов
///////////////////////////////////////////////////////////////////

int servo_gor_pin    = 7;                   // пин для сервы горизонтального поворота камеры
int servo_vert_pin   = 6;                   // пин для сервы вертикального поворота камеры

int manual_photo_pin = 3;                    //пин включающий ИК (канал AUX1 на передатчике)
int manual_pin       = 2;                    // пин включающий автоматическое/ручное управление (канал AUX2 на передатчике)

int manual_gor_pin   = 12;                   // вход сигнала с приёмника для горизонтальной сервы
int manual_vert_pin  = 11;                   // вход сигнала с приёмника для вертикальной сервы

///////////////////////////////////////////////////////////////////
// Объекты программы
///////////////////////////////////////////////////////////////////

Servo servo_gor;                            // создаём объект для контроля сервы горизонтального поворота
Servo servo_vert;                           //создаём объект для контроля сервы вертикального поворота
Nikon nex(9);                               // ИК диод для управления затвором

///////////////////////////////////////////////////////////////////
// Переменные программы
///////////////////////////////////////////////////////////////////

boolean servo_gor_go = LOW;
int posv1 = 70; //позиции вертикальной сервы
int posv2 = 100;
int posv3 = 50;
int posr = 92;
unsigned long  micros_prev = 0;      ////канал AUX2
volatile unsigned int time = 1900;
unsigned long  micros_prev1 = 0;     ////канал AUX1
volatile unsigned int time1 = 1900;

///////////////////////////////////////////////////////////////////
// Инициализация
///////////////////////////////////////////////////////////////////

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

  pinMode(servo_vert_pin, OUTPUT);
  pinMode(servo_gor_pin, OUTPUT);
  pinMode(manual_vert_pin, INPUT);
  pinMode(manual_gor_pin, INPUT);
  pinMode(manual_pin, INPUT);
  pinMode(manual_photo_pin, INPUT);
  
  servo_vert.attach(servo_vert_pin);
  servo_gor.attach(servo_gor_pin);
  
  digitalWrite(manual_pin, HIGH);        ///AUX2
  attachInterrupt(0, Mode, CHANGE);
  
  digitalWrite(manual_photo_pin, HIGH);  ////AUX1
  attachInterrupt(1, Mode1, CHANGE);
} 

void Mode()  ////чтение канала AUX2 (переключение между авто\ручным управлением)
{
  if(PIND&1<<2){
    micros_prev = micros();
  }
  else{
    time = micros() - micros_prev;
  }
}

void Mode1()    ////чтение канала AUX1 (спуск затвора)
{
  if(PIND&1<<3){
    micros_prev1 = micros();
  }
  else{
    time1 = micros() - micros_prev1;
  }
}

///////////////////////////////////////////////////////////////////
// Автоматическое управление
///////////////////////////////////////////////////////////////////

void ServoGor(boolean g)                           // функция поворота сервы горизонта
{
  int p;
  if(g==HIGH)
  {
    servo_gor_go = HIGH;
    servo_gor.attach(servo_gor_pin);               // подключаем серву горизонтальную
    for(p=1525; p<=1600; p++)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
  }
  if(g==LOW)
  {
    servo_gor_go = LOW;
    for(p=1600; p>=1525; p--)
    {
      servo_gor.writeMicroseconds(p);
      delay(3);
    }
    servo_gor.detach();                             //отключаем серву горизонтальную
  }
}

void cycle()    //панорамный цикл
{
while(time < 1700){ 
  servo_gor.write(posr);
  servo_vert.write(posv2);
  delay(800);
  shutter(); 
  delay(800);
  servo_vert.write(posv1);
  delay(800);
  shutter(); 
  delay(800);
  ServoGor(HIGH);
  delay(400);
  ServoGor(LOW);
}
}

void shutter()   // спуск затвора
{
  nex.shutterNow();
}

void auto_loop() //полный цикл автоматического управления
{ 
 
  for (int i=0;i<9;i++)
  cycle();
  if(time < 1700){
  servo_vert.write(posv3); //съемка надира
  delay(800);
  shutter(); 
  delay(800);
}
}


///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////

void manual_loop() //цикл ручного управления сервами с передатчика
{ 
  
  DDRD |= (1<<6) | (1<<7);                // Настраиваем 6 и 7 выводы на выход
  while(time > 1700){ 
    if(time1 < 1700) nex.shutterNow(); 
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}
///////////////////////////////////////////////////////////////////
// Основной цикл
///////////////////////////////////////////////////////////////////
void loop()
{ Serial.println(time);
   delay(2000);
  

   if (time > 1700)
  {
    servo_vert.detach();
    servo_gor.detach();
    manual_loop();
    servo_vert.attach(servo_vert_pin);
    servo_gor.attach(servo_gor_pin);
  }
  else 
    auto_loop();
}

 

 
 

 

trypel
trypel аватар
Offline
Зарегистрирован: 22.08.2012

Путем добавления задержки в шаттер получилось добиться срабатывания затвора, но с питанием серв все осталось как прежде...

Подтверждаются ваши слова про длительность шаттера, но он полностью перекрывает управление сервами

maksim
Offline
Зарегистрирован: 12.02.2012

Задержку delay(2000); перенесите в самый конец функции setup(), а вместо задержки после shutter() можно сделать так

///////////////////////////////////////////////////////////////////
// Ручное управление
///////////////////////////////////////////////////////////////////

void manual_loop() //цикл ручного управления сервами с передатчика
{ 

  DDRD |= (1<<6) | (1<<7);                // Настраиваем 6 и 7 выводы на выход
  boolean flag = 0;
  while(time > 1700){ 
    if(time1 < 1700){
      if(!flag){
        nex.shutterNow(); 
        flag = 1;
      }
    }
    else flag = 0;      
    PINB&1<<4?PORTD|=1<<7:PORTD&=~(1<<7); // Если на 12 выводе 1, то на 7 вывод даем 1, иначе 0
    PINB&1<<3?PORTD|=1<<6:PORTD&=~(1<<6); // Если на 11 выводе 1, то на 6 вывод даем 1, иначе 0
  }
}