terça-feira, 16 de junho de 2015

Controlando arduino através de um smartphone via bluetooth

Hoje estarei mostrando como é possível fazer interações com o arduino através de um smartphone via protocolo bluetooth. Primeiramente é necessário você ter em mãos um arduino (óbvio) e um usb host shield com um dongle bluetooth para poder fazer a comunicação com seu smartphone.
O hardware
Além disso, também é necessário você fazer o download de algum aplicativo que ofereça comunicação serial através de bluetooth para poder controlar o microcontrolador. Estou utilizando no momento um smartphone Nokia Lumia, equipado com Windows Phone 8.1 e consegui encontrar um aplicativo na loja chamado 'Bluetooth Agent' (https://goo.gl/ZrwIFK) que apresenta uma interface bem bacana com botões para você enviar comandos via serial bluetooth.


Nessa parte tudo o que você a fazer é colocar algum nome conveniente ao botão e configurar para cada botão enviar algum caractere. Um exemplo disso é o botão "Girar <" que ao ser pressionado envia o caractere "1" para a porta serial bluetooth. O mesmo funciona para os outros botões. Isso poderá ser entendido melhor ao analisarmos o código do arduino:

#include <SPP.h>
#include <usbhub.h>
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif

USB Usb;
BTD Btd(&Usb);
SPP SerialBT(&Btd);

int motorE1 = 2;
int motorD1 = 3;

int pin11 = 26;
int pin12 = 27;
int pin13 = 28;
int pin14 = 29;

int rele = A8;

void setup(){
  pinMode(motorE1, OUTPUT);
  pinMode(motorD1, OUTPUT);
  pinMode(pin11, OUTPUT);
  pinMode(pin12, OUTPUT);
  pinMode(pin13, OUTPUT);
  pinMode(pin14, OUTPUT);
  pinMode(rele, OUTPUT);
  digitalWrite(rele, HIGH);
  Serial.begin(115200);
  while (!Serial);
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1); 
  }
  Serial.print(F("\r\nSPP Bluetooth Library Started"));
}

void loop(){
  Usb.Task(); 

  if (SerialBT.connected){
  char x = SerialBT.read();
  
  if(x == '1'){
    digitalWrite(pin11, LOW);
    digitalWrite(pin12, HIGH);
    analogWrite(motorE1, 255);
    digitalWrite(pin13, LOW);
    digitalWrite(pin14, HIGH);
    analogWrite(motorD1, 255);
  }
  
  if(x == '2'){
    digitalWrite(pin11, HIGH);
    digitalWrite(pin12, LOW);
    analogWrite(motorE1, 255);
    digitalWrite(pin13, HIGH);
    digitalWrite(pin14, LOW);
    analogWrite(motorD1, 255);
  }
  
  if(x == '3'){
    digitalWrite(pin11, HIGH);
    digitalWrite(pin12, HIGH);
    analogWrite(motorE1, 255);
    digitalWrite(pin13, HIGH);
    digitalWrite(pin14, HIGH);
    analogWrite(motorD1, 255);
  }
  
  if(x == '4'){
    digitalWrite(pin11, LOW);
    digitalWrite(pin12, HIGH);
    analogWrite(motorE1, 255);
  
  }
  
  if(x == '5'){
    digitalWrite(pin11, HIGH);
    digitalWrite(pin12, LOW);
     analogWrite(motorE1, 255);
  }
  
  if(x == '6'){
    digitalWrite(pin11, HIGH);
    digitalWrite(pin12, HIGH);
    analogWrite(motorE1, 255);
  }
  
  if(x == '7'){
    digitalWrite(pin13, LOW);
    digitalWrite(pin14, HIGH);
    analogWrite(motorD1, 255);
  
  }
  
  if(x == '8'){
    digitalWrite(pin13, HIGH);
    digitalWrite(pin14, LOW);
     analogWrite(motorD1, 255);
  }
  
  if(x == '9'){
    digitalWrite(pin13, HIGH);
    digitalWrite(pin14, HIGH);
    analogWrite(motorD1, 255);
  }
  
  if(x == 'a'){
    digitalWrite(rele, LOW);
  }
  
  if(x == '0'){
    digitalWrite(rele, HIGH);
  }
  
  if(x == 'b'){
    digitalWrite(rele, LOW);
    delay(1000);
    digitalWrite(rele, HIGH);
  }
 }
}

O código se baseia em comparações à variável 'x', pois na mesma é guardado o último valor de leitura da porta bluetooth. Sendo assim, quando x for igual à 1 (aquele '1' enviado pelo botão "Girar <") é executado tal comando para controlar uma ponte-h. O mesmo ocorre para todas as outras funções. 

Segue um vídeo de demonstração no qual controlei dois motores e um relé que faz acender uma lâmpada:


quarta-feira, 20 de maio de 2015

Implementando sensor de temperatura e umidade com C#

Como todos sabem, o serial monitor do arduino, possui um limite bem pequeno para possibilidades de comunicação, além de não ser possível elaborar interfaces gráficas com botões e tudo mais. Uma solução para isso é criar programas executáveis em C# (csharp), que é uma linguagem de programação voltada para objetos desenvolvida pela microsoft e baseada no C++ e integrar ao seu projeto. Nesse post vou apresentar para vocês uma pequena interação entre o C# e o arduino, onde o microcontrolador lê um sensor de temperatura e umidade DHT11 e a aplicação em C# mostra esses valores no display e plota um gráfico com os número de temperatura umidade relativa recebidos. 

Para chegar nisso, temos duas partes principais: a primeira é a programação do arduino para ler os valores do sensor e fazer um Serial.print quando ele receber o caractere 'a' na porta serial que foi enviada pelo programa. A segunda parte é fazer toda a interface e programação em C# utilizando o Visual Studio, para que a cada 1s ele envie o caractere 'a' na porta serial, para o arduino lhe fornecer os valores de leituras. Esse delay entre as leituras pode ser alterado para o tempo que você quiser, apenas achei 1s conveniente para mim. Vamos à programação no arduino.

#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600); 

  dht.begin();
}

void loop() {
  delay(500);

  int h = dht.readHumidity();
  int t = dht.readTemperature();

  char x = Serial.read();
  
  if(x == 'a'){
    Serial.print(h);
    Serial.print(","); 
    Serial.println(t);
  }
}

Essa parte não tem nenhum segredo. Ele captura os valores de temperatura e umidade e joga na porta serial quando recebe o caractere 'a'. Já a parte em C# é um pouco mais complexa, mas nada fora do normal.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;

namespace arduino
{
    public partial class Form1 : Form
    {

        Thread X;
        public Form1()
        {
            InitializeComponent();
            ComboPorta.DataSource = SerialPort.GetPortNames();
            X = new Thread(new ThreadStart(Serial));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (SP.IsOpen)
            {
                SP.Close();
                X.Abort();
                timerx.Enabled = false;
            }
            else
            {
                SP.PortName = ComboPorta.Text;
                SP.BaudRate = Convert.ToInt32(ComboBaud.Text);
                SP.Open();
                //X.Start();
                timerx.Enabled = true;
               
            }
        }

        void Serial()
        {
            while (true)
            {
                SP.Write("a");
                textBox1.Text += SP.ReadLine();
                textBox1.Text += "\r\n";
            }
        }


        private void timerx_Tick(object sender, EventArgs e)
        {
            SP.Write("a");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            SP.Close();
            X.Abort();
            timerx.Enabled = false;
        }

        private void SP_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            this.Invoke(new EventHandler(transfere));
        }

        void transfere(object sender, EventArgs e)
        {
            string dado = SP.ReadLine();
            string [] dados = dado.Split(',');
            textBox1.Text += dados[0];
            textBox1.Text += "%\r\n";
            textBox1.Select(textBox1.Text.Length, 0);
            textBox1.ScrollToCaret();
            
            textBox2.Text += dados[1];
            textBox2.Text += "°C\r\n";
            textBox2.Select(textBox2.Text.Length, 0);
            textBox2.ScrollToCaret();

            chart1.Series[0].Points.Add(Convert.ToDouble(dados[0]));
            chart1.Series[1].Points.Add(Convert.ToDouble(dados[1]));
            int x = chart1.Series[0].Points.Count;
            if (x > 100)
                chart1.ChartAreas[0].AxisX.ScaleView.Zoom(x - 100, x);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void label4_Click(object sender, EventArgs e)
        {

        }

            
    }
}

Sintetizando todo esse código, temos o programa enviando a cada 1000ms o char 'a' na porta serial e capturando os dados fornecidos que logo depois são quebrados pela função split e atribuídos como dados[1] e dados [2], para umidade e temperatura respectivamente. O resto é lógica incorporada ao C# e a interface visual do programa. O resultado final é esse:


Logo abaixo deixo o link para download tanto da programação em arduino como o projeto no Visual Studio para quem quiser testar, implementar, modificar, etc. Ah, o arquivo executável do programa encontra-se na pasta SerialPort\visual\arduino\bin\Debug.

Download do programa: https://goo.gl/Xk8jgm

domingo, 10 de maio de 2015

Robô controlado por Dualshock 3 utilizando arduino

Hoje eu venho apresentar para vocês o meu primeiro protótipo de um "carrinho" controlado sem fio através de um dualshock 3, o controle de PS3 no caso. Para isso ser possível, é necessário utilizar um dongle bluetooth e um usb host shield para o arduino poder conseguir fazer a comunicação com o controle. Já na parte de locomoção utilizei o motor e as reduçoes do servo MG 995 (que possui engrenagens de metal), onde são controlados por drivers externos, nesse caso duas ponte-H que usam o L298N. Para conseguir alimentar tudo isso estou utilizando tipo de bateria selada 12V 7Ah (utilizadas em central de alarmes e no-breaks), ela aguenta bastante tempo até mas não cheguei a medir a [acronym]corrente[/acronym] que "puxa" com os 4 motores operando com força máxima para calcular a duração. A bateria também é um pouco pesada, o ideal seria usar bateria Li-Po que é mais compacta e não compromete tanto o tempo que o robô consegue operar, mas era o que tinha disponível no momento. Também há iluminação na frente que é composta por 15 led's de alto-brilho que apresentaram um bom resultado.

Agora a parte mais trabalhosa, a programação. Não existe nenhum mistério nesse código, pois para esse shield existe uma biblioteca que tem vários exemplos, inclusive para controle de PS3. Só é necessário adaptar a programação para o uso. Segue ai o programa que estou usando no arduino.


#include <PS3BT.h>                                                   

USB Usb;
BTD Btd(&Usb);
PS3BT PS3(&Btd); 

int motorE1 = 2;
int motorD1 = 3;
int motorE2 = 4;
int motorD2 = 5;

int pin11 = 30;
int pin12 = 31;
int pin13 = 32;
int pin14 = 33;
int pin21 = 34;
int pin22 = 35;
int pin23 = 36;
int pin24 = 37;

void setup() {
  Serial.begin(115200);                                              
  if (Usb.Init() == -1)
  {                                            
  Serial.print(F("\r\nOSC did not start"));
  while(1);
  }
  Serial.print(F("\r\nPS3 Bluetooth Library Started")); 

  pinMode(motorE1, OUTPUT);
  pinMode(motorD1, OUTPUT);
  pinMode(motorE2, OUTPUT);
  pinMode(motorD2, OUTPUT);
  pinMode(pin11, OUTPUT);
  pinMode(pin12, OUTPUT);
  pinMode(pin13, OUTPUT);
  pinMode(pin14, OUTPUT);
  pinMode(pin21, OUTPUT);
  pinMode(pin22, OUTPUT);
  pinMode(pin23, OUTPUT);
  pinMode(pin24, OUTPUT);  
                                                      
   
}
void loop() 
{
  Usb.Task();  
  
  if(PS3.PS3Connected || PS3.PS3NavigationConnected){
    if (PS3.getAnalogHat(LeftHatY) > 135){
      digitalWrite(pin11, HIGH);
      digitalWrite(pin12, LOW);
      analogWrite(motorE1, map(PS3.getAnalogHat(LeftHatY), 130, 255, 0, 255));
      }
        
    if (PS3.getAnalogHat(LeftHatY) < 120){
      digitalWrite(pin11, LOW);
      digitalWrite(pin12, HIGH); 
      analogWrite(motorE1, map(PS3.getAnalogHat(LeftHatY), 0, 125, 255, 0));
    }     
     
    if (PS3.getAnalogHat(LeftHatY) > 135){
      digitalWrite(pin21, HIGH);
      digitalWrite(pin22, LOW);
      analogWrite(motorE2, map(PS3.getAnalogHat(LeftHatY), 130, 255, 0, 255));
    }
          
    if (PS3.getAnalogHat(LeftHatY) < 120){
      digitalWrite(pin21, LOW);
      digitalWrite(pin22, HIGH); 
      analogWrite(motorE2, map(PS3.getAnalogHat(LeftHatY), 0, 125, 255, 0));
    }     
      
    if (PS3.getAnalogHat(RightHatY) > 135){
      digitalWrite(pin13, HIGH);
      digitalWrite(pin14, LOW);
      analogWrite(motorD1, map(PS3.getAnalogHat(RightHatY), 130, 255, 0, 255));
    }
       
    if (PS3.getAnalogHat(RightHatY) < 120){
      digitalWrite(pin13, LOW);
      digitalWrite(pin14, HIGH); 
      analogWrite(motorD1, map(PS3.getAnalogHat(RightHatY), 0, 125, 255, 0));
    } 
  
    if (PS3.getAnalogHat(RightHatY) > 135){
      digitalWrite(pin23, HIGH);
      digitalWrite(pin24, LOW);
      analogWrite(motorD2, map(PS3.getAnalogHat(RightHatY), 130, 255, 0, 255));
    }
          
    if (PS3.getAnalogHat(RightHatY) < 120) {
      digitalWrite(pin23, LOW);
      digitalWrite(pin24, HIGH); 
      analogWrite(motorD2, map(PS3.getAnalogHat(RightHatY), 0, 125, 255, 0));
    }
  
    if (PS3.getButtonClick(SQUARE)){
      digitalWrite(53, HIGH);
    }

    if (PS3.getButtonClick(CROSS)){
      digitalWrite(53, LOW);
    }

    if (PS3.getButtonClick(CIRCLE)){
      analogWrite(motorE1, 0);
      analogWrite(motorE2, 0);
      analogWrite(motorD1, 0);
      analogWrite(motorD2, 0);
    }
     
    if(PS3.getButtonClick(PS)){
      PS3.disconnect();      
      analogWrite(motorE1, 0);
      analogWrite(motorE2, 0);
      analogWrite(motorD1, 0);
      analogWrite(motorD2, 0);
      digitalWrite(53, LOW);
  }
 }
}


Explicando de forma bem simples, o arduino captura a variável do eixo analógico do controle, converte para PWM pela função 'map' e joga o sinal para a ponte H junto com o os sinais 'high' e 'low' para controlar a direção do motor. Ali na parte que faz uso do pino 53, é a iluminação que nao declarei uma variável para ele.


Seguem agora algumas fotos e um vídeo de testes que fiz:



Frisando novamente que apenas é o protótipo, ainda quero implementar várias coisas nele, como um sensor ultrassônico que tenho aqui, além de algum tipo de braço/garra na frente para pegar objetos.

sexta-feira, 5 de abril de 2013

Braço Robótico


Eu utilizo arduino ja faz algum tempo e irei mostrar um projeto meu, um braço robótico que desenvolvi não faz muito tempo. Vou deixar o vídeo logo aqui em cima e depois explico tudo.


O braço possui dois eixos de movimentação. Como puderam notar, utilizei 5 servos motores pequenos (parecidos com os de parabólicas, só que menores), sendo dois para o levantamento, um para o giro e dois para a garra, um controle infravermelho e seu respectivo receptor, arduino UNO e uma fonte de alimentação de computador para não sobrecarregar o regulador de tensão do Arduino que suporta apenas 1,5A. As garras do braço ou pinças são feitas de acrílico 4mm e possuem uma borracha na ponta para aumentar o atrito com os objetos. 

Na protoboard estão posicionados o receptor IR, o arduino, um LED e alguns cabos (jumpers) para a conexão com os vários periféricos do braço. Para melhorar o entendimento, desenhei no Fritzing o esquema de ligação dos componentes, segue uma imagem:


E agora eis a parte mais complicada, a programação do arduino. Apesar de parecer não tão difícil, é a parte  que mais da dor de cabeça, pois para o hardware funcionar corretamente do jeito que queremos é necessário cuidar todos os detalhes, desde um parênteses até a lógica do programa. Aqui está:

//Produzido por Robinson Joel Ten Caten.

#include <IRremote.h>
#include <Servo.h> 

Servo SERVO_GE;
Servo SERVO_GD;
Servo SERVO_G;
Servo SERVO_LE;
Servo SERVO_LD;

int receiver = 12;
int led = 13;
int luz = 8;

IRrecv irrecv(receiver); 
decode_results results;

void setup(){
  pinMode(led, OUTPUT);
  pinMode(luz, OUTPUT);
  SERVO_LE.attach(5);
  SERVO_LD.attach(6);
  SERVO_G.attach(9);
  SERVO_GE.attach(10);
  SERVO_GD.attach(11);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  SERVO_G.write(80);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  digitalWrite(luz, LOW);
  Serial.begin(9600);
  irrecv.enableIRIn();
}

void pisca(){
  digitalWrite(led, HIGH);
  delay(100);
  digitalWrite(led, LOW);
}

void loop(){

if (irrecv.decode(&results)){  
switch(results.value){ 
   
            //CONTROLE 

case 1086259455:{ //      PLAY/PAUSE
  pisca();
  Serial.println(">> A ESQUERDA");
  SERVO_G.write(0);
  break;
}

case 1086292095:{ //      CHANEL -
  pisca();
  Serial.println(">> CENTRALIZADO");
  SERVO_G.write(80);
  break;
}

case 1086275775:{ //      CHANEL +
  pisca();
  Serial.println(">> A DIREITA");
  SERVO_G.write(165);
  break;
}

case 1086267615:{ //      EQUALIZADOR
  pisca();
  Serial.println(">> PARA TRAS");
  SERVO_LE.write(150);
  SERVO_LD.write(30);
  break;
}

case 1086300255:{ //      VOLUME -
  pisca();
  Serial.println(">> CENTRALIZADO");
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  break;

case 1086283935:{ //      VOUME +
  pisca();
  Serial.println(">> PARA FRENTE");
  SERVO_LE.write(20);
  SERVO_LD.write(135);
  break; 
}

case 1086296175:{ //      PREVIOUS
  pisca(); 
  Serial.println(">> GARRA ABERTA");
  SERVO_GE.write(60); 
  SERVO_GD.write(45);
  break; 
}

case 1086279855:{ //      NEXT
  pisca(); 
  Serial.println(">> GARRA FECHADA");
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  break; 
}

case 1086263535:{ //      NUMERO 0
  pisca();
  Serial.println(">> NORMAL");
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  SERVO_G.write(80);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  break;  
}

case 1086271695:{ //      NUMERO 1
  pisca();
  Serial.println(">> PEGANDO OBJETO");
  SERVO_G.write(80);
  SERVO_GE.write(60); 
  SERVO_GD.write(45);
  delay(150);
  SERVO_LE.write(20);
  SERVO_LD.write(135);
  delay(150);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  delay(150);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  break;
}
  
case 1086304335:{ //      NUMERO 2
  pisca();
  Serial.println(">> LARGANDO OBJETO");
  SERVO_G.write(80);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  delay(150);
  SERVO_LE.write(20);
  SERVO_LD.write(135);
  delay(150);
  SERVO_GE.write(60); 
  SERVO_GD.write(45);
  delay(150);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  break;
}  

case 1086288015:{ //      NUMERO 3
  pisca();
  Serial.println(">> JA ERAS");
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  delay(150);
  SERVO_LE.write(150);
  SERVO_LD.write(30);
  delay(150);
  SERVO_GE.write(60); 
  SERVO_GD.write(45);
  delay(150);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  SERVO_LE.write(90);
  SERVO_LD.write(90);
  break;
}
  
case 1086261495:{ //      NUMERO 4
  pisca();
  Serial.println(">> ABRINDO E FECHANDO A GARRA");
  SERVO_GE.write(60); 
  SERVO_GD.write(45);
  delay(300);
  SERVO_GE.write(103); 
  SERVO_GD.write(0);
  break;
}

case 1086294135:{ //      NUMERO 5
  pisca();
  Serial.println(">> LUZ ACESSA");
  digitalWrite(luz, HIGH);
  break;
}

case 1086277815:{ //      NUMERO 6
  pisca();
  Serial.println(">> LUZ APAGADA");
  digitalWrite(luz, LOW);
  break;
}

case 1086269655:{}  //     NUMERO 7
case 1086302295:{} //      NUMERO 8
case 1086285975:{} //      NUMERO 9
}
  
  delay(100); 
  irrecv.resume(); 
  }
}

Não vou entrar em muitos detalhes na programação se não ficaria muito extenso. Para conseguir compilar este programa é necessário baixar uma biblioteca, a IRremote que é utilizada para usar controles infravermelhos. Para poder programar as funções de cada botão é necessário saber o código do mesmo, assim quando feita a leitura de um botão "x" é feita tal coisa e assim sucessivamente com todos os comandos do controle.




Por hoje é só.

Arduino - o que é?


Arduino é uma placa de uso Open Source, ou seja, de livre uso que surgiu em 2005 com o objetivo de criar ferramentas acessíveis, a baixo custo, flexíveis e de fácil uso mesmo por leigos em eletrônica. Pode ser utilizadas para várias tarefas e projetos, desde acender um pequeno LED, até comandar um robô complexo. O arduino é baseado em microcontroladores da Atmel (variando do modelo da placa), que possui o são baseados em entradas e saídas (I/O) que podem ser tanto digitais como analógicas. Sua linguagem é essencialmente baseada em C/C++ e possui um ambiente próprio de programação (IDE) escrita em Java.

Para poder programar o arduino, você só precisa baixar a IDE (http://arduino.cc/en/Main/Software), instalar os drivers no computador e plugar o cabo USB. A partir dai, terá uma infinidade de possiblidades a seu dispor.





Bom pessoal por hoje é isso, até a proxima.