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

2º Bate Papo do SP-GTUG - Divulgação

Pessoal, Para aqueles que já estiveram presentes nas atividades do SP-GTUG (encontros ou bate papos na Globalcode), e para os que ainda não puderam estar presentes, teremos um novo bate papo acerca de mais duas tecnologias do Google: AdSense e Python no GAE. Este será o nosso segundo bate papo do SP-GTUG, nos mesmos moldes dos minicursos da Globalcode . Local e data O bate papo acontecerá no dia 27/03/10, das 10:00 às 13:00 na Globalcode. Para fazer sua inscrição e participar acesse a home da Globalcode e vá até a parte de "Minicursos Gratuitos da Semana ". Conteúdo das apresentações Abaixo seguem as descrições passadas pelos palestrantes: Título: "Algoritmos em Python" Resumo: Python é uma linguagem considerada frugal, simples, sem ser simplória! Entenda como construir algoritmos ninjas com essa linguagem, adotada pela Google e pelo MIT. Veremos muito, muito código, desde algoritmos clássicos até tutoriais do

10 reasons why we love JSF

1. One-slide technology: it's so simple that I can explain basic JSF with one slide. 2. Easy to extend: components, listeners, render kit, Events, Controller, etc. 3. Real-world adoption: JBoss, Exadel, Oracle, IBM, ... 4. Architecture model: you can choose between more than 100 different architecture. 5. Open-mind community: using JSF you are going to meet very interesting people. 6. We are using JSF the last 5 years and we found very good market for JSF in Brazil 7. Progress: look to JSf 1.1 to JSF 1.2, JSF 1.2 to JSF 2.0. People are working really hard! 8. Many professionals now available 9. It's a standard. It's JCP. Before complain, report and help! 10. Ed Burns, spec leader, is an old Globalcode community friend! EXTRA: My wife is specialist in JSF. She's my F1 for JSF :) Nice job JSF community! -Vinicius Senger

JSF 2 - Composite Components, você não precisa mais ser um ninja

Estamos em uma nova era da computação, os dados não estão mais localizados em um banco dentro de sua empresa, vivemos a explosão de redes sociais, informações são geradas a todo instante, e se torna essencial que sua aplicação conheça os serviços disponíveis na web e consumam suas APIs geralmente disponíveis por serviços REST. Legal, mas como ficam meus aplicativos Java EE neste novo cenário? Para quem vem acompanhando a evolução da plataforma, é notório que todo esforço vem sendo utilizado para aumentar a produtividade e a integração com novos serviços. Basicamente duas especificações surgem com muita força para atender este cenário, a JSR - 314 (JSF-2) e JSR - 311 (JAX-RS), neste post exploraremos a JSR-314 (JSF2) e sua nova forma de criar Composite Components. Uma das grandes queixas dos desenvolvedores JSF era a complexidade em criar composite components, era necessário um vasto conhecimento sobre o ciclo de vida de uma aplicação JSF. Agora, você não precisa ser mais um “ninja” em

Gosta de informática e sonha ser programador Java um dia ?

A Globalcode está procurando jovens que queiram ser programadores no futuro, para fazer parte de sua equipe de vendas e operacional na unidade Paraíso em São Paulo somente. O grande diferencial é o planejamento para carreira de programador. O planejamento de cursos do portifólio da Globalcode: Academia do Programador, Academia Java, Academia Web, Robótica, Eletrônica, etc, será realizado periodicamente de acordo com o desempenho e interesse individual. Atenção : Este não é um estágio para trabalhar com Java, são duas vagas CLT administrativas para pessoas que queiram ser programadores no futuro. Perfil : Conhecimentos de informática básica, saber lidar com pessoas e trabalhar em equipe. Deve ter concluído o ensino médio, ter boa escrita, ser organizado, responsável, comprometido e dinâmico. Interesse por computação, programação, internet, robótica, eletrônica,... Temos duas vagas para jovem-aprendiz abertas: 1) Setor operacional No dia a dia Serviços externos Controle de estoqu

JavaMail: Enviando mensagem HTML com anexos

Introdução Depois do post "JavaMail: Enviando e-mail com Java" , que apresentava como enviar um e-mail com Java, resolvi complementar a assunto apresentando como enviar uma mensagem formatada, em HTML , e também como realizar o envio de anexos. Bibliotecas Além da biblioteca JavaMail, veja mais no post anterior , é necessário incluir o JavaBeans Activation Framework (JAF), apenas se a versão utilizada for anterior ao JSE 6.0 , que já tem o JAF incluso. O JAF está disponível em http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html , e neste download encontramos, alguns exemplos na pasta demo , documentação, incluindo javadocs, na pasta docs e a biblioteca activation.jar , que deve ser acrescentada no classpath da aplicação para versões anteriores ao JSE 6.0. Exemplo Primeiramente devemos realizar a configuração da javax.mail.Session e da javax.mail.internet.MimeMessage , estes passos podem ser vistos no post anterior . Agora vamos montar um

TDC INNOVATION lança University Pass

Modalidade de ingresso tem como objetivo ajudar na capacitação dos universitários Uma pesquisa realizada em 2020 pela Associação Brasileira das Empresas de Tecnologia da Informação e Comunicação (Brasscom) diz que até o ano de 2024 o Brasil precisará de cerca de 420 mil profissionais na área de Tecnologia da Informação. Porém, por ano, a mesma pesquisa diz que o país forma apenas 46 mil profissionais capacitados no nicho. Pensando nisso, para ajudar na formação e capacitação desses jovens profissionais, o TDC INNOVATION, segunda edição do ano do The Developer's Conference, lança o University Pass, modalidade de ingresso que possibilita aceso digital gratuito a todas as palestras do evento, ou com 50% de desconto para quem preferir ir pessoalmente. Com o tema central “Desafios para a criação do futuro Digital”, o TDC INNOVATION ocorrerá entre 1 e 3 de junho, de forma híbrida: presencialmente no Centro de Convenções CentroSul, em Florianópolis, e com transmissão simultaneamente pela