Автопилот

yah
Offline
Зарегистрирован: 09.11.2013

Пишу небольшой автопилот. Возникла небольшая проблема с подергиванием серв.  Вот код:

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <Servo.h> 

//объекты серво
Servo servo_1;
Servo servo_2;

//объявление постоянных констант
static const int RXPin = 11, TXPin = 12;            //пины для serial gps
static const unsigned long GPSBaud = 9600;          //baudrate для gps
static const unsigned long COMBaud = 9600;          //baudrate для com

//объявление константных переменных финальной точки
const double fin_lat = 54.512431;	//финальные координаты LAT
const double fin_lon = 36.274083;	//финальные координаты LON

//переменные
double lat, lon;          //текущие lat, lon
double course, azimuth;   //курс, азимут
float alt, speed;         //высота, скорость
int er_com = 10;	  //переменная погрешность при сравнивании углов
int servo_pos;//текущая позиция сервы

//объекты
TinyGPSPlus gps;                     	    //новый объект для GPS
SoftwareSerial gpsSerial(RXPin, TXPin);     //программное сериал соединение для GPS

void setup()
{
  Serial.begin(COMBaud);			//открываем serial с компьютером
  gpsSerial.begin(GPSBaud);			//serial для GPS	
  
  //объекты серв
  servo_1.attach(9);
  servo_2.attach(10);
  
  //полет по прямой до получения координат GPS
  servo_1.write(90); 
  servo_2.write(90); 
  
  Serial.println("START");
  //отсылаем финальные координаты
  Serial.print("F_LAT=");  Serial.print(fin_lat, 6); Serial.print(" ");
  Serial.print("F_LON="); Serial.print(fin_lon, 6); Serial.print(" ");
  Serial.println();
}

void loop()
{
  unsigned long start = millis();
  if (gpsSerial.available() > 0)
	if (gps.encode(gpsSerial.read())){
		get_gps_info();                   //получение данных GPS
		servo_set();                      //выбор направления
	}
}//endloop


//функция получения данных по GPS
void get_gps_info()
{
  lat = gps.location.lat();         //определение LAT
  lon = gps.location.lng();         //определение LON
  alt = gps.altitude.meters();       //высота
  speed = gps.speed.kmph();          //скорость
  course = gps.course.deg();               //курс

  unsigned long date = gps.date.value();   //дата
  unsigned long time = gps.time.value();   //время

  azimuth = gps.courseTo(gps.location.lat(), gps.location.lng(), fin_lat, fin_lon);
}

//перевод серв
void servo_set(){
  //выставление серв
  if (abs(course - azimuth) <= er_com / 2){
      servo_1.write(90); 
      servo_2.write(90); 
      Serial.println("SERVO_POS=middle;"); // Отладка
  } else if (sin((azimuth - course)*PI/180.0) <= 0.0000001){
      servo_1.write(180); 
      servo_2.write(90); 
      Serial.println("SERVO_POS=left;"); // Отладка
  }else{
      servo_1.write(90); 
      servo_2.write(180); 
      Serial.println("SERVO_POS=right;"); // Отладка
  }
}

Вот видео работы:

http://www.youtube.com/watch?v=yoa7B7GMUyc

каждую секунду приходит пакет и серва дергается, почему так?

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

Все упирается в использовании программного UARTa потому как при передаче или приеме данных библиотека SoftwareSerial глобально запрещает прерывания, в результате останавливается и генерация сигнала для сервы. Выход - подключить GPS-модуль к аппаратному UARTу (Serial), то бишь к выводам 0(RX) и 1(TX).

yah
Offline
Зарегистрирован: 09.11.2013

а если использовать NewSoftSerial вместо SoftwareSerial проблема сохраниться?

или как еще можно это решить, а то очень уж нужен программый Serial

ites
Offline
Зарегистрирован: 26.12.2013

maksim пишет:

Все упирается в использовании программного UARTa потому как при передаче или приеме данных библиотека SoftwareSerial глобально запрещает прерывания, в результате останавливается и генерация сигнала для сервы. Выход - подключить GPS-модуль к аппаратному UARTу (Serial), то бишь к выводам 0(RX) и 1(TX).

Приём, насколько я вижу, там в прерывании сделан, а вот передача делает cli(), да.

yah библиотека NewSoftSerial уже является частью стандартной библиотеки ардуино, начиная с версии 1.0, насколько я могу прочитать на сайте и в гитхабе.

Один из камментов к NewSoftSerial может навести на мысль:

Mike, yeah, I’m afraid both [New]SoftSerial and the current Servo motor library use interrupts in ways that are not mutually compatible. However, if your design has two or fewer servos and you can tolerate them being fixed to certain pins, the OLD servo library (posted on this site as PWMServo) might solve your problem…

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

ites пишет:

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

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

void SoftwareSerial::recv()
{
...
  uint8_t d = 0;

  // If RX line is high, then we don't see any start bit
  // so interrupt is probably not for us
  if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
  {
    // Wait approximately 1/2 of a bit width to "center" the sample
    tunedDelay(_rx_delay_centering);
    DebugPulse(_DEBUG_PIN2, 1);

    // Read each of the 8 bits
    for (uint8_t i=0x1; i; i <<= 1)
    {
      tunedDelay(_rx_delay_intrabit);
      DebugPulse(_DEBUG_PIN2, 1);
      uint8_t noti = ~i;
      if (rx_pin_read())
        d |= i;
      else // else clause added to ensure function timing is ~balanced
        d &= noti;
    }

    // skip the stop bit
    tunedDelay(_rx_delay_stopbit);
...
inline void SoftwareSerial::tunedDelay(uint16_t delay) { 
  uint8_t tmp=0;

  asm volatile("sbiw    %0, 0x01 \n\t"
    "ldi %1, 0xFF \n\t"
    "cpi %A0, 0xFF \n\t"
    "cpc %B0, %1 \n\t"
    "brne .-10 \n\t"
    : "+r" (delay), "+a" (tmp)
    : "0" (delay)
    );
}

Так что тоже блокинг.

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

yah пишет:

или как еще можно это решить, а то очень уж нужен программый Serial

Либо писать неблокирующий программный UART на таймере, либо сервами управлять не в прерывании, а генерить ШИМ на аппаратных выводах таймера.

А вот и одно готовое решение - http://playground.arduino.cc/ComponentLib/Servotimer1, но так как подключать можно сервы только к 9 и 10 выводам, то данный вариант подходит только если у вас всего 2 сервы.

yah
Offline
Зарегистрирован: 09.11.2013

С Servotimer1 ничего не получилось выдает одни ошибки

вот нашел описание такой же ошибок http://pharos.ece.utexas.edu/wiki/index.php/Conflict_Between_Servo_and_Software_Serial_Libraries_-_02/15/2012#Solutions

но решения своей так  и не нашел

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

yah пишет:

С Servotimer1 ничего не получилось выдает одни ошибки

но решения своей так  и не нашел

Ну еще поищите...

- У меня проблема - не заводится машина
- Надо залить бензин
- Не, бензин залить не получилось - не знаю как и куда, вот у кого то тоже не заводится (ссылка),
но решения своей так и не нашел