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.
- rbmotor.zip Biblioteca para controlar os motores das rodas.
- liquidcrystal_i2c.zip Biblioteca para escrever no LCD.
- NewPing Biblioteca para controlar os sensores SONAR.
- rbflamesensor.zip Biblioteca para controlar o sensor de chama.
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).
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
- print() Shows the text passed as a parameter starting at the current cursor position
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.