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.