Apresentação do kit RB1

Esta página está em construção

O kit RB1 que é um kit didático de Robótica, de baixo custo, com base no chassi Magician e no controlador Romeo BLE compatível com o Arduino UNO. Embora se possa considerar um kit genérico para actividades de Robótica Educativa, foi desenvolvido com o Concurso Nacional de Robótica Robô Bombeiro em mente e tem os componentes típicos que normalmente são usados pelos robôs do concurso.

Componentes

A seguinte tabela descreve a lista de componentes do kit RB1.

Qt. Descrição
1 Chassis em acrílico (com 2 rodas motrizes e uma roda de apoio tipo esfera).
1 Suporte para 4 pilhas de 1.5V (o Kit não inclui as pilhas).
2 Motores de corrente contínua para mover as rodas do robô numa configuração de condução diferencial.
1 Ventoinha com controlo electrónico que funciona como o sistema de extinção do robô.
3 Sensores tipo SONAR para medir as distâncias a que se encontram os obstáculos e permitir ao robô navegar.
2 Sensores tipo bumper para detetar o contato com obstáculos
1 Sensor fotorefletivo para detetar as linhas brancas que assinalam as entradas dos quartos na arena do concurso Robô Bombeiro.
1 Câmara de infravermelhos para detetar a chama da vela ou outras fontes de IV.
2 Botões de pressão Start e Stop.
1 LED Azul para assinalar detecção da chama.
1 LCD (16 x 2) para mostrar mensagens.
1 Controlador Romeo BLE
- Compatível com Arduino UNO
- Pinos macho e fêmea para fácil ligação de sensores
- 14 portais digitais I/O
- 6 PWM Outputs
- 8 portas analógicas de input (10-bit)
- Bus I2C com 3 ligações na placa
- Controlador de motores CC integrado de dois canais
- Chip Bluetooth Low Energy (BLE) integrado
- Suporta Bluetooth HID e iBeacons
- Sockets integrado para modulo APC220 RF
- Suporta programação remota via Bluetooth

Para além dos componentes listados, o Kit inclui toda a cablagem, parafusos e outras peças, para a montagem completa do robô.

O Kit tem um custo de 198 euros e é fornecido desmontado.

Caso esteja interessado/a em adquirir o Kit envie um e-mail para robobombeiro@ipg.pt.

Manual de Montagem

O manual de montagem descreve passo a passo a montagem dos componentes do Kit incluindo as ligações com o controlador Romeo BLE. Nos exemplos de programação que se seguem assume-se que os componentes foram ligados como indicado no manual de montagem.
manual_de_montagem_do_kit_rb1.pdf

Controlador Romeo BLE

O Kit RB1 usa o controlador Romeo BLE da DFRobot, o qual é compatível com o Arduino. Pode programar o controlador com o IDE do Arduino seleccionado a placa Arduino Uno.

A seguinte figura apresenta um diagrama do controlador com a identificação dos principais recursos. Para mais informações sobre o controlador consulte a página oficial do fabricante.

Bibliotecas

Os exemplos das secções a seguir usam bibliotecas de software que devem ser instaladas no Arduino para que os exemplos funcionem corretamente.

Segue-se a lista das bibliotecas usadas com links para download ou para a página dos autores.

Veja aqui como instalar bibliotecas no IDE do Arduino.

Exemplos de Programas

As secções que se seguem apresentam detalhes importantes sobre os componentes que constituem o Kit e exemplos de programas para testar e programar esses mesmos componentes. É também apresentado um programa básico para o robô procurar e extinguir o incêndio na arena do concurso Robô Bombeiro (a disponibilizar em breve).

A documentação que se apresenta pretende ser um manual básico do funcionamento do kit e não uma introdução à robótica móvel ou à programação de robôs. Para esse efeito sugerimos que frequente curso Introdução à Robótica com o Robô Bombeiro.

Atuadores do Robô

O robô tem os seguintes atuadores:

  • 2 motores de corrente continua para mover as rodas;
  • 1 motor de corrente continua para mover a ventoinha que funciona como o sistema de extinção do robô.

Motores das Rodas

O robô usa um sistema de condução diferencial com duas rodas motrizes e uma roda de apoio. Cada roda motriz é movida por um motor de corrente continua. Os motores das rodas são controlados a partir do próprio controlador RoMeo que incorpora um circuito de ponte-H para o efeito. Ver aqui os detalhes.

O exemplo a seguir exemplifica como controlar os motores do robô RB1 através do circuito de ponte-H incorporado no controlador Romeo. O exemplo é semelhante ao apresentado na página do controlador, mas usa a biblioteca RBMotor para simplificar o controlo dos motores.

A biblioteca RBMotor implementa a classe com o mesmo nome que toma conta dos detalhes do funcionamento das portas para controlar um dado motor.

Funções da biblioteca:

  • RBMotor(int powerPin, int dirPin, int minPWM) O construtor da classe recebe três parâmetros; as portas para controlar a velocidade e o sentido de rotação do motor, e o valor mínimo PWB a considerar. Internamente a classe mapeia o intervalo entre esse valor mínimo e o valor máximo de 255, num intervalo de velocidades possíveis de 0 a 16.
  • setPower(int power) Define o valor de power (velocidade) do motor (de 0 a 16).
  • stop() Pára os motores.


#include "RBMotor.h" //Biblioteca para controlar os motores

//Portas usadas pelo circuito ponte-h do controlador Romeo BLE
int P1 = 5;    //Porta para o controlo da velocidade do motor M1 (valor de PWM de 0 a 255)
int P2 = 6;    //Porta para o controlo da velocidade do motor M2 (valor de PWM de 0 a 255)
int D1 = 4;    //Porta para o controlo do sentido de rotação do motor M1 (valor LOW ou HIGH)
int D2 = 7;    //Porta para o controlo do sentido de rotação do motor M2 (valor LOW ou HIGH)

RBMotor M1(P1, D1, 150);  //Criação do objeto do motor da esquerda
RBMotor M2(P2, D2, 150);  //Criação do objeto do motor da direita

void setup(void) 
{ 
  int i;
  for(i=4;i<=7;i++)
    pinMode(i, OUTPUT);  
    
  Serial.begin(115200); //Baud Rate da comunicação série
  Serial.println("Run keyboard control");
} 

void loop(void) 
{
  if(Serial.available()){
    char val = Serial.read();
    if(val != -1)
    {
      switch(val)
      {
      case 'w': //Avançar
        advance (16, 16);   //Avançar à máxima velocidade
        break;
      case 's': //Recuar
        back_off (16, 16);   //Recuar à máxima velocidade
        break;
      case 'a': //Virar à esquerda
        turn_L (8, 8);       //Virar à esquerda à velocidade 8 
        break;       
      case 'd': //Virar à direita
        turn_R (8, 8);       //Virar à direita à velocidade 8
        break;
      case 'z':
        Serial.println("Hello");
        break;
      case 'x': //Stop
        stop();
        break;
      }
    }
    else stop();  
  }
}

//Stop
void stop(void)              
{
  M1.stop();
  M2.stop();
}   

//Avançar
void advance(char a,char b)  
{
  M1.setPower(a);
  M2.setPower(b);
}  

//Recuar
void back_off (char a,char b)
{
  M1.setPower(-a);
  M2.setPower(-b);
}

//Virar à esquerda
void turn_L (char a,char b)  
{
  M1.setPower(-a);
  M2.setPower(b);
}

//Virar à direita
void turn_R (char a,char b)  
{
  M1.setPower(a);
  M2.setPower(-b);
}

Exemplo Dança

O exemplo a seguir faz o robô executar uma dança movendo-se ao ritmos de valores aleatórios! Ver também os exemplos Explorar I e Explorar II.


#include <RBMotor.h>  //Biblioteca para controlar os motores
 
// Portas usadas pela ponte-h do controlador Romeo
const int RM_POWER = 5;
const int LM_POWER = 6;
const int RM_DIR = 4;
const int LM_DIR = 7;
 
int leftPower;  // Power a aplicar ao motor da esquerda
int rightPower; // Power a aplicar ao motor da direita
int time;       // Tempo de execução da manobra   
 
// Criação dos objetos dos dois motores
RBMotor leftMotor(LM_POWER, LM_DIR, 150);
RBMotor rightMotor(RM_POWER, RM_DIR, 150);
   
void setup() {
  randomSeed(analogRead(0));  // Inicialização do gerador de números aleatórios 
}
 
void loop() {
  leftPower = random(-16, 17); 
  rightPower = random(-16, 17);
  time = random(401) + 100;
  go(leftPower, rightPower, time);
}
 
void go(int leftPower, int rightPower, int milliseconds) {
  leftMotor.setPower(leftPower);
  rightMotor.setPower(rightPower);
  delay(milliseconds);
}

Ventoinha

A ventoinha é controlado por um circuito electrónico com duas entradas digitais que controla a direção de rotação da ventoinha. No Kit RB1 usamos apenas a entrada INB que está ligada à porta digital 3 do controlador. Para ligar a ventoinha basta colocar a porta digital a LOW e para desligar a HIGH. O exemplo a seguir exemplifica o controlo da ventoinha desligando-a e ligando-a a cada 3 segundos.

const int VENTOINHA = 3;  // A ventoinha está ligada à porta 3

void setup() {
  pinMode(VENTOINHA, OUTPUT); 
  digitalWrite(VENTOINHA, HIGH);  // Um valor HIGH desliga a ventoinha
}

void loop() {
  digitalWrite(VENTOINHA, LOW);  // Ligar a ventoinha
  delay(3000);                   // Esperar 3 segundos
  digitalWrite(VENTOINHA, HIGH); // Desligar a ventoinha 
  delay(3000);                   // Esperar 3 segundos 
}

Interface do Robô

O robô está equipado com diversos elementos de interface:

  • 1 LCD;
  • 1 LED;
  • 6 botões de pressão na própria placa RoMeo;
  • 2 botões de pressão.

LCD

O LCD está ligado ao controlador através do bus I2C e usa o endereço 0x27. A comunicação com o LCD é realizada usando duas bibbilotecas. A biblioteca Wire e a biblioteca LiquidCrystal_I2C.

O programa a seguir demonstra a configuração básica do LCD e a escrita de uma mensagem.

#include <Wire.h>   // Biblioteca para comunicação I2C.
#include <LiquidCrystal_I2C.h>  // Biblioteca para controlar o LCD.
 
LiquidCrystal_I2C lcd(0x27,16,2);  // Configuração do endereço, do número de caracteres e do número de linhas do LCD.
 
void setup()
{
  lcd.init();  // Inicialização do LCD. 
  
  // Escrever uma mensagem no LCD.
  lcd.backlight();
  lcd.print("Hello, RB1!");
}
 
void loop()
{
}


Funções da classe LiquidCrystal_I2C:

  • LiquidCrystal_I2C() Set the LCD address for a 16 chars and 2 line display
  • init() Initialization for the LCD
  • clear() Clear display, set cursor position to zero
  • home() Set cursor position to zero
  • createChar() Fill the first 8 CGRAM locations with custom characters
  • setCursor() Set the position of the cursor
  • cursor() Turns the underline cursor on
  • noCursor() Turns the underline cursor off
  • blink() Turn on the blinking cursor
  • noBlink() Turn off the blinking cursor
  • display() Turn the display on(quickly)
  • noDisplay() Turn the display 0ff(quickly)
  • backlight() Turn the backlight on
  • noBacklight() Turn the backlight off
  • scrollDisplayLeft() Make the display scroll left without changing the RAM
  • scrollDisplayRight() Make the display scroll right without changing the RAM
  • autoscroll() This will 'right justify' text from the cursor
  • noAutoscroll() This will 'left justify' text from the cursor
  • leftToRight() This is for text that flows Left to Right
  • rightToLeft() This is for text that flows Right to Left

LED

O robô tem um LED azul montado junto da ventoinha que no contexto do concurso Robô Bombeiro deve ser usado para assinalar que a chama foi detetada antes de a tentar extinguir.

O programa a seguir exemplifica como se pode ligar e desligar o LED.

const int LED = 13;  //O LED está ligado à porta 13.

void setup() {                
  pinMode(LED, OUTPUT);     
}

void loop() {
  digitalWrite(LED, HIGH);  //Ligar o LED.
  delay(1000);              //Esperar 1 segundo.
  digitalWrite(LED, LOW);   //Desligar o LED.
  delay(1000);              //Esperar 1 segundo.
}


Botões no Controlador Romeo BLE

A completar em breve.

#include <SimpleMotor.h>


Botões Verde e Vermelho

O robô tem dois botões de pressão, um verde e outro vermelho, montados junto da ventoinha. No contexto do concurso Robô Bombeiro estes botões servem respetivamente para iniciar e terminar o funcionamento do robô e são obrigatórios.

O botão verde está ligado na porta 11 e o vermelho na porta 10.

O programa a seguir demonstra o uso do botão verde para ligar e desligar o LED.

const int BT_VERDE = 11;  // Porta do botão verde.
const int LED = 13;       // Porta do LED interno.

int estado = 0;  // Variável para ler o estado do botão.

void setup() {
  // A porta do LED é configurada para output.
  pinMode(LED, OUTPUT);
  
  // A porta do botão é configurada para imput.
  pinMode(BT_VERDE, INPUT_PULLUP);
}

void loop() {
  // Leitura do estado do botão.
  estado = digitalRead(BT_VERDE);

  // Verificar se o botão foi activado.
  // Se sim, o estado do botão é LOW.
  if (estado == LOW) {         
    digitalWrite(LED, HIGH);  // Ligar o LED.  
  } 
  else {
    digitalWrite(LED, LOW);  // Desligar o LED. 
  }
}


Sensores do Robô

O robô está equipado com os seguintes sensores:

  • 3 sensores SONAR HC-SR04 para medir as distâncias a que se encontram os obstáculos;
  • 2 bumpers para detetar o contato com obstáculos;
  • 1 sensor fotorefletivo para detetar as linhas brancas que assinalam as entradas dos quartos na arena do concurso Robô Bombeiro;
  • 1 câmara de infravermelhos para detetar a chama da vela ou outras fontes de IV.

As secções a seguir apresentam informação adicional sobre o funcionamento e programação de cada um dos sensores.

Sensores SONAR

O robô tem 3 sensores SONAR.

É aconselhável usar a biblioteca NewPing para obter medições a partir dos sensores SONAR. A biblioteca é muito eficiente e permite ligar cada sensor a uma única porta digital, partilhando assim os sinais de Trigger e Echo. Por esse motivo, os pinos dos sinais referidos estão soldados entre si, como indicado na seguinte figura.

Métodos da classe NewPing v1.8

  • NewPing sonar(trigger_pin, echo_pin [, max_cm_distance]) - Initialize an ultrasonic device, trigger pin, echo pin, and optional maximum distance you wish to sensor to measure (default = 500cm).
  • sonar.ping([max_cm_distance]) - Send a ping and get the echo time (in microseconds) as a result. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_in([max_cm_distance]) - Send a ping and get the distance in whole inches. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_cm([max_cm_distance]) - Send a ping and get the distance in whole centimeters. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.ping_median(iterations [, max_cm_distance]) - Do multiple pings (default=5), discard out of range pings and return median in microseconds. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.convert_in(echoTime) - Convert echoTime from microseconds to inches.
  • sonar.convert_cm(echoTime) - Convert echoTime from microseconds to centimeters.
  • sonar.ping_timer(function [, max_cm_distance]) - Send a ping and call function to test if ping is complete. [max_cm_distance] allows you to optionally set a new max distance.
  • sonar.check_timer() - Check if ping has returned within the set distance limit.
  • NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
  • NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
  • NewPing::timer_stop() - Stop the timer.

Os sensores SONAR esquerdo, frontal e direito do robô, estão respetivamente ligados às portas digitais 9, 8 e 2 do controlador.

O exemplo a seguir demonstra como obter e mostrar no LCD as distancias medidas pelos sensores SONAR.

#include <NewPing.h>  //Biblioteca para o controlo dos sensores SONAR.
#include <LiquidCrystal_I2C.h>  //Biblioteca para o controlo do LCD.

//Objetos dos sensores SONAR da esquerda, frente e direita.
NewPing sonarE(9, 9, 300);  //Controlado pela porta 9.
NewPing sonarF(8, 8, 300);  //Controlado pela porta 8.
NewPing sonarD(2, 2, 300);  //Controlado pela porta 2.

//Objeto do LCD.
LiquidCrystal_I2C lcd(0x27, 16, 2); //LCD com endereço 0x27, 16 colunas e 2 linhas.

int distE, distF, distD; //Distancias lidas pelos sensores SONAR.

void setup() {
  //Inicialização do LCD
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Teste dos SONAR");
}

void loop() {

  //Ler as distâncias. 
  distE = medirDist(sonarE);
  distF = medirDist(sonarF);
  distD = medirDist(sonarD);

  //Mostrar distancias
  mostrarDistancias();
}

//Função para obter a distancia do sensor SONAR.
//s - Sensor SONAR.
int medirDist(NewPing &s) {
  return (s.ping() / US_ROUNDTRIP_CM);
}

//Função para mostrar no LCD as distâncias lidas pelos sensores SONAR.
void mostrarDistancias() {
  lcd.setCursor(0, 1);
  lcd.print("E");
  if (distE < 100)
    lcd.print(" ");
  if (distE < 10)
    lcd.print(" ");
  lcd.print( distE);
  lcd.print(" F");
  if (distF < 100)
    lcd.print(" ");                                                                                                                                                                                                                                                                                                                               
  if (distF < 10)
    lcd.print(" ");
  lcd.print( distF);
  lcd.print(" D");
  if (distD < 100)
    lcd.print(" ");
  if (distD < 10)
    lcd.print(" ");
  lcd.print( distD);
}

Segue-se um segundo exemplo que demonstra o uso dos sensores SONAR.

Exemplo Explorar I

Este programa controla o robô de modo a navegar no espaço livre e a mudar de direção sempre que os sensores SONAR detetarem um obstáculo a uma distância inferior a uma dado limite.

#include <RBMotor.h>  //Biblioteca para o controlo dos motores.
#include <NewPing.h>  //Biblioteca para o controlo dos sensores SONAR.
#include <LiquidCrystal_I2C.h>  //Biblioteca para o controlo do LCD.

//Portas dos botões verde e vermelho.
const int BT_VERDE = 11;
const int BT_VERMELHO = 10;

//Objetos dos motores da esquerda e da direita. 
RBMotor motorE(6, 7, 150);  //Controlado pelas portas 6 e 7.
RBMotor motorD(5, 4, 150);  //Controlado pelas portas 5 e 4.

//Objetos dos sensores SONAR da esquerda, frente e direita.
NewPing sonarE(9, 9, 100);  //Controlado pela porta 9.
NewPing sonarF(8, 8, 100);  //Controlado pela porta 8.
NewPing sonarD(2, 2, 100);  //Controlado pela porta 2.

//Objeto do LCD.
LiquidCrystal_I2C lcd(0x27, 16, 2); //LCD com endereço 0x27, 16 colunas e 2 linhas.

int distE, distF, distD; //Distancias lidas pelos sensores SONAR.
boolean iniciar = false; //Flag para iniciar o programa ao primir o botão verde.

void setup() {
  //Configuração das portas dos botões.
  pinMode(BT_VERDE, INPUT_PULLUP);
  pinMode(BT_VERMELHO, INPUT_PULLUP);

  //Inicialização do LCD
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Explorar I");
}

void loop() {

   if (!iniciar) {
    //Esperar até que o botão verde seja premido.
    while (digitalRead(BT_VERDE) == HIGH);
    iniciar = true;
  }

  //Ler as distâncias. 
  distE = medirDist(sonarE);
  distF = medirDist(sonarF);
  distD = medirDist(sonarD);

  //Mostrar distancias
  mostrarDistancias();
  
  //Mover o robô de modo a explorar o espaço que o rodeia.
  mover(8, 0);  //Avançar à velocidade de 8.
  //Se os sensores SONAR detetarem algum obstáculo a menos de 15 cm, o robô muda de direção.
  if (distF > 0 && distF < 15) { 
    //Rodar aproximadamente 180º à velocidade de 5.
    rodar(5);  
    delay(2000);
  } else if (distE > 0 && distE < 15) {
    //Rodar para a direita aproximadamente 45º à velocidade de 5.
    rodar(-5);
    delay(600);
  } else if (distD > 0 && distD < 15) {
    //Rodar para a esquerda aproximadamente 45º à velocidade de 5.
    rodar(5);
    delay(600);
  }
  

  //Parar o robô se o botão vermelho for premido.
  if (digitalRead(BT_VERMELHO) == LOW) {
    parar();
    iniciar = false;
  }
}

//Função para mover o robô.
//v - Velocidade.
//d - Delta que determina a diferença de velocidade entre o motor da esquerda 
//    e motor da direita, fazendo o robô descrever uma curva.
//v > 0 avança.
//v < 0 recua. 
void mover(int v, int d) {
  motorE.setPower(v - d);
  motorD.setPower(v + d);
}

//Função para rodar o robô.
//v - Velocidade.
//v > 0 roda para a esquerda. 
//v < 0 roda para a direita.
void rodar(int v) {
  motorE.setPower(v);
  motorD.setPower(-v);
}

//Função para parar os motores.
void parar() {
  motorE.stop();
  motorD.stop();
}

//Função para obter a distancia do sensor SONAR.
//s - Sensor SONAR.
int medirDist(NewPing &s) {
  return (s.ping() / US_ROUNDTRIP_CM);
}

//Função para mostrar no LCD as distâncias lidas pelos sensores SONAR.
void mostrarDistancias() {
  lcd.setCursor(0, 1);
  lcd.print("E");
  if (distE < 100)
    lcd.print(" ");
  if (distE < 10)
    lcd.print(" ");
  lcd.print( distE);
  lcd.print(" F");
  if (distF < 100)
    lcd.print(" ");                                                                                                                                                                                                                                                                                                                               
  if (distF < 10)
    lcd.print(" ");
  lcd.print( distF);
  lcd.print(" D");
  if (distD < 100)
    lcd.print(" ");
  if (distD < 10)
    lcd.print(" ");
  lcd.print( distD);
}

Bumpers

Os bumpers da esquerda e da direita do robô estão respetivamente ligados às portas digitais 12 e 0 do controlador.

O exemplo a seguir exemplifica a leitura dos estados dos bumpers. O programa escreve no LCD quais são os bumpers que estão premidos.

#include <LiquidCrystal_I2C.h>  //Biblioteca para o controlo do LCD.

const int BUMPER_E = 12;  //O bumper da esquerda está ligado à porta 12.
const int BUMPER_D = 0;   //O bumper da direita está ligado à porta 0.

//Objeto do LCD.
LiquidCrystal_I2C lcd(0x27, 16, 2); //LCD com endereço 0x27, 16 colunas e 2 linhas.

void setup() {
  //Inicialização do LCD
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Teste dos Bumpers");

  //configuração das portas dos bumpers para input com pullup.
  pinMode(BUMPER_E, INPUT_PULLUP);
  pinMode(BUMPER_D, INPUT_PULLUP);
}

void loop() {
  lcd.setCursor(0, 1);
  
  if (digitalRead(BUMPER_E) == LOW && digitalRead(BUMPER_D) == LOW) { //Ambos os bumpers estão premidos.
    lcd.print("E e D");
  }
  else if (digitalRead(BUMPER_E) == LOW) { //O bumper da esquerda está premido.
    lcd.print("E");
  }
  else if (digitalRead(BUMPER_D) == LOW) { //O bumper da direita está premido.
    lcd.print("D");
  }
  else {
    lcd.print("     ");  //Nenhum bumper está premido.
  }
}

Exemplo Explorar II

Este programa controla o robô de modo semelhante ao programa do exemplo Explorar I, com a diferença de usar também os bumpers do robô para detetar colisões com obstáculos. O robô executará uma manobra de recuperação no caso de um dos bumpers ser premido, ou no caso dos dois bumpers serem premidos ao mesmo tempo.

#include <RBMotor.h>  // Biblioteca para o controlo dos motores.
#include <NewPing.h>  // Biblioteca para o controlo dos sensores SONAR.
#include <LiquidCrystal_I2C.h>  // Biblioteca para o controlo do LCD.
 
// Portas dos botões verde e vermelho.
const int BT_VERDE = 11;
const int BT_VERMELHO = 10;

// Portas dos bumpers da esquerda e da direita
const int BUMPER_E = 12;  
const int BUMPER_D = 0;   
 
// Objetos dos motores da esquerda e da direita. 
RBMotor motorE(6, 7, 150);  // Controlado pelas portas 6 e 7.
RBMotor motorD(5, 4, 150);  // Controlado pelas portas 5 e 4.
 
// Objetos dos sensores SONAR da esquerda, frente e direita.
NewPing sonarE(9, 9, 100);  // Controlado pela porta 9.
NewPing sonarF(8, 8, 100);  // Controlado pela porta 8.
NewPing sonarD(2, 2, 100);  // Controlado pela porta 2.
 
// Objeto do LCD.
LiquidCrystal_I2C lcd(0x27, 16, 2); // LCD com endereço 0x27, 16 colunas e 2 linhas.
 
int distE, distF, distD; // Distâncias lidas pelos sensores SONAR.
boolean iniciar = false; // Flag para iniciar o programa ao primir o botão verde.
 
void setup() {
  // Configuração das portas dos botões para input com pullup.
  pinMode(BT_VERDE, INPUT_PULLUP);
  pinMode(BT_VERMELHO, INPUT_PULLUP);

  // Configuração das portas dos bumpers para input com pullup.
  pinMode(BUMPER_E, INPUT_PULLUP);
  pinMode(BUMPER_D, INPUT_PULLUP);
 
  // Inicialização do LCD
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Explorar I");

  // Inicialização do gerador de números aleatórios 
  randomSeed(analogRead(0));  
}
 
void loop() {
 
   if (!iniciar) {
    // Esperar até que o botão verde seja premido.
    while (digitalRead(BT_VERDE) == HIGH);
    iniciar = true;
  }
 
  // Medir as distâncias. 
  distE = medirDist(sonarE);
  distF = medirDist(sonarF);
  distD = medirDist(sonarD);
 
  // Mostrar distancias
  mostrarDistancias();
   
  // Mover o robô de modo a explorar o espaço que o rodeia.
  mover(8, 0);  // Avançar à velocidade de 8.
  
  // Se os sensores SONAR detetarem algum obstáculo a menos de 15 cm, o robô muda de direção.
  if (distF > 0 && distF < 15) { 
    // Rodar aproximadamente 180º à velocidade de 5.
    rodar(5);  
    delay(2000);
  } else if (distE > 0 && distE < 15) {
    // Rodar para a direita aproximadamente 45º à velocidade de 5.
    rodar(-5);
    delay(600);
  } else if (distD > 0 && distD < 15) {
    // Rodar para a esquerda aproximadamente 45º à velocidade de 5.
    rodar(5);
    delay(600);
  }

 // Se os sensores bumper forem premidos devido a coliderem com algum obstáculo, o robô muda de direção 
 // executando manobras predefinidas para cada situação.  
 if (digitalRead(BUMPER_E) == LOW && digitalRead(BUMPER_D) == LOW) { // Ambos os bumpers estão premidos.
    manobraBumperEeD();
  }
  else if (digitalRead(BUMPER_E) == LOW) { // O bumper da esquerda está premido.
    manobraBumperE();
  }
  else if (digitalRead(BUMPER_D) == LOW) { // O bumper da direita está premido.
    manobraBumperD();
  }
  
  // Parar o robô se o botão vermelho for premido.
  if (digitalRead(BT_VERMELHO) == LOW) {
    parar();
    iniciar = false;
  }
}
 
// Função para mover o robô.
// v - Velocidade.
// d - Delta que determina a diferença de velocidade entre o motor da esquerda 
//     e motor da direita, fazendo o robô descrever uma curva no caso de não ser 0.
// v > 0 avança.
// v < 0 recua. 
void mover(int v, int d) {
  motorE.setPower(v - d);
  motorD.setPower(v + d);
}
 
// Função para rodar o robô.
// v - Velocidade.
// v > 0 roda para a esquerda. 
// v < 0 roda para a direita.
void rodar(int v) {
  motorE.setPower(v);
  motorD.setPower(-v);
}
 
// Função para parar os motores.
void parar() {
  motorE.stop();
  motorD.stop();
}

// Função para manobrar o robô no caso dos dois bumperes serem premidosao mesmo tempo. 
void manobraBumperEeD() {
  int r = random(1, 11);
  // Escolher aleatoriamente uma das manobras, em função de r ser par ou impar.  
  if(r % 2 == 0)
    manobraBumperE();
  else
    manobraBumperE(); 
}

// Função para manobrar o robô no caso do bumper da esquerda ser premidos
void manobraBumperE() {
  mover(-12, 8);  //Recua descrevendo um arco para a esquerda.
  delay(1200);
}

// Função para manobrar o robô no caso do bumper da direita ser premidos
void manobraBumperD() {
  mover(-12, -8);  //Recua descrevendo um arco para a esquerda.
  delay(1200);
}
 
// Função para obter a distância medida pleo sensor SONAR.
// s - Sensor SONAR.
int medirDist(NewPing &s) {
  // return (s.ping() / US_ROUNDTRIP_CM);
  return(s.ping_cm());
}
 
// Função para mostrar no LCD as distâncias lidas pelos sensores SONAR.
void mostrarDistancias() {
  lcd.setCursor(0, 1);
  lcd.print("E");
  if (distE < 100)
    lcd.print(" ");
  if (distE < 10)
    lcd.print(" ");
  lcd.print( distE);
  lcd.print(" F");
  if (distF < 100)
    lcd.print(" ");                                                                                                                                                                                                                                                                                                                               
  if (distF < 10)
    lcd.print(" ");
  lcd.print( distF);
  lcd.print(" D");
  if (distD < 100)
    lcd.print(" ");
  if (distD < 10)
    lcd.print(" ");
  lcd.print( distD);
}

Sensor Fotorefletivo (Sensor de Linha)

O sensor fotorefletivo do robô está ligado à porta analógica 0 do controlador.

No contexto do Robô Bombeiro este sensor pode ser usado para detetar as linhas brancas que assinalam as entradas dos quartos, permitindo saber quando é que o robô se encontra nessas localizações.

O seguinte exemplo exemplifica como ler e escrever no LCD o valor obtido pelo sensor. O valor obtido estará entre 0 e 1023 e será tanto mais elevado quanto menos refletiva for a superfície para onde o sensor está virado.

#include <LiquidCrystal_I2C.h>  // Biblioteca para escrever no LCD.

const int SENSOR_LINHA = 0;     // Porta analógica do sensor de linha. 
LiquidCrystal_I2C lcd(0x27, 16, 2); //Objeto para o LCD com endereço 0x27, 16 carateres e 2 linhas
int val = 0;
 
void setup() {
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Teste S. Linha");
}
 
void loop() {
  val = analogRead(SENSOR_LINHA);
  mostrarDadosSLinha();
}
 
// Função para escrever no LCD o valor obtido pelo sensor de linha.
void mostrarDadosSLinha() {
  lcd.setCursor(0, 1);
  lcd.print("Val: ");
  if (val < 1000)
    lcd.print(" ");
  if (val < 100)
    lcd.print(" ");
  if (val < 10)
    lcd.print(" ");
  lcd.print(val);
}

O sensor tem também uma saída digital que pode ser ligada a uma porta digital, mas que não é usada no kit RB1. A saída digital terá o valor HIGH no caso do detetor do sensor detetar a luz refletida, o que dependerá da superfície para onde o sensor está virado e da sensibilidade ajustada através do potenciómetro incorporado no sensor.

Câmara de IV (Sensor de Chama)

A câmara de infravermelhos está ligada ao bus I2C do controlador e deteta até 4 fontes de infravermelhos devolvendo as coordenas x, Y de cada uma delas. Ver a página do sensor no site do fabricante para mais detalhes sobre o funcionamento do sensor e exemplos de programas para o mesmo.

No contexto do Robô Bombeiro, este sensor pode ser usado para detetar eficazmente a chama da vela uma vez que esta é uma fonte de radiação infravermelha. O exemplo a seguir exemplifica como obter os dados da chama. O exemplo usa a biblioteca rbflamesensor.zip que simplifica a programação do sensor. Esta biblioteca implementa a classe com o mesmo nome que toma conta dos detalhes do funcionalismo do sensor. Segue-se a lista de funções disponibilizadas pela classe.

  • RBFlameSensor(int d) - O construtor da classe recebe um valor inteiro entre 1 e 10 que indica o número de possíveis direções a considerar para a posição da chama. Isto é, o ângulo de visão horizontal é dividido em d regiões
  • init() - Inicializa parâmetros internos do sensor.
  • update(flameX, flameY) - Devolve verdade ou falso indicando se a chama foi ou não detetada e devolve as coordenadas flameX e flameY da chama.
  • setDivi(d) - Altera o número de direções possíveis a considerar para a chama. Altera o valor inicial do parâmetro d passado no construtor.
  • getDir() - Devolve a direção da chama em relação ao sensor (devolve -1 se a chama não for detetada).


#include <Wire.h>               //Biblioteca para comnicação I2C.
#include <LiquidCrystal_I2C.h>  //Biblioteca para escrever no LCD.
#include <RBFlameSensor.h>      //Biblioteca para controlar o sensor de chama.

LiquidCrystal_I2C lcd(0x27, 16, 2); //Objeto para o LCD com endereço 0x27, 16 carateres e 2 linhas

//Objeto para o sensor de chama com uma divisão do campo de visão em 3 intervalos.
//Isto implica que o sensor devolve 3 direções possiveis para a posição da chama:
// 1 - a chama encontra-se à direita;
// 2 - a chama encontra-se ao centro;
// 3 - a chama encontra-se à esquerda.
//No caso do sensor não detetar a chama, o valor da direção é -1.
RBFlameSensor sensorChama(3); 

int xChama;    //Coordenada x da chama no campo de visão do sensor.
int yChama;    //Coordenada x da chama no campo de visão do sensor.
bool haChama;  //Flag que indica a presença de chama.
int dirChama;  //Direção da chama em relação ao sensor.

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.noAutoscroll();
  lcd.home();
  lcd.print("Sensor Chama");

  sensorChama.init();  //Inicializa parametros internos do sensor de chama.
}

void loop() {
  haChama = sensorChama.update(xChama, yChama);
  dirChama = sensorChama.getDir();
  mostrarDadosChama();
}

//Escreve "1" ou "0" no caso da chama ter sido ou não detectada, 
//seguida das coodenadas X, Y e da direção da chama (da fonte de IV).
//No caso da chama não ser detetada, as coordenadas são iguas a 1023 e a 
//direção é iguala -1.   
void mostrarDadosChama() {
  lcd.setCursor(0, 1);
  if(haChama)
    lcd.print("1 ");
  else  
    lcd.print("0 ");
  if (xChama < 1000)
    lcd.print(" ");
  if (xChama < 100)
    lcd.print(" ");
  if (xChama < 10)
    lcd.print(" ");
  lcd.print(xChama, DEC);
  lcd.print(",");
  if (yChama < 1000)
    lcd.print(" ");
  if (yChama < 100)
    lcd.print(" ");
  if (yChama < 10)
    lcd.print(" ");
  lcd.print(yChama, DEC);
  lcd.print(",");
  if (dirChama < 10)
    lcd.print(" ");
  lcd.print(dirChama, DEC);
  lcd.print(" ");
}

Acessórios para o Kit RB1

Pack Energia de 7.4V e 4000mA

Este Pack Energia é uma excelente alternativa ao pack de 4 pilhas AA do kit RB1, permitindo aumentar significativamente a potência dos motores e o tempo de autonomia do robô.

Conteúdo do pack:

  • 2 x Bateria recarregável 18650 de 3.7V e 4000mA
  • 1 caixa para 2 baterias 18650
  • 1 carregador para 2 baterias 18650

Shaft Encoders

Estes sensores medem o deslocamento angular das rodas do robô, permitindo medir facilmente que distância é que o robô já percorreu ou que ângulo já rodou.

Cabo de Alimentação Externa para a Ventoinha

A disponibilizar em breve.

Barra para Bumpers

A barra para os bumpers aumenta o perímetro de detecção de colisão, melhorando significativamente a eficácia destes sensores.

rb1_docs.txt · Esta página foi modificada pela última vez em: 2017/02/06 10:02 por ccarreto
Recent changes RSS feed Creative Commons License Donate Minima Template by Wikidesign Driven by DokuWiki