LusoRobótica - Robótica em Português
Sistemas específicos => Arduino / AVR => Tópico iniciado por: msr em 19 de Dezembro de 2009, 23:59
-
Boas pessoal,
Estou aqui a pensar como hei de fazer um protocolo via porta Serial.
A minha ideia base seria enviar as seguintes intruções:
- ligar e desligar um LED
- posição exacta de um Servo
Estava a pensar num "protocolo" desde género:
"L ON" - led acende
"L OFF" - led apaga
"S 67" - posicao do servo = 67 graus
O problema aparece precisamente no envio da posição do servo. Para sacar aquele inteiro parece-me que são precisas umas quantas maroscas.
Encontrei um post que fala sobre isto e estava a pensar seguir qualquer coisa como a que o "todbot" refere no final do post:
http://todbot.com/blog/2009/07/30/arduino-serial-protocol-design-patterns/ (http://todbot.com/blog/2009/07/30/arduino-serial-protocol-design-patterns/)
Mas gostava de vos pergunta se conhecem alguma coisa que facilite aquilo que pretendo fazer?
-
O objectivo é comunicar o que com que? PC com micro? que micro?
Eu digo isto porque por exemplo se fores utilizar um Arduino não me parece nada complicado e eu ainda há pouco fiz uma coisa parecida. Recebia uma trama do género no Arduino vinda do PC: :p132421& e foi relativamente simples de implementar.
-
Não percebo... a comunicação vai ser orientada a caracteres é?
é que um send de um caracter tem um byte, 256 combinações.
Um servo se for com o analogWrite vai de 0 a 256, se for com uma servo lib vai de 0 a 180º pelo que qualquer das duas podem ser enviadas com um caracter apenas.
-
É mesmo com o Arduino. PC->Arduino. Se pudesses partilhar o código era nice.
A ideia é fazer o "parse" de uma linha de comando.
TigPT, tambem já pensei nisso. Até podia aproveitar os 8bits do byte e fazer o protocolo a partir daí, certo? Mas, para "debug", estou a usar a consola serial do IDE do Arduino que converte tudo o que digitas para caracteres. Daí a comunicação orientada a caracteres.
Edit:
Para fazer uma comunicação orientada ao byte era um bocado manhoso acho. Primeiro preciso saber a que é que se refere a instrução, se ao LED se ao servo. No LED só existe a opção "acende" ou "apaga" no entanto para o Servo queria ter duas opções: move para a esquerda, para a direita ou para uma determinada posição em concreto. Portanto teria mesmo que fazer a comunicação "orientada ao bit" e neste momento, para isso, acho que me faltam alguns skills em C# ou C++ ;D
-
N tinhas feito código para isso em C#?
http://lusorobotica.com/index.php/topic,1755.msg16892.html#msg16892 (http://lusorobotica.com/index.php/topic,1755.msg16892.html#msg16892)
um simples programa em C# fazia logo isso td.
-
Certo.
Mas o que esse programa faz é enviar uma string. Faz o mesmo que a consola do IDE do Arduino.
-
basta metere um campo para enviar posição de servo em k escreves a string, o programa faz Integer.ParseInt da string e se for menos k 256 (para proteger) manda o caracter com esse valor, ou seja send da variável.
-
#include <stdlib.h>
#define DATAOUT 11//MOSI
#define DATAIN 12//MISO - nao e' usado
#define SPICLOCK 13//sck
#define SLAVESELECT 10//SS1
#define SLAVESELECT1 9//SS2
byte pot0_0=17,pot0_1=18,pot1_0=17,pot1_1=18;
byte clr;
char spi_transfer(volatile char data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
{
};
return SPDR; // return the received byte
}
int incomingByte = 0;
uint8_t start=0;
uint8_t pid=0;
uint8_t conta=0;
char message[8] = "";
char valorpid[6];
double p,i,d,t=0;
long Rp,Ri,Rd=0;
void setup(){
//SPI
pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK,OUTPUT);
pinMode(SLAVESELECT,OUTPUT);
pinMode(SLAVESELECT1,OUTPUT);
digitalWrite(SLAVESELECT,HIGH);
digitalWrite(SLAVESELECT1,HIGH);
SPCR = (1<<SPE)|(1<<MSTR);
clr=SPSR;
clr=SPDR;
delay(10);
//Serial
Serial.begin(115200);
Serial.print(0x0C, BYTE);
}
byte write_pot0(int address, int value){
digitalWrite(SLAVESELECT,LOW);
spi_transfer(address);
spi_transfer(value);
digitalWrite(SLAVESELECT,HIGH);
delay(10);
}
byte write_pot1(int address, int value){
digitalWrite(SLAVESELECT1,LOW);
spi_transfer(address);
spi_transfer(value);
digitalWrite(SLAVESELECT1,HIGH);
delay(10);
}
int res2pot(long res){
double pot =((res-125)/(330));
if(pot < 0){pot=0;};
if(pot > 255){pot=255;}
return pot;
}
void loop(){
Serial.print(0x0C, BYTE);
Serial.print("P:");
Serial.println(p,DEC);
Serial.print(" Rp:");
Serial.println(Rp,DEC);
Serial.print("I:");
Serial.println(i,DEC);
Serial.print(" Ri:");
Serial.println(Ri,DEC);
Serial.print("D:");
Serial.println(d,DEC);
Serial.print(" Rd:");
Serial.println(Rd,DEC);
delay(100);
if (Serial.available() > 0) {
incomingByte = Serial.read();
if(incomingByte == 0x3A & !start & !conta){
message[conta]=incomingByte;
conta++;
start=1;
}else if(start & !pid & ((incomingByte == (0x70))|(incomingByte == (0x69))|(incomingByte == (0x64))) & (conta==1)){
message[conta]=incomingByte;
conta++;
pid=1;
}else if(start & pid){
if(!(incomingByte == 38) & (incomingByte>=0x30) & (incomingByte<=0x39) & (conta<8)){
message[conta]=incomingByte;
conta++;
}else if(incomingByte == 0x26 & (conta==8)){
message[conta]=incomingByte;
conta++;
for(int h=2;h<8;h++){
valorpid[h-2]=message[h];
}
switch (message[1]) {
case 0x70:
p=(atof(valorpid))/1000;
Rp=p*10000;
write_pot0(pot0_0,res2pot(Rp));
break;
case 0x69:
i=(atof(valorpid))/1000;
t=1/(0.0000022*i);
Ri=long(t);
write_pot1(pot1_0,res2pot(Ri));
break;
case 0x64:
d=(atof(valorpid))/1000;
t=d/0.0000022;
Rd=long(t);
write_pot1(pot1_1,res2pot(Rd));
break;
}
start=0;
pid=0;
conta=0;
}else if(1){
start=0;
pid=0;
conta=0;
}
}else if(1){
start=0;
pid=0;
conta=0;
}
}
}
Aqui tens o código de todo o projecto que consistia em receber a trama e alterar os valores de uns potenciómetros digitais por SPI. Os potenciómetros digitais seriam para acertar as constantes de um controlador PID analógico.
A parte do código que te interessa é onde começa o if (Serial.available() > 0) {. Eu no meu caso tratei de evitar receber coisas mal por isso faço algumas confirmações ao que recebo.
-
controlador PID analógico.
Que coisa bonita!
Bem acho que já pus isto a funcionar.
Estou a usar este código:
memset(cmdbuf,'\0',sizeof(cmdbuf));
while(Serial.available()){
delay(10);
if(i != CODE_BUF)
cmdbuf[i++] = Serial.read();
else
break;
}
Mas ainda tenho que ver melhor. Aquele delay é para garantir que já lá chegaram os bytes todos. Coisa que ha pouco nao acontecia e daí estar a obter resultados inesperados.
Quando tiver tudo feito dou notícias.
-
Não percebi muito bem mas deve ser :p