LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: almamater em 04 de Agosto de 2010, 00:28

Título: Arduino SerialPort
Enviado por: almamater em 04 de Agosto de 2010, 00:28
Hello!

Estou a programar uma pequena aplicação em VB para se conectar ao arduino e obter informação da eeprom, consigo que funcione mas tenho um problema..

Só consigo obter resposta do Arduino (mesmo com a ligação série efectuada / open) se fizer Reset manual nele, isto apenas acontece qdo antes ele foi utilizado tb por um serial monitor como o que vem no software de upload do Arduino...

A minha questão é, pq é que ao ligar o Serial Monitor da aplicação do Arduino ele faz Auto-Reset e através da minha aplicação ele não o faz, se fizesse ia ficar com este problema resolvido..

Estou a usar:

       clsSerial.BaudRate = 9600
        clsSerial.DataBits = 8
        clsSerial.Parity = 0
        clsSerial.StopBits = 1
        clsSerial.GetPorts()
        clsSerial.PortNumber = 6

Há alguma forma de "forçar" o reset ao arduino durante esta ligação?

Se ligar o Arduino e utilizar logo a minha aplicação funciona bem, mas se usar antes a porta série dele a seguir já me acontece o que referi  :-[
Título: Re: Arduino SerialPort
Enviado por: Marvin em 04 de Agosto de 2010, 09:05
Bom dia,

VB .net ou VB6?

Penso que esse problema pode ser devido a teres a ligação da porta de serie já aberta, terias de verificar se já existe uma ligação aberta e fecha-la manualmente (não sei se é possivel).

Acho que quando fazes um reset, fechas as ligações com a porta de serie actuais e abres as novas ligações, dai ele funcionar nessa altura.



Título: Re: Arduino SerialPort
Enviado por: almamater em 04 de Agosto de 2010, 10:25
Bom dia,

VB .net ou VB6?

Penso que esse problema pode ser devido a teres a ligação da porta de serie já aberta, terias de verificar se já existe uma ligação aberta e fecha-la manualmente (não sei se é possivel).

Acho que quando fazes um reset, fechas as ligações com a porta de serie actuais e abres as novas ligações, dai ele funcionar nessa altura.

Vb .net 2008 e 2010, pois deve ser isso.. já tentei encontrar alguma opção para forçar o fecho das ligações da COM do arduino mas sem resultados.. grr foi um filme para perceber o envio/recepção para o arduino e consegui, agora reparei neste pormenor!


Título: Re: Arduino SerialPort
Enviado por: Marvin em 04 de Agosto de 2010, 11:11
Se perceberes de C# posso-te enviar o que uso para a comunicação. Sendo .net podes inclusive colocar como um projecto em paralelo na solução.
Título: Re: Arduino SerialPort
Enviado por: almamater em 04 de Agosto de 2010, 11:15
Se perceberes de C# posso-te enviar o que uso para a comunicação. Sendo .net podes inclusive colocar como um projecto em paralelo na solução.

OK, gracias! pode ser que resolva o meu problema! podes enviar para aqui (almamater@mail.telepac.pt) sff
Título: Re: Arduino SerialPort
Enviado por: msr em 04 de Agosto de 2010, 11:51
Dá uma vista de olhos aqui também: http://bravomofo.blogspot.com/2010/03/serial-talk.html (http://bravomofo.blogspot.com/2010/03/serial-talk.html)

Comigo funcionou sem problemas até ao momento.
Título: Re: Arduino SerialPort
Enviado por: almamater em 04 de Agosto de 2010, 12:16
humm estranho, estava a testar agora a mesma coisa mas num Computador com Windows XP e funciona tudo bem  :o, estabelecendo ligação com a minha aplicação em VB o Arduino faz reset.. coisa que em Windows 7 não faz.. será dos drivers FTDI?
Título: Re: Arduino SerialPort
Enviado por: almamater em 04 de Agosto de 2010, 16:42
Bom.. outra dúvida.. a questão anterior tem de se resolver com um Reset ao Arduino sempre que acontece.

Agora estou com outra situação, como é que posso enviar o valor por exemplo  "155" e o Arduino não ler linha a linha:

1
5
5

mas sim um valor inteiro 155 ?  ::)

A função que estou a usar em VB para o envio é:
Código: [Seleccione]
Dim WithEvents serialPort As New IO.Ports.SerialPort

  Public Function Send(ByVal txtMsg As String) As Boolean
        Try
            txtMsg += vbCrLf
            serialPort.Write(txtMsg)
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
-----------------------------------

Private WithEvents clsSerial As New Serial

'ENVIO:

clsSerial.Send("155")


Título: Re: Arduino SerialPort
Enviado por: senso em 04 de Agosto de 2010, 22:42
Tens que usar a função atoi, que converte ASCII ou seja strings em inteiros.
Para usares essa função tens de passar a string a usar, não sei como lhe chamas no teu programa, portanto imaginemos que se chama String_recebida, para converteres para um int fazes o seguinte no teu programa:
Código: [Seleccione]
meu_inteiro =  atoi(String_recebida);
Título: Re: Arduino SerialPort
Enviado por: almamater em 05 de Agosto de 2010, 01:35
Bom.. tentei de diversas formas implementar isso no programa do arduino mas sem sucesso.. algo me está a escapar  :-\


Peguei no exemplo do site do arduino para tentar perceber:
Código: [Seleccione]
int incomingByte = 0; // for incoming serial data

void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}

void loop() {

// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();

// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
               }
             }

Enviado para o Arduino o valor "255" ele recebe isto (http://img535.imageshack.us/img535/3969/001ejg.png):

I received: 50
I received: 53
I received: 53


Ok, apresenta segundo a tabela Aschii, colocando a função atoi "int meu_inteiro =  atoi(incomingByte);" tenho um erro:

error: invalid conversion from 'int' to 'const char*

Já pesquisei e já testei definir com
Código: [Seleccione]
char* incomingByte [0];
mas nunca dá!


é que eu precisava mesmo de obter o valor certo definido, pq quero guardar na eeprom várias varáveis e cada uma delas vai ter um valor de 0 a 255 recebido pela porta série, como o Arduino recebe linha a linha tenho possivelmente de fazer um ciclo para juntar as leituras todas para me fazer 1 número: 255 em vez de 3 números: 2, 5, 5



Título: Re: Arduino SerialPort
Enviado por: Cynary em 05 de Agosto de 2010, 03:42
Não estás a perceber ... o problema não está no arduino :P
Tens de converter de string para inteiro ... ou melhor provavelmente não precisas de fazer isso, se, como argumento da função send, em vez de uma string, aceitares um inteiro, e o enviares.
Assim, quando fazes:
Código: [Seleccione]
clsSerial.Send(155)(nota a falta de aspas), envias o INTEIRO (que será o carácter de acordo com a tabela ASCII :P).
Ou então, dentro da função, usas o atoi.
Usando síntaxe de C (não gosto do de VB xD e não estou habituado), a tua função seria uma coisa assim:
Código: (c) [Seleccione]
  int Send(int intMsg) {
  return serialPort.Write((char)intMsg); } // Considerando que retorna falso quando falha e vice-versa.

No entanto, isto tem a desvantagem de aceitar apenas números entre 0 e 255, já que o arduino recebe byte a byte ... a outra opção, é alterar o código do arduino de forma a que ele receba cada dígito do número, e os transforme em inteiros (postei há pouco tempo uma função que faz isso! xD).
Vê este tópico: http://lusorobotica.com/index.php?topic=2633.0 (http://lusorobotica.com/index.php?topic=2633.0)
Apenas tens de enviar um carácter para o arduino saber que tem de parar de ler o número :P, usando a função getnumber()
Título: Re: Arduino SerialPort
Enviado por: almamater em 05 de Agosto de 2010, 10:53
Obrigado pela explicação.

Neste caso enviado o 255 dá o seguinte:

(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fimg827.imageshack.us%2Fimg827%2F2125%2F001wj.th.png&hash=e0fd2f9c9fd24980aaf4c4894343adb8faacddf1) (http://img827.imageshack.us/i/001wj.png/)

Está certo assim não está?
Título: Re: Arduino SerialPort
Enviado por: TigPT em 05 de Agosto de 2010, 11:42
O metRo_ uma vez andou a pedir-me ajuda num código para exactamente isso.

O cliente que está a receber o serial tem que processar a informação, já que a transmissão serial é sempre byte a byte

Das duas uma. Ou fazes um software para quem está a enviar os dados, que converte o número que colocas na letra ascii com esse valor, e podes mandar valores de 0 a 256 (equivalente a 1 byte de comunicação), ou quem recebe os dados, sabe que vai receber vários números ascii e vai multiplicado por 10 para shiftar de forma decimal até obter um caracter terminador, ou x bytes pré configurados.
Título: Re: Arduino SerialPort
Enviado por: almamater em 06 de Agosto de 2010, 01:58
Ok, podem chamar-me burro  :-X

Tenho 3 processos que podem ser executados de acordo com o que é recebido via serial.read, tenho tudo a funcionar menos a parte de receber o valor inteiro e por inteiro

Em VB tenho as seguintes funções:
Código: [Seleccione]

                                Envia Strings:
  Public Function Send(ByVal txtMsg As String) As Boolean
        Try

          ' // txtMsg += vbCrLf
            serialPort.Write(txtMsg)
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

                             Para enviar o valor Inteiro (já testei as Byte e as Integer):

    Public Function Send2(ByVal txtMsg2 As Byte) As Boolean
        Try
            serialPort.Write(txtMsg2)
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function


No lado do Arduino tenho:

Código: [Seleccione]
   
byte com;            //lê string recebido
byte Posicao;       //saber a posição na eeprom
byte ValorExtra;   //para gravar valor na eeprom

int ValorEeprom;  //para ler valor de eeprom


void loop()
{

  if (Serial.available() > 0)
  {

com = Serial.read();
  delay(50);   
 
  if (com== 103){     //se receber a letra "g"
  Posicao= Serial.read();     
  delay(50);   
  ValorExtra= Serial.read();
   delay(50);   
     }


 if (com== 103){                       // letra "g"     
   
   if (Posicao== 97){                  // letra "a"
   EEPROM.write(0,ValorExtra);
      Serial.print("VALOR 1 GUARDADO: ");
   Serial.println(EEPROM.read(0));
   delay(100);
 
   }
     if (Posicao== 98) { // letra "b"
   EEPROM.write(1,ValorExtra);
      Serial.print("VALOR 2 GUARDADO: ");
   Serial.println(EEPROM.read(1));
   delay(100);
   }

etc.


Ou seja, o "g" representa a condição para gravar na eeprom e dentro desta tenho vários IFs que identificam a posição pretendida..

No meu programa em VB estou a fazer assim:


Código: [Seleccione]
clsSerial.Send("ga")                  '//Usa a função SEND para enviar as letras "g" e "a"           [ciclo gravar e na posição/IF  'a']
clsSerial.Send2(145)      '//Usa a função SEND2 para enviar o valor a gravar na eeprom que pode ser de 0-255
   

O arduino de facto detecta o "g", detecta o "a" mas quando vai a gravar na eeprom grava apenas o número correspondente em ascii do 1º digito que recebeu, neste caso do 1 e grava o valor 49 em vez do 145

-----------------

Estive o dia todo a inventar e alterar coisas e juro que já tinha conseguido receber o valor por inteiro de uma só vez.. mas sinceramente já dei tanta volta que me baralhei e tou assim neste momento.

Título: Re: Arduino SerialPort
Enviado por: senso em 06 de Agosto de 2010, 02:14
Mas a função atoi faz isso e devia funcionar devidamente..
Lê sobre ela.
Título: Re: Arduino SerialPort
Enviado por: Cynary em 06 de Agosto de 2010, 04:36
Hum, isso devia ter funcionado ... só se houver algum problema com a forma como a função Serial.write está a processar o número :S E em vez de o processar como um valor de um byte, transforma numa string (o que, sinceramente, acho uma grande estupidez xD).
De qualquer forma, aconselho-te então a usar ou a função que te mostrei: http://lusorobotica.com/index.php?topic=2633.0 (http://lusorobotica.com/index.php?topic=2633.0)
Ou então, guarda o número numa string, e usa o atoi (vai dar ao mesmo xD). De qualquer forma, tens de enviar um carácter de fim de número.
Por exemplo, alterar o código que mostraste, de forma a mandar um número, terminado de S (ps: não precisas de dois if(comm==103), por isso tomei a liberdade de tirar o segundo :P):

Código: (vb) [Seleccione]
  Public Function Send(ByVal txtMsg As String) As Boolean
        Try

          ' // txtMsg += vbCrLf
            serialPort.Write(txtMsg)
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

Código: (c) [Seleccione]
   
byte com;            //lê string recebido
byte Posicao;       //saber a posição na eeprom
byte ValorExtra;   //para gravar valor na eeprom

int ValorEeprom;  //para ler valor de eeprom


void loop()
{

  if (Serial.available() > 0)
  {

com = Serial.read();
  delay(50);   
 
  if (com== 103){     //se receber a letra "g"
  Posicao= Serial.read();     
  delay(50);   
  ValorExtra= Serial.read();
   delay(50);   
     }


 if (com== 103){                       // letra "g"     
   
   if (Posicao== 97){                  // letra "a"
   EEPROM.write(0,ValorExtra);
      Serial.print("VALOR 1 GUARDADO: ");
   Serial.println(EEPROM.read(0));
   delay(100);
 
   }
     if (Posicao== 98) { // letra "b"
   EEPROM.write(1,ValorExtra);
      Serial.print("VALOR 2 GUARDADO: ");
   Serial.println(EEPROM.read(1));
   delay(100);
   }

etc.
long getnumber(char stop_character) {
  int cs;
  long i = 0;
  while(1) {
    while(!Serial.available())
      delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
    cs = Serial.read();
    if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
    if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
    i *= 10;
    i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
  return i; }
Código: (vb) [Seleccione]
clsSerial.Send("ga145S")                  '//Usa a função SEND para enviar as letras "g" e "a"           [ciclo gravar e na posição/IF  'a'] e o número 145 (letra S usada para terminar o número)
Atenção, como a variável usada para guardar o número recebido é um byte, só suporta entre 0 e 255, apesar de poderes enviar números maiores para a função getnumber, apenas os primeiros 8 bits serão usados.

Prefiro usar uma função como a que mostrei aqui, em vez do atoi, pois o atoi obrigaria a usar processamento e armazenamento extra: receber a string por serial, guardá-la, e depois passá-la para o atoi processá-la carácter a carácter. Assim, processamos cada byte do serial logo.

Ou fazes isto, ou então fazes o que provavelmente é o melhor: estuda melhor o VB, e vê se percebes porque é que o teu byte 145 está a ser convertido para uma string, e como podes evitar isso. Ou então muda de linguagem :P, para uma em que isso não acontece sem tu saberes ...
Título: Re: Arduino SerialPort
Enviado por: almamater em 06 de Agosto de 2010, 19:14
Humm ok! Tenho pensar adoptar o C# / c.net  ;D

Obrigado pela paciência antes de mais!

Acho que não foram publicadas as alterações referidas na parte do com= serial.read (), tenho apenas de colocar desta forma com = getnumber('S'); certo?
Código: [Seleccione]
void loop()
{   
com = getnumber('S');
  delay(50);   
 
  if (com== 103){
  Posicao= Serial.read();
  delay(50);   
  ValorExtra= Serial.read();
     }
   
 

           
     //GRAVAR VALORES EEPROM:   
   
   if (Posicao== 97){                  // letra "a"
   EEPROM.write(0,ValorExtra);
      Serial.print("VALOR 1 GUARDADO: ");
   Serial.println(EEPROM.read(0));
   delay(100);
 
   }
     if (Posicao== 98) { // letra "b"
   EEPROM.write(1,ValorExtra);
      Serial.print("VALOR 2 GUARDADO: ");
   Serial.println(EEPROM.read(1));
   delay(100);
   }

etc

}

long getnumber(char stop_character) {
  int cs;
  long i = 0;
  while(1) {
    while(!Serial.available())
      delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
    cs = Serial.read();
    if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
    if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
    i *= 10;
    i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
  return i; }
Título: Re: Arduino SerialPort
Enviado por: Cynary em 06 de Agosto de 2010, 20:10
Humm ok! Tenho pensar adoptar o C# / c.net  ;D

Obrigado pela paciência antes de mais!

Acho que não foram publicadas as alterações referidas na parte do com= serial.read (), tenho apenas de colocar desta forma com = getnumber('S'); certo?
Código: [Seleccione]
void loop()
{   
com = getnumber('S');
  delay(50);   
 
  if (com== 103){
  Posicao= Serial.read();
  delay(50);   
  ValorExtra= Serial.read();
     }
   
 

           
     //GRAVAR VALORES EEPROM:   
   
   if (Posicao== 97){                  // letra "a"
   EEPROM.write(0,ValorExtra);
      Serial.print("VALOR 1 GUARDADO: ");
   Serial.println(EEPROM.read(0));
   delay(100);
 
   }
     if (Posicao== 98) { // letra "b"
   EEPROM.write(1,ValorExtra);
      Serial.print("VALOR 2 GUARDADO: ");
   Serial.println(EEPROM.read(1));
   delay(100);
   }

etc

}

long getnumber(char stop_character) {
  int cs;
  long i = 0;
  while(1) {
    while(!Serial.available())
      delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
    cs = Serial.read();
    if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
    if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
    i *= 10;
    i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
  return i; }

Não alteres o que disseste que alteravas xD
O com serve para receberes letras, ou seja, lê carácter a carácter do serial, normalmente. O getnumber('S') lê todos os dígitos do serial (ignorando assim as letras 'g' e 'a'), até chegar à letra 'S'. Logo, tens inicialmente de ler o 'g' (para saberes que vais receber o número) e o 'a' (para saberes onde guardar) através do serial.read(). Depois é que lês o número :P

PS: Não conheço o C# por isso não posso comentar. No entanto, recomendaria que tentasses aprender uma linguagem diferente e universal (no sentido de ser suportada por vários sistemas operativos), como python, perl, C/C++ ou java (recomendo mais o C/C++, pois se vais fazer projectos com o arduino, ou mesmo outros microcontroladores, provavelmente vais usar essa linguagem, por isso é importante que compreendas bem o seu sintaxe/funcionalidade).
Título: Re: Arduino SerialPort
Enviado por: almamater em 07 de Agosto de 2010, 17:40
 :D

Muito obrigado a todos pela ajuda! em especial ao Cynary que nesta fase final não estava mesmo a perceber o porquê de não chegar um inteiro ao Arduino mas com a função Getnumber é uma maravilha!!  ;)

Obrigado!
Título: Re: Arduino SerialPort
Enviado por: almamater em 14 de Abril de 2011, 12:18
Bom, aproveitando este tópico pq o assunto é o mesmo.. e fui eu que o criei  :P



Estive ontem a testar a ligação com o Arduino em VB .net com o Firmata e funcionou bem, a ligação é estabelecida sem problemas e fica logo 'sincronizado'  com a aplicação, com os exemplos que disponibilizam (http://firmata.org/wiki/Main_Page (http://firmata.org/wiki/Main_Page)) consigo ligar/desligar os pinos e obter valores analógicos.

Eu estava a pensar em monitorizar sensores (temperatura / distância / etc) numa aplicação, acho que a melhor forma é o Arduino obter o valor do sensor e calcular o resultado e enviar o mesmo para a aplicação (serial).. com o Firmata não percebi ainda muito bem como enviar/receber strings..

Como costumam fazer? a minha alternativa ao Firmata é estabelecer uma ligação série normal e ler/filtrar tudo o que chega vindo do Arduino..