LusoRobótica - Robótica em Português

Robótica => Projectos de robótica => Projectos em desenvolvimento => Tópico iniciado por: dvdt em 04 de Novembro de 2012, 15:25

Título: Ler PPM com Arduino
Enviado por: dvdt em 04 de Novembro de 2012, 15:25
Boas pessoal eu estou aqui com uma duvida
Estou a escrever o código para o meu novo projecto e precisava da vossa ajuda para me dizerem o que devo fazer para ler o sinal ppm do receptor rc e para os enviar novamente através do arduino, ou seja ler e inserir a mesma leitura. Sim de momento pode parecer sem sentido mas eu vou vos deixar um cheirinho de como vai funcionar.
Quando o botão do comando estiver numa posição o arduino vai enviar os sinais que esta a receber e quando estiver noutra posição vai se dirigir para waypoints
Título: Re: Novo veiculo
Enviado por: senso em 04 de Novembro de 2012, 15:29
Vai ver código dos mil e um projectos de quad-copter que existem, todos recebem dados PPM RC e 99% enviada dados PPM para os ESC's.
Título: Re: Novo veiculo
Enviado por: dvdt em 04 de Novembro de 2012, 15:47
eu estava a pensar em usar ch1=pulseIn() para obter o valor em microsegundos e depois writeMicroseconds(ch1)
Acham que resulta?
Título: Re: Novo veiculo
Enviado por: senso em 04 de Novembro de 2012, 15:52
O pulseIn é uma função bloqueante, ou seja estás a perder tempo á espera que o sinal mude de estado, a maneira mais inteligente de fazer isso é usar interrupções, todos os pinos do atmega podem gerar uma interrupção.
Título: Re: Novo veiculo
Enviado por: dvdt em 04 de Novembro de 2012, 15:55
Pois mas tenho pouca pratica com o arduino e nunca usei interropçoes
Título: Re: Ler PPM com Arduino
Enviado por: amando96 em 04 de Novembro de 2012, 16:53
Aproveita para aprender  :P literatura sobre o tema não falta.

O que tenho agora também está a usar pulsein, mas é para refazer quando houver tempo  :)
Título: Re: Ler PPM com Arduino
Enviado por: StarRider em 04 de Novembro de 2012, 19:39
Boas,

É quando se chega a estes requisitos que saltam à vista as fragilidades do "compilador" Arduino, e digo
"compilador" pois o Arduino não passa disso ... felizmente o hardware "por baixo" do Arduino (seja ele AVR
ou outro) tem sempre a possibilidade de fazer o tu queres muito facilmente.

Se decidires meter "esse tal" Arduino de lado e programar com uma verdadeira toolchain tenho aqui código
para ler PPM e PCM que podes usar sem qualquer problema.

Abraços,
PA
Título: Re: Ler PPM com Arduino
Enviado por: metRo_ em 04 de Novembro de 2012, 19:44
Se decidires meter "esse tal" Arduino de lado e programar com uma verdadeira toolchain tenho aqui código
para ler PPM e PCM que podes usar sem qualquer problema.

Abraços,
PA

ele até pode misturar as duas se tiveres a usar o avr-gcc.
Título: Re: Ler PPM com Arduino
Enviado por: dvdt em 04 de Novembro de 2012, 19:46
Mas será que alguem me podia explicar mais ao menos  como é que funciona a funçao interrupt() e como é que posso usá-la (por ex. codigo para o quad que falaram)
Título: Re: Ler PPM com Arduino
Enviado por: dvdt em 04 de Novembro de 2012, 21:06
Boas agora precisava de saber é como é que meto a função if a apanhar toda a função do gps e que variáveis vou usar  para os sinais ppm. Em baixo fica o código em já contam as variveis (ch1,ch2,ch3) bem como as inputs do recetor.
Código: [Seleccione]
#include <Servo.h>
#include <NewSoftSerial.h>
#include <TinyGPS.h> 
#include <Wire.h>
#define speedesc 125
int ch1;
int ch2;
int ch3;
int reverse=0;
int HMC6352Address = 0x42;
int slaveAddress;
byte headingData[2];
int i, headingValue;
  float flat, flon;
   float heading=0;
int headinggps;
int buzzing;
int buttonreaddone;
Servo servo;
Servo esc;
TinyGPS gps;
NewSoftSerial nss(8, 11);
#define buzzer 7
int radius;
int x4=0;
#define buttons 0
int waypoints;
int waycont=1;
float x2lat;
float x2lon;
float flat2;
float flon2;
float flat3;       
float flon3;
float flat4;
float flon4;
float flat5;
float flon5;
float flat6;
float flon6;
float flat7;
float flon7;
float flat8;
float flon8;
float flat9;
float flon9;
float flat10;
float flon10;
float flat11;
float flon11;
float flat12;
float flon12;
float flat13;
float flon13;
void gpsdump(TinyGPS &gps);
bool feedgps();
void printFloat(double f, int digits = 2);
int serv;
void setup()
{
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);
  slaveAddress = HMC6352Address >> 1; 
Wire.begin();
  Serial.begin(115200);
  nss.begin(4800);
  pinMode(buzzer, OUTPUT);
  pinMode(buttons, INPUT);
servo.attach(9);
esc.attach(10);
esc.write(90);
delay(5000);
buzz();
  ch1 = pulseIn(5, HIGH, 25000);
  ch2 = pulseIn(6, HIGH, 25000);
  ch3 = pulseIn(7, HIGH, 25000);
 
}
void loop()
{
  bool newdata = false;
  unsigned long start = millis();
  while (millis() - start < 250)
  {
    if (feedgps())
      newdata = true;
  }
 
  if (newdata)
  {
    Serial.println("Acquired Data");
    Serial.println("-------------");
    gpsdump(gps);
    Serial.println("-------------");
   Serial.println();
  }
}

void printFloat(double number, int digits)
{

  if (number < 0.0)
  {
     Serial.print('-');
     number = -number;
  }


  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;
 
  number += rounding;


  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
 Serial.print(int_part);


  if (digits > 0)
    Serial.print(".");

  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    Serial.print(toPrint);
    remainder -= toPrint;
  }
}

void gpsdump(TinyGPS &gps)
{
  long lat, lon;

  unsigned long age, date, time, chars;

  unsigned short sentences, failed;

 
  feedgps();

  gps.f_get_position(&flat, &flon, &age);
  Serial.print("Lat/Long(float): "); printFloat(flat, 7); Serial.print(", "); printFloat(flon, 7);
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
feedgps();

  gps.stats(&chars, &sentences, &failed);
  Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: "); Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
  if(buttonreaddone!=5){
    buttonread();
  }
  if(buttonreaddone==5){
distance();
  }
}
 
bool feedgps()
{
  while (nss.available())
  {
    if (gps.encode(nss.read()))
      return true;
  }
  return false;
}

void distance(){
  if(waycont==1){
 x2lat = flat2;
 x2lon = flon2;   
  }
  if(waycont==2){
    x2lat = flat3;
    x2lon = flon3;
  }
  if(waycont==3){
    x2lat = flat4;
    x2lon = flon4;
  }
  if(waycont==4){
  x2lat = flat5;
  x2lon = flon5;
  }
   if(waycont==5){
  x2lat = flat6;
  x2lon = flon6;
  }
    if(waycont==6){
  x2lat = flat7;
  x2lon = flon7;
  }
     if(waycont==7){
  x2lat = flat8;
  x2lon = flon8;
  }
     if(waycont==8){
  x2lat = flat9;
  x2lon = flon9;
  }
     if(waycont==9){
  x2lat = flat10;
  x2lon = flon10;
  }
     if(waycont==10){
  x2lat = flat11;
  x2lon = flon11;
  }
     if(waycont==11){
  x2lat = flat12;
  x2lon = flon12;
  }
     if(waycont==12){
  x2lat = flat13;
  x2lon = flon13;
  }
 

 float flat1=flat;           
 float flon1=flon;
float dist_calc=0;
float dist_calc2=0;
float diflat=0;
float diflon=0;


diflat=radians(x2lat-flat1);
flat1=radians(flat1);
x2lat=radians(x2lat);
diflon=radians((x2lon)-(flon1));

dist_calc = (sin(diflat/2.0)*sin(diflat/2.0));
dist_calc2= cos(flat1);
dist_calc2*=cos(x2lat);
dist_calc2*=sin(diflon/2.0);                                       
dist_calc2*=sin(diflon/2.0);
dist_calc +=dist_calc2;

dist_calc=(2*atan2(sqrt(dist_calc),sqrt(1.0-dist_calc)));

dist_calc*=6371000.0;
Serial.println("distance");
Serial.println(dist_calc);
if(dist_calc<radius){
while(waycont==waypoints){
  buzz();
esc.write(80);
delay(3000);
if(reverse==0){
esc.write(60);
delay(1000);
reverse=1;
}
}
waycont+=1;
}

 flon1 = radians(flon1);
 x2lon = radians(x2lon);

heading = atan2(sin(x2lon-flon1)*cos(x2lat),cos(flat1)*sin(x2lat)-sin(flat1)*cos(x2lat)*cos(x2lon-flon1)),2*3.1415926535;
heading = heading*180/3.1415926535;
int head =heading;
if(head<0){
  heading+=360;
}

Serial.println("heading:");
Serial.println(heading);


int turn=0;
 Wire.beginTransmission(slaveAddress);
  Wire.send("A");             
  Wire.endTransmission();
  delay(10);                 
  Wire.requestFrom(slaveAddress, 2);       
  i = 0;
  while(Wire.available() && i < 2)
  {
    headingData[i] = Wire.receive();
    i++;
  }
  headingValue = headingData[0]*256 + headingData[1];
 int pracheading = headingValue / 10;
 if(pracheading>0){
   headinggps=pracheading;
 }

x4=headinggps-heading;

int x5;


if(x4>=-180){
  if(x4<=0){
    turn=8;    //set turn =8 which means "right"         
  }
}
if(x4<-180){
  turn=5;      //set turn = 5 which means "left"
}
if(x4>=0){
  if(x4<180){
    turn=5;   //set turn = 5 which means "left"
  }
}
if(x4>=180){     //set turn =8 which means "right"
  turn=8;
}

//-------------------------------------------------------------DO NOT TOUCH!!!
float hd = headinggps;
if(hd==heading){
    turn=3;   //then set turn = 3 meaning go "straight"
 
}

if(turn==3){
 
  servo.write(90);  //drive straight
  esc.write(speedesc);
  delay(60);
}
//-------------------------------------------------------------------------------------turn right
if(turn==8){
rightturn();

}
//------------------------------------------------------------------------------------------turn left

if(turn==5){
leftturn();
}

 //-------------------------------------------------------------------------
}

 

void done(){
esc.write(70); 
      done();
}

void rightturn(){
if(headinggps+2>heading){
  if(headinggps-2<heading){
    servo.write(90);
    delay(60);
    return;
  }
}
 x4=headinggps-heading; 
if(x4<-180){
return;
}
if(x4>=0){
  if(x4<180){
  return;
  }
}
servo.write(80);
esc.write(speedesc);
  Wire.beginTransmission(slaveAddress);        //the wire is for the compass module
  Wire.send("A");             
  Wire.endTransmission();
  delay(10);                 
  Wire.requestFrom(slaveAddress, 2);       
  i = 0;
  while(Wire.available() && i < 2)
  {
    headingData[i] = Wire.receive();
    i++;
  }
  headingValue = headingData[0]*256 + headingData[1]; 
headinggps = headingValue / 10;      // this is the heading of the compass
rightturn();
}


//----------------------------------------------left turning
void leftturn(){
  if(headinggps+4>heading){
  if(headinggps-4<heading){
  servo.write(90);
    delay(60);
    return;
  }
}
x4=headinggps-heading; 
if(x4>=-180){
  if(x4<=0){
     return;         
  }
}

if(x4>=180){     
  return;
}
servo.write(110);  // turn wheels left
esc.write(speedesc);

  Wire.beginTransmission(slaveAddress);        //the wire is for the compass module
  Wire.send("A");             
  Wire.endTransmission();
  delay(10);                 
  Wire.requestFrom(slaveAddress, 2);       
  i = 0;
  while(Wire.available() && i < 2)
  {
    headingData[i] = Wire.receive();
    i++;
  }
headingValue = headingData[0]*256 + headingData[1]; 
headinggps = headingValue / 10;      // this is the heading of the compass
leftturn();
}


void buttonread(){
  int butval= analogRead(buttons);
  if(waypoints>0){
  if(butval<100){
    buttonreaddone=5;
        buzz();
      return;
  }
  }
  if(waypoints==0){
    if(butval<100){
      radius+=1;
    buzz();
      return;
    }
  }
      if(butval>600){
     if(waypoints==0){
      flat2=flat;
      flon2=flon;
      waypoints+=1;
         buzz();
      return;
     }
         if(waypoints==1){
      flat3=flat;
      flon3=flon;
      waypoints+=1;
       buzz();
      return;
     }
         if(waypoints==2){
      flat4=flat;
      flon4=flon;
      waypoints+=1;
        buzz();
      return;
     }
         if(waypoints==3){
      flat5=flat;
      flon5=flon;
      waypoints+=1;
        buzz();
      return;
     }
         if(waypoints==4){
      flat6=flat;
      flon6=flon;
      waypoints+=1;
     buzz();
      return;
     }
         if(waypoints==5){
      flat7=flat;
      flon7=flon;
      waypoints+=1;
       buzz();
      return;
     }
          if(waypoints==6){
      flat8=flat;
      flon8=flon;
      waypoints+=1;
         buzz();
      return;
     }
          if(waypoints==7){
      flat9=flat;
      flon9=flon;
      waypoints+=1;
        buzz();
      return;
     }
          if(waypoints==8){
      flat10=flat;
      flon10=flon;
      waypoints+=1;
       buzz();
      return;
     }
          if(waypoints==9){
      flat11=flat;
      flon11=flon;
      waypoints+=1;
     buzz();
      return;
     }
          if(waypoints==10){
      flat12=flat;
      flon12=flon;
      waypoints+=1;
        buzz();
      return;
     }
          if(waypoints==11){
      flat13=flat;
      flon13=flon;
      waypoints+=1;
    buzz();
      return;
     }
       
     }

}
void buzz(){
    while(buzzing<500){
        digitalWrite(buzzer, HIGH);
        delayMicroseconds(250);
        digitalWrite(buzzer, LOW);
        delayMicroseconds(250);
        buzzing++;
      }
      delay(100);
      buzzing=0;
}
Título: Re: Ler PPM com Arduino
Enviado por: senso em 05 de Novembro de 2012, 01:04
Precisas mesmo desses floats todos?
Sabes usar arrays, visto a maneira como estás a usar os floats podias usar um simples array, tornava o código muito mais limpo e legivel.
Título: Re: Ler PPM com Arduino
Enviado por: dvdt em 05 de Novembro de 2012, 08:19
Pois mas foi assim que me explicaram :-[ e nao sei como é que se usa o array
Título: Re: Ler PPM com Arduino
Enviado por: StarRider em 05 de Novembro de 2012, 14:19
Boas,

Pois, com todos esses float(s) e cálculos de virgula flutuante e AVR deve estar de rastos ;)

Basicamente necessitas de um timer e um input capture para ler PPM, não te vou poder ajudar em termos
de Arduino, mas posso tentar ajudar a implementar código usando o AVR se estiveres interessado.

Diz-me uma coisa, o sinal PPM que vai ler vem de um receptor RC ?

Abraços,
PA
Título: Re: Ler PPM com Arduino
Enviado por: senso em 05 de Novembro de 2012, 19:16
O IDE do Arduino tem o compilador avr-gcc assim como o avrdude e mais umas coisas lá, é simplesmente um avr-gcc a correr, e todo o código abaixo das funções bonitas é simplesmente código avr, não percebo porque raio dizem que arduino é uma linguagem de programação -.-
Título: Re: Ler PPM com Arduino
Enviado por: dropes em 05 de Novembro de 2012, 19:56
A instrução "case" também facilita em vez de se colocar "if" em grande parte do código:

if(waycont==1)...if(waycont==12)
if(waypoints==1)...if(waypoints==12)

Código: [Seleccione]
switch (expressions)
{
case constant expressions
}

For example:

switch (i/10)
{
case 0: printf ("Number less than 10"); // A
break;
case 1: printf ("Number less than 20"); // B
break;
case 2: printf ("Number less than 30"); // C
break;
default: printf ("Number greater than or equal to 40"); // D
break; }

Tens razão Senso, assim como AVR nativo não é uma linguagem mas sim assember.
Título: Re: Ler PPM com Arduino
Enviado por: dvdt em 05 de Novembro de 2012, 19:56
sim é sinal proveniente de um receptor ;D ou seja 3 ch um para usar para activar/desactivar o gps e os canais para para controlar o dito veiculo quando o gps esta desligado
Título: Re: Ler PPM com Arduino
Enviado por: StarRider em 05 de Novembro de 2012, 21:14
O IDE do Arduino tem o compilador avr-gcc assim como o avrdude e mais umas coisas lá, é simplesmente um avr-gcc a correr, e todo o código abaixo das funções bonitas é simplesmente código avr, não percebo porque raio dizem que arduino é uma linguagem de programação -.-

"linguagem de programação" ... onde é que isso foi dito ?
Título: Re: Ler PPM com Arduino
Enviado por: StarRider em 05 de Novembro de 2012, 21:48
sim é sinal proveniente de um receptor ;D ou seja 3 ch um para usar para activar/desactivar o gps e os canais para para controlar o dito veiculo quando o gps esta desligado

Boas,

Se vais obter o sinal a partir do receptor temos aqui duas situações possíveis:
- Obter os canais a partir da saída PPM do receptor, são poucos os receptores que oferecem
uma saída com PPM, podes sempre ir buscar o sinal ao circuito do receptor mas tens que saber
onde ele anda e implica "bricolage". Depois temos ainda que alguns receptores são PCM, e dentro
destes a codificação PCM varia entre marcas (Futaba/Robbe vs Graupner/JR).
- Obter os canais a partir das saídas PWM do receptor, simples, rápido e universal, mas necessita
de um pino IO do AVR por canal que desejes utilizar.

Depois temos ainda ainda a forma como vais "controlar"  o veiculo, se directamente usando
também PWM (que é o que os servos e ESCs  entendem), ou se vais re-direccionar os canais
para um outro qualquer desmodelador, sendo que a ser assim vais ter que implementar rotinas
para fazer o encoding dos canais.

"Descomplicando", o mais simples é ler os canais directamente das saídas PWM do receptor (esquece o PPM)
e controlar os servos/motores do veiculo usando o PWM gerado pelo AVR.
Ficam assim com a possibilidade de ler até 8 canais, e usar essa mesma informação para controlar tudo.

Que dizes ?

Não percebi bem o que queres dizer por "ligar/desligar" o GPS. Queres dizer cortar fisicamente a alimentação
ao mesmo ?

Abraços,
PA
Título: Re: Ler PPM com Arduino
Enviado por: dvdt em 05 de Novembro de 2012, 22:22
Pois talvez pwm seja mais fácil. ;)
Vamos começar do inicio
   Tudo vai assentar num veiculo terrestre de pequenas dimensões mas com capacidades de andar em qualquer terreno. Dentro deste veiculo quero incluir  um arduino, GPS, bússola, receptor e controlador para os motores.
Usando então um canal do meu comando que poder activar/desactivar a função GPS que estará introduzida no arduino para que este ora fico sobre o meu controlo usando os outros dois ch ora entre em modo autónomo e se desloque para para localizações especificas (waypoints).
   O controlador de motores que eu estou a usar pode ser ora controlado por serial ou pwm ou seja penso que seja mais fácil pwm tendo em conta que são só dois canais. Espero ter esclarecido todas as duvidas mais alguma questão estou à ordem. ;D