Projeto

Geral

Perfil

Comunicação » Histórico » Revisão 2

Revisão 1 (Renan Pícoli, 08/03/2017 22:14 h) → Revisão 2/4 (Renan Pícoli, 08/03/2017 22:17 h)

h1. Comunicação 

 h2. 1. FIRMWARE 

 
 Em main.cpp há três objetos maiores (mais complexos): um da classe Robo, um da classe USB_STM32 (usb) e outro da classe NRF24L01P (declarados em radio/bsp.h e instanciados em src/bsp.cpp) 
 Além do objeto auxiliar _usbserialbuffer, um buffer circular de uint8_t 
 OBS: quando a classe Robo é instanciada em bsp.cpp, pode-se escolher um modo de teste, no qual apenas a serial (e a linha de comando acessada pelo Tera Term) é usada. 

 h3. 
 1.1 CLASSE NR24L01P 

 
 NR24L01P está declarada em /inc/hal/nrf24l01p.h e herda publicamente da classe de abstrata MODEM (declarada em /inc/hal/modem.h 
 Seu contrutor recebe como parâmetro um objeto da classe abstrata SPI (declarada em /inc/hal/spi.h com métodos para escrita e início/término de comunicação) e objetos da classe abstrata IO_Pin (declarada em /inc/hal/io_pin.h, com métodos para leitura, escrita e configuração de pinos). 
 Possui um buffer circular para dados transmitidos (_txbuffer) e outro para dados recebidos (_rxbuffer). 
 Esta classe conta com métodos para: 
 sinalizar que o transmissor está disponível para receber uma payload (TxReady()); 
 configurar o transmissor e mandar uma payload para a fila de transmissão (TxPackage() e TxPackage_ESB()); 
 sinalizar que o receptor    tem uma ou mais payloads disponíveis para leitura (RxSize()); 
 ler uma payload para um buffer (RxData(...)); 
 função para configurar como receptor e iniciar o monitoramento de pacotes (StartRX() e StartRX_ESB()); 
 funções de configuração (SetRXFrequency() e Config()) e inicialização (Init()); 
 Uma função de “manutenção” InterruptCallback(), que é chamada de tempos em tempos e quando o pino de IRQ do nRF24 for a nível baixo. Essa função faz uma verificação de alguns registradores, para lidar com os casos de máximo número de retransmissões, chegada de pacote válido, pacote transmitido com “sucesso” (critérios diferentes se o ACK estiver ou não habilitado) ou fila de transmissão cheia, além de fazer a temporização dos leds.Por exemplo, se um pacote de tamanho válido foi recebido, a payload é lida e colocada no _rxbuffer da classe (outras classes ou interrupções não devem acessar o hardware do nRF24, apenas acessam os buffers circulares). Se um pacote foi transmitido, o pino CE é resetado, pacotes na fila de recepção são ignorados. 

 OBS: em caso de sucesso, o led verde da Transmissora e o led azul da receptora acendem. Caso, o receptor não receba, nenhum led acende. 

 h3. 1.2 CLASSE USB_STM32 

 
 Classe declarada em /inc/hal_stm32/usb_stm32.h e herda publicamente da classe USB (declarada em /inc/hal_stm32/usb.h. Esta classe é amiga da classe  
 USB_DEVICE_CLASS, o que lhe permite acessar métodos privados ou protegidos de USB_DEVICE_CLASS. 
 O microcontrolador possui um controlador OTG_FS e um OTG_HS, totalmente conforme à especificação USB 2.0 . Usamos o OTG_FS. 
 Nota: USB On-The-Go, abreviada USB OTG, o dispositivo pode atuar tanto como mestre quanto como escravo. 
 É uma Virtual COM Port, emula uma porta serial (porta COM). 
 O dispositivo USB emula uma virtual COM port. 
 CDC (communication devices class) 
 A função OTG_FS_IRQHandler() implementada em /src/bsp.cpp é chamada quando o periférico OTG_FS da Discovery dispara uma interrupção para indicar que dados foram recebidos, por exemplo. 

 h3. 1.3 CLASSE USB_DEVICE_CLASS_CDC_VCP 

 
 Declarada em /inc/usb/usb_device_class_cdc_vcp.h, herda publicamente de USB_DEVICE_CLASS. Como alguns métodos de USB_DEVICE_CLASS_CDC_VCP sobrecarregam métodos de USB_DEVICE_CLASS, da qual USB_STM32 é amiga, USB_STM32 pode acessar estes métodos.  
 USB_DEVICE_CLASS_CDC_VCP implementa uma virtual COM port (vcp), possui um buffer circular de envio (_datainbuffer) e um de recepção (_dataoutbuffer). Para enviar dados, usa-se um dos métodos USB_DEVICE_CLASS_CDC_VCP.SendData(). Para receber, usa-se um dos métodos USB_DEVICE_CLASS_CDC_VCP.GetData(). 

 h3. 1.4 PROTOBUF 

 Utiliza-se a biblioteca nanopb (https://github.com/nanopb/nanopb), uma implementação em ANSI C do protobuf, protocolo de serialização desenvolvido pela Google (veja https://developers.google.com/protocol-buffers/). 
 Nanopb is an ANSI-C library for encoding and decoding messages in Google's Protocol Buffers format with minimal requirements for RAM and code space. It is primarily suitable for 32-bit microcontrollers. https://jpa.kapsi.fi/nanopb/docs/index.html 
 Nanopb é uma biblioteca em ANSI-C para codificação e decodificação de mensagens no formato Protocol Buffers da Google com requisitos mínimos de RAM e tamanho de código. É adequado principalmente para uso em microcontroladores de 32 bits. 

 To begin with, you must provide a .proto file describing your messsage’s format: 
 For starters, consider this simple message: 
 message Example { 
    required int32 value = 1; 
 } 
 Save this in message.proto and compile it using    protoc: 
 user@host:~$ protoc -omessage.pb message.proto 
 user@host:~$ python nanopb/generator/nanopb_generator.py message.pb 
 You should now have in message.pb.h: 
 typedef struct { 
    int32_t value; 
 } Example; 

 extern const pb_field_t Example_fields[2]; 
 This was how you would generate the files message.pb.c (contains initializers for const arrays) and message.pb.h (contains type declarations). Once you have finished this step, you will need only encode and decode messages. 
  Now in your main program do this to encode a message: 
 Example mymessage = {42}; //initialize your structure 
 uint8_t buffer[10]; 	 //declares a buffer for the encoded message 

 // generates a auxiliary object 
 pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); 

 // encodes the message. Example_fields teaches the format 
 pb_encode(&stream, Example_fields, &mymessage); 
 After that, buffer will contain the encoded message. The number of bytes in the message is stored in stream.bytes_written. 
 Example mymessage; //declares your structure 
 uint8_t buffer[10]=...;// buffer filled with the encoded message 

 // generates a auxiliary object 
 pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer)); 

 // decodes the message. Example_fields teaches the format 
 pb_decode(&stream, Example_fields, &mymessage); 
 Using Protocol Buffers is a way of serializing structured data (e.g. the object representing our robot) for communications with ease, efficiency and maintaining compatibility with older versions. 

 h2. 
 2. LABVIEW 

 
 O arquivo principal do projeto é SSL Vision Log Player.vi, que possui um loop while de rótulo “Communication”, no qual clusters(análogos a structs de C) são continuamente lidos de uma “Lossy stream”, os quais representam nosso time, o    time adversário, as posições onde a bola foi detectada, a geometria do campo, informações do juiz e a Time Stamp recebida. A Time Stamp recebida menos a Time Stamp medida no momento da execução é armazenada em Total Delay. our_robots (um vetor de Robot) é convertido para grSim Robot Commando e é mandado para transmissão, a qual pode ser via UDP (UDP TX, grSim Packet Command UDP Test.vi transmite para o grSim) ou via serial (SERIAL TX, Serial Transmitter.vi, que codifica usando protobuf e escreve na porta COM implementada na Discovery dedicada a transmitir para os robôs). 

 h3.  
 2.1 SERIAL TX (Serial Transmitter.vi) 

 
 Um dos controles (Porta:) permite selecionar a porta que será usada, por exemplo,  
 uma porta COM, um feedback node armazena o valor anterior de Porta: e se eles 
 diferirem (ou não havia porta selecionada antes) ou se houve um erro na escrita 
 anterior, Visa Close fecha a porta anteriormente aberta, faz-se 
 error_out.status=FALSE para limpar qq erro e a vi Visa Configure Serial Port abre e 
 configura a porta serial. Por outro lado, se a porta não mudou e não houve erro, 
 apenas passa-se a porta anterior (via feedback node) para a função VISA Write, que 
 escreve na serial uma string gerada a partir da saída da vi grSim Robot Command, 
 que recebe um grSim Robot Command, o codifica usando protobuf e o transforma em 
 um array de bytes. Antes de passar o cluster para a serialização, um ajuste é feito: os 
 campos velnormal e veltangent são trocados e a veltangent final tem seu sinal 
 invertido, para corrigir uma confusão quanto à definição dessas velocidades.