Pular para o conteúdo principal

Arduino + Sun Spot + Controle Remoto

Finalizamos nesta semana um incrível projeto de integração do Sun Spot com Arduino. Costumo dizer que o Sun Spot é o primo rico do Arduino e como não conseguimos encontrar acelerômetros em estoque nas lojas dos Estados Unidos, acabamos por topar o desafio de fazer o Arduino pegar os dados do acelerometro do Sun Spot, um tipo de "mashup" de hardware, ou no clássico termo: um hacking.

Para ter uma "implementação de referência" de uso do Sun Spot com Arduino, pegamos um controle de remoto infravermelho de um bicho bem esquisito que trouxemos da Maker Faire: o Mechamo.

O resultado esta no vídeo abaixo onde controlamos esta aranha usando o acelerômetro do Sun Spot:



Com o mesmo conceito você pode usar qualquer recurso do Sun Spot no Arduino e vice-versa. Vamos avançar agora transformando o código em bibliotecas para o Arduino com C++ e Jars para o Sun Spot.

O projeto contou com inúmeras colaborações do Paulos Carlos Ferreira dos Santos e Benedicto Franco Junior. Dois grandes mentores e parceiros Globalcode.

A seguir o descritivo completo incluindo código-fonte do projeto.

Etapa 1: abrindo e interceptando o controle remoto

Abrimos o controle remoto dela e para nossa sorte seu controle é o mais básico possível: com 4 botões comuns. Com isso usando o multimetro descobrimos qual era o pino de sinal de cada botão e soldamos 5 fios: 1 no terra e 1 para cada botão, esquerda, direita, frente e traz. Feito.

Etapa 2: testando o controle remoto com Arduino

Logo que terminamos testamos controlar o controle remoto puramente com Arduino e funcionou bem tranquilo o que nos deu uma segurança para prosseguir para a próxima fase: integrar o Arduino com Sun Spot, transferir dados do acelerometro do Sun Spot e depois comandar o controle remoto.

Etapa 3: integrando Arduino com Sun Spot método 1

A primeira solução que implementamos foi a mais ansiosa, diria assim. Foi com a técnica de polling, usamos 3 digitais: uma para dados, uma para polling e uma para acknowledge. Polling é basicamente ficar laço infinito lendo o sinal e assim que mudar de estado, 0 para 1 ou inverso, você reage e inicia a leitura dos dados. Funcinou! Mas deu um trabalhão para sincronizar os hardwares, na real tivemos que ir tentando o melhor delay após mudar o estado de uma porta digital. Enfim, mas funcionou gastando processamento de polling e também com custo de delays bem alto.

Etapa 4: mudando para usar interrupções no Arduino

Apresentando a engenhoca para o real engenheiro Paulo Carlos Ferreira dos Santos, tivemos uma mudança siginificativa na técnica: usar uma das 2 interrupções disponíveis do Arduino. UAU. Show de técnica. Basicamente mantivemos o uso de 3 digitais, porém uma das digitais ligamos do Sun Spot no Arduino Digital 2 que representa a interrupção 0, a digital 3 a interrupção 1. O que muda radicalmente é o código, pois fica assíncrono e a programação de serviços de interrupção (IRS) requer algumas práticas.

Se você é programador Java como eu, logo vai querer pensar com Threads, o que não acontece com Arduino pois ele é real-time. Xii, e as váriáveis que são alteradas pelos serviços de interrupção? Se temos duas interrupções? Pois é, a boa prática é quando entrar em uma interrupção, bloquear a outra, que no caso de só termos duas fica tranquilo. Bem, viagens a parte, seguimos adiante com a implementação de interrupção, que requer o uso das seguintes funções do Arduino:

attachInterrupt(0, suaFuncaoDeInterrupcao, RISING);

Esta função esta vinculando na interrupção 0, porta digital 2, a função "suaFuncaoDeInterrupcao", quando o sinal mudar de 0 para 1, e apenas de 0 para 1. Poderia ser falling (contrário), CHANGE qualquer mudança ou ainda LOW, ou seja, sempre que 0. Enfim, fácil de usar.

Aprendemos também que devemos fazer o mínimo necessário dentro da função de serviço de interrupção, pois em primeiro tentar interromper uma vez e transferir um byte por vez, não deu. Ai mostramos novamente a engenhoca para o engenheiro que diagnosticou com precisão: tem que ser uma interrupção por bit... Dito e feito e sincronizado.

Outro detalhe é que as variáveis que alteramos nas função de serviço de interrupção devem ser volatile (se lembram deste nome no Java??) volatile é uma diretiva de compilação que faz o Arduino alocar esta variável na RAM e não na stack e seu único uso é realmente para funções de interrupção.

Sei que ficou grande o post mas foram muitos aprendizados que queremos documentar e compartilhar com todos. Vejam o código completo do Arduino:

int SUN_SPOT = 9;
int SUN_SPOT_ACK = 10;
int SUN_SPOT_INTERRUPT = 0; //PORTA digital 2

int FORWARD=7; //fio branco
int BACKWARD=6; //fio laranja
int LEFT=4; //azul
int RIGHT=5; //verde

int interrupt=0;
volatile int data;
volatile boolean bit_array[16];
volatile int contador;
volatile int x;
volatile int y;

void setup() {
setupSunSpot();
//Setup do controle remoto da Aranha
setupMechamo();

attachInterrupt(0, receiveSunSpot, RISING);
Serial.begin(9600);
}
void setupSunSpot() {
pinMode(SUN_SPOT,INPUT);
pinMode(SUN_SPOT_ACK,OUTPUT);
}
void setupMechamo() {
pinMode(FORWARD, OUTPUT);
pinMode(BACKWARD, OUTPUT);
pinMode(LEFT, OUTPUT);
pinMode(RIGHT, OUTPUT);
digitalWrite(SUN_SPOT_ACK,LOW);
digitalWrite(FORWARD,HIGH);
digitalWrite(BACKWARD,HIGH);
digitalWrite(LEFT,HIGH);
digitalWrite(RIGHT,HIGH);
}
void receiveSunSpot() {
digitalWrite(SUN_SPOT_ACK,LOW);
bit_array[contador++]=digitalRead(SUN_SPOT);
if(contador==16) {
contador=0;
x = BtoI(0,7,bit_array);
y = BtoI(8,15,bit_array);
}
digitalWrite(SUN_SPOT_ACK,HIGH);
}

int BtoI(int start,int end, volatile boolean bits[]){
boolean negative=bits[start];
start++;
unsigned long integer=0;
unsigned long mask=1;
int r;
for (int i = end; i >= start; i--) {
if(negative) {
if (!bits[i]) integer |= mask;
}
else {
if (bits[i]) integer |= mask;
}
mask = mask << 1;
}
r = (int) integer;
if(negative) r= ~r;
return r;
}

void loop() {
digitalWrite(RIGHT, !(x>30 && x<90));
digitalWrite(LEFT, !(x<-30 && x>-90));
digitalWrite(FORWARD, !(y>30 && y<90));
digitalWrite(BACKWARD, !(y<-30 && y>-90));

Serial.print("x = ");
Serial.println(x);
Serial.print("y = ");
Serial.println(y);
delay(300);
}




Podemos perceber que o método loop fica totalmente independente da recepção dos dados do Sun Spot. Isso acontece assincronamente pela interrupção. Lembrando que apesar de termos apenas 2 no Arduino convencional, o Arduino Mega oferece 4 interrupções. Se fossemos criar um sistema de threads com para ATMega sem dúvida metade do caminho esta andado com este projeto.

Bem, vamos analisar agora o lado do Sun Spot. Lá é nossa praia (pelo menos minha), pois é Java. Programamos o Sun Spot com NetBeans e Midlets e uma agradável API no leva para os objetos que representam componentes do Sun Spot, como acelerômetro e portas digitais / analógicas.

Com este código obtemos as portas digitais de comunicação com Arduino:
 private IIOPin arduinoData = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D0];
private IIOPin arduinoStrobe = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D2];
private IIOPin arduinoAck = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D1];



Aqui configuramos no startup se as portas serão de input ou output além do estado inicial delas:

  protected void startApp() throws MIDletStateChangeException {
arduinoData.setAsOutput(true);
arduinoStrobe.setAsOutput(true);
arduinoAck.setAsOutput(false);
arduinoData.setHigh(false);
arduinoStrobe.setHigh(false);
arduinoLoop();
}



O código completo ficou assim:

package br.com.globalcode.arduino;

import com.sun.spot.sensorboard.io.IIOPin;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ITriColorLED;
import com.sun.spot.sensorboard.peripheral.LEDColor;
import com.sun.spot.sensorboard.peripheral.IAccelerometer3D;
import com.sun.spot.util.Utils;

import java.io.IOException;

import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/*
* ArduinoIntegration.java
*
* This simple Sun Spot Midlet reads accelerometer X and Y axis and send
* to Arduino using interruption.
*
* author: Vinicius Senger - vinicius@globalcode.com.br
* Paulo Carlos dos Santos - paulosantos@globalcode.com.br
* date: July, 2009
*/
public class ArduinoIntegration extends MIDlet {

private IAccelerometer3D accel = EDemoBoard.getInstance().getAccelerometer();
private ITriColorLED[] leds = EDemoBoard.getInstance().getLEDs();
private IIOPin arduinoData = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D0];
private IIOPin arduinoStrobe = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D2];
private IIOPin arduinoAck = EDemoBoard.getInstance().getIOPins()[EDemoBoard.D1];

public void arduinoLoop() {
for (int i = 0; i < 8; i++) {
leds[i].setOff(); // turn off all LEDs
leds[i].setColor(LEDColor.BLUE); // set them to be blue when lit
}
int oldX = 0;
int oldY = 0;
while (true) {
try {
int tiltX = (int) Math.toDegrees(accel.getTiltX()); // returns [-90, +90]
int tiltY = (int) Math.toDegrees(accel.getTiltY()); // returns [-90, +90]
if (tiltX != oldX || tiltY != oldY) {
sendBitsToIO(getBits((byte) tiltX), getBits((byte) tiltY));
oldX = tiltX;
oldY = tiltY;
}
changeLeds(tiltX);
} catch (IOException ex) {
System.out.println("Error reading accelerometer: " + ex);
}
}
}
private void sendBitsToIO(boolean bitsX[], boolean bitsY[]) {
for (int x = 0; x < bitsX.length; x++) {
send(bitsX[x]);
}
for (int y = 0; y < bitsY.length; y++) {
send(bitsY[y]);
}
}

private void send(boolean bit) {
arduinoData.setHigh(bit);
arduinoStrobe.setHigh();
arduinoStrobe.setLow();
while (arduinoAck.isLow());
}

private boolean[] getBits(byte value) {
//Depois de escrever o método minha
//querida esposa lembrou to Integer.toBinaryString :)
// Agora fica assim mesmo.
boolean result[] = new boolean[8];
byte displayMask = (byte) (1 << 7);
for (int c = 0; c < 8; c++) {
result[c] = (value & displayMask) != 0;
value <<= 1;
}
return result;
}

private void changeLeds(int tiltX) {
int offset = -tiltX / 15;
if (offset < -3) {
offset = -3;
}
if (offset > 3) {
offset = 3;
}
leds[3 + offset].setOn();
leds[4 + offset].setOn();
Utils.sleep(20);
leds[3 + offset].setOff();
leds[4 + offset].setOff();
}


protected void startApp() throws MIDletStateChangeException {
arduinoData.setAsOutput(true);
arduinoStrobe.setAsOutput(true);

arduinoAck.setAsOutput(false);
arduinoData.setHigh(false);
arduinoStrobe.setHigh(false);
arduinoLoop();
}

protected void pauseApp() {
}

protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
for (int i = 0; i < 8; i++) {
leds[i].setOff();
}
}
}

Comentários

Dr. Spock disse…
Ficou show de bola essa video montagem ... Só acho que faltou colocar o SyntaxHighlighter para mostrar o código fonte formatado e colorido como aparece em alguns outros blog ...

Dica: http://developertips.blogspot.com/2007/08/syntaxhighlighter-on-blogger.html
Hey Vinicius,

Qual irá ser o seu próximo desafio? Que tal integrar o SunSpot com esta aranha?
Unknown disse…
Detalhe pra taça de vinho em cima da mesa =P
Wagner Santos disse…
Bem loko heim Vinicius, parabéns !!! =)

Quero um brinquedinho desses para mim hehe..

Alguém já pensou em fazer experiências com o Lego Mindstorms e o Arduino, ou o Sun Spot,, deve ser no minimo interessante ..

Abraço,
Unknown disse…
@Wagnão: logo você poderá ter o seu pois nesta semana chegam os Program-ME. Lego MindStorms rola normal com Arduino, ja tem bastante gente fazendo com a versão mais recente da Lego. Mas o mais legal do hacking é fazer coisas com o que você tem na mão.

Agora estou neste mesmo projeto integrando o GPS Garmin que eu tenho para fazer a Aranha andar em rotas traçadas por GPS. Minha idéia é fazer ela aprender a chegar na praia sozinha, afinal de contas, é a inteligência mais digna de um robô filho de peixe.RS.

O mais legal disso é poder ver a eletrônica no baixo nível e praticar deslocamento de bits como nunca.

Isso é muito bom pois todos os fundamentos de lógica e algoritmos são praticados.

[]s
Vinicius
Unknown disse…
@Bene, meu próximo é usar o GPS para guiar ela por latitude e longitude. A comunicação Garmin X Arduino não demorou 15 minutos. Agora comprei DB9 e estou montando um hacking cable serial para facilitar. O que esta dificil nesta etapa é que o GPS só pega fora de casa e por conta das árvores, só com tempo bom. Como esta chovendo muito por aqui, esta integração esta parada. RSRSS. Desculpão hein?
Vinícius,

Lembre-se que o GPS comum, nas melhores condições, tem precisão variando em torno dos 15 metros. Com o serviço de correção WAAS disponível apenas na América do Norte, a precisão melhora para algo em torno de 3 metros.

[]s,

Bene.
Paulo Siqueira disse…
Muito legal mesmo! Mas concordo com o Spock, faltou um Sintax Highlight aí ;)
Anônimo disse…
Muito legal a integração de hardwares.

Postagens mais visitadas deste blog

O que é Lógica de programação?

Este é o segundo de uma série de posts voltados aos leitores do blog que estão dando início à carreira de desenvolvimento de software. O assunto de hoje é a lógica de programação. Para ler antes: Entendendo como funciona a programação de computadores: linguagens de programação, lógica, banco de dados A lógica de programação é um pré-requisito para quem quer se tornar um desenvolvedor de software, independente da linguagem de programação que se pretende utilizar. Mas o que é de fato a Lógica de Programação e como saber se eu tenho esse pré-requisito? A lógica de programação nada mais é do que a organização coerente das instruções do programa para que seu objetivo seja alcançado. Para criar essa organização, instruções simples do programa, como mudar o valor de uma variável ou desenhar uma imagem na tela do computador, são interconectadas a estruturas lógicas que guiam o fluxo da execução do programa. Isso é muito próximo ao que usamos em nosso cotidiano para realizar atividad...

TDC ONLINE: SUA PLATAFORMA DE PALESTRAS GRAVADAS DO TDC DISPONÍVEL

Além do conteúdo ao vivo transmitido online nas edições do TDC, agora você pode ter acesso à centenas de palestras gravadas, através da nossa nova plataforma de vídeos - o TDC Online, que reúne todas as Trilhas premium, Stadium e Salas dos Patrocinadores das edições anteriores de 2022, TDC Innovation e TDC Connections.  Para acessar, basta clicar na edição em que você participou ( TDC Innovation ou TDC Connections ); Fazer o mesmo login (com e-mail e senha) cadastrados na hora de adquirir ou resgatar o seu ingresso no TDC; E clicar na Trilha de sua opção, e de acordo com a modalidade do seu ingresso. Logo em seguida, você será direcionado para a seguinte página com a lista de todas as palestras por Trilha: Pronto! Agora você tem acesso à centenas de palestras gravadas da sua área de interesse, para assistir como e quando quiser! Caso tenha esquecido a senha, clique na opção "Esqueci a senha" , insira o e-mail que você realizou para o cadastro no evento, e aparecerá a op...

TDC BUSINESS, chega a São Paulo com novas trilhas de Inteligência Artificial e Inovação

Maior conferência de profissionais de tecnologia do Brasil abordará temas em alta no momento como, por exemplo, Inteligência Artificial, Segurança, Ciência de Dados e Inovação O TDC BUSINESS, a 17° edição do The Developer's Conference na cidade de São Paulo, que acontece entre os dias 19 e 21 de Setembro, reunirá profissionais e especialistas da área para troca de experiência, compartilhamento de conteúdos e networking. Com o tema central: “Tecnologia para negócios transformadores”, o evento será totalmente híbrido, ocorrendo presencialmente no espaço Pro Magno, e com transmissão simultânea e atividades de network pela internet. A expectativa é reunir mais de 14.000 pessoas, somando a participação presencial e online.   Segundo Yara Mascarenhas, Fundadora e Host do Evento, “nosso objetivo com o TDC é inspirar a colaboração entre os profissionais e empresas para construir uma nova realidade para o mercado de TI.  Vamos juntar tecnologia e negócios com as trilhas técnicas...

12 ESQUENTAS TDC ESPERANDO POR VOCÊ

O TDC nasceu do sonho de profissionais que valorizam o compartilhamento de conhecimento, experiências e oportunidades entre as comunidades de desenvolvedores.  Por isso, o crescimento do TDC nunca poderia ficar longe do crescimento das comunidades! Pensando nessa união, criamos um projeto quente: O ESQUENTA TDC ! Visando divulgar os meetups de comunidades que querem transformar e inspirar carreiras, foi co-criado este projeto lindo e cheio de apoio, onde o TDC abraça meetups de diversas comunidades espalhadas pelo Brasil e elas contribuem com a divulgação da edição regente.  O TDC Innovation vai rolar de 14 a 16 de JUNHO, mas até lá vão acontecer muitos encontros incríveis!  Fique por dentro das comunidades que vão participar, quais temas irão abordar e claro as datas e locais para você participar. 💥Esquentas TDC Innovation 2023: 24/05 - Esquenta TDC: Carreira e Desenvolvimento Presencial em Floripa das 19:00 as 21:30 com inscrição AQUI Comunidade: Google Developer...

JSON fácil em Java com GSon !

Ola pessoal ! O formato JSON ( J ava S cript O bject N otation) vem se consagrando cada vez mais na comunicação de dados, principalmente nos dispositivos móveis devido a esse formato ser mais leve que o XML e também mais legível. Uma prova disso são as inúmeras bibliotecas que existem para manipular esse formato, e no caso do Android, o suporte ao JSON é nativo. Mas apesar de ter esse suporte nativo, algumas operações devem ser feitas manualmente e o código acaba ficando um pouco verboso e repetitivo, já que para cada objeto que se deseja transmitir é necessário fazer um método que lê as propriedades do JSON e faz as devidas atribuições no seu objeto Java. Vamos supor o seguinte objeto sendo transmitido em JSON: {   user: {     id: 123456,     name: "Neto Marin",     username: "netomarin",     email: "netomarin@globalcode.com.br"   } } Se você fosse tratar um Webservice que envia esse JSON para o seu aplicativo Android...

JavaOne Brasil, dicas para submissão de palestras

Não quero parecer pretensiosa dando dicas para submissão de palestras para o JavaOne Brasil, mas sim repassar os tantos conselhos e sugestões recebidas pelos vetaranos do JavaOne: Bruno Souza e Leonardo Galvão que revisaram dezenas de submissões para o JavaOne e ajudaram a aprovar tantas palestras, e também misturar um pouco da minha experiência na seleção de palestras nos eventos realizados pela Globalcode e SouJava . 10 anos de JavaOne: http://www.globalcode.com.br/noticias/Globalcode10AnosNoJavaOne Os palestrantes ganham a entrada! A submissão pode ser feita em português! O passo mais importante para ser aprovado como palestrante no JavaOne é sem dúvida nenhuma submeter pelo menos uma palestra. Então, independente de qualquer coisa, participe, arrisque, divulgue.  Mas, se quiser aumentar as suas chances...   1) Leve a sério: peça para amigos fazerem uma leitura crítica do texto, e claro uma boa revisão ortográfica. 2) Submissão de várias palestras ou variações do ...