Sie sind auf Seite 1von 35

CURSO DE ENGENHARIA MECNICA

Sistemas Mecatrnicos

Proponente:

Agosto de 2015

Resumo
O presente trabalho apresenta a leitura, analise e descrio de trs diferentes relatrios
de trs grupos de alunos que, ao longo da disciplina de Sistemas Mecatrnicos,
desenvolveram um projeto, desde a concepo at a construo, de sistemas robticos
utilizando a plataforma de prototipagem eletrnica conhecida como Arduino. Ser explicado
com detralhes a programao utilizada nos referidos relatrios.

1. Introduo
Arduino uma plataforma de prototipagem eletrnica, criada por Massimo Banzi e David
Cuartielles em 2005 com objetivo de permitir o desenvolvimento de controle de sistemas
interativos, de baixo custo e acessvel a todos.
O projeto foi criado pensando em artistas e amadores, ou seja, no necessrio ter
conhecimentos prvios em eletrnica ou programao para iniciar-se no mundo Arduino.
Com o Arduino possvel tambm enviar e receber informaes de praticamente qualquer outro
sistema eletrnico. Desta forma possvel contruir por exemplo, um sistema de captao de
dados de sensores, como temperatura, iluminao, processar e enviar esses dados para um
sistema remoto por exemplo. Outra caracterstica importante que todo material (software,
bibliotecas, hardware) open-source, ou seja, pode ser reproduzido e usado por todos sem a
necessidade de pagamento de royalties ou direitos autorais.
A plataforma composta essencialmente de duas partes: O Hardware e o Software.

Arduino uno
Resumidamente o hardware uma placa eletrnica que possui todos componentes necessrios
para a maioria dos projetos e contm uma eletrnica que permite usar a placa com diversas
fontes de energia, baterias e fontes de alimentao. O hardware tambm permite o acoplamento
de circuitos externos atravs de pinos de conexo em posies padronizadas.
J com relao ao software, o Arduino um compilador gcc (C e C++) baseado em Wiring e
que usa uma interface grfica contruda em Java baseado no projeto Processing. Tudo isso
resume-se a um programa IDE (ambiente de desenvolvimento integrado) muito simples de usar e
de estender com bibliotecas que podem ser facilmente encontradas na internet.

Ambiente de desenvolvimento do Arduino


Depois de criar o programa e compilar usando a IDE, o cdigo gerado enviado para a placa
onde gravado dentro do chip controlador. Esse software que roda na placa chama-se
FIRMWARE. As funes da IDE do Arduino so basicamente duas: Permitir o desenvolvimento
de um software e envi-lo placa para que possa ser executado.

2. Objetivos

Ler o relatrio de cada um dos trs grupos de projeto.


Entender o cdigo.
Escrever um texto explicando ** passo a passo ** como e porque o cdigo fonte
(programa) do Arduino funciona. Sempre que tiver entradas e sadas, explicar a que
entradas e sadas o cdigo est relacionado.

3. Desenvolvimento
O desenvolvimento ser apresentado mostrando-se os trechos da programao de cada grupo
com a explicao logo abaixo.
3.1. Grupo Guilherme Leal/Pablo/Veiga/Isabella (carro)
#include <waypointClass.h>
#include <TinyGPS.h> // biblioteca para gps
#include <Wire.h>
#include "DualVNH5019MotorShield.h"
#include <TinyGPS.h>
#define HMC5883_WriteAddress 0x1E // i.e 0x3C >> 1
#define HMC5883_ModeRegisterAddress 0x02
#define HMC5883_ContinuousModeCommand 0x00
Essa parte responsvel pelo cdigo de bssola.
#define HMC5883_DataOutputXMSBAddress 0x03
TinyGPS gps;
// Waypoints
#define WAYPOINT_DIST_TOLERANE 5
#define NUMBER_WAYPOINTS 3
int waypointNumber = 0;
waypointClass

waypointList[NUMBER_WAYPOINTS]

{waypointClass(-47.878017,-

21.981077), waypointClass(-50, -21.981027), waypointClass(-47.877681, -21.981027)};


int targetHeading;
float flat,
flon,
targetLat,
targetLong;
int distanceToTarget,

// current distance to target (current waypoint)

originalDistanceToTarget;
int distanceToWaypoint(void) ;
float angle;
float erro;
5

DualVNH5019MotorShield md; // ESCUDO DO MOTOR


int k=0;
char c;
int regb=0x01;
int regbdata=0x40;
Essas variveis so responsveis pela bussola
int outputData[6];
void stopIfFault()
Void usado para declaraes de funes, neste caso usado para contorlar o motor em caso do
carro no seguir a condio.
{
if (md.getM1Fault())
{
Serial.println("M1 fault");
Para monitorar os erros do motor, utiliza-se if e while.
If(condio) { cdigo },ou seja, se a condio for verdadeira o programa realiza o cdigo.
while(1);
}
if (md.getM2Fault())
{
Serial.println("M2 fault");
while(1);
}
}
Essa parte anterior com programao condicional apresenta o cdigo para que o robo siga a
linha
void setup()
{
Serial.begin(115200);
6

Serial1.begin(38400);
Serial.begin(9600);
Serial.print("Lets

start

the

show!

Run,

Barry

Run

!");

//Serial.println(TinyGPS::library_version());
Serial.println();
Wire.begin();
Inicia a biblioteca Wire para fazer parte da I2C bus (faz parte da bssola).
A funo void setup() funciona como uma funo de inicializao, o que estar contido nela
rodar apenas uma vez no programa.
Na comunicao serial, possvel obter todos os dados que o Arduino est gerando ou
recebendo e enviar ao computador para simplesmente analisar os dados ou rodar algum outro
programa.
Iniciou-se a comunicao serial com a funo "Serial.begin(taxa); cada dispositivo
configurado para receber uma taxa de bits especfica (9600 a taxa do computador) a funo
"Serial.print" Envia dados para a porta serial como texto legvel ASII.
void loop() {
Os procedimentos colocados nessa funo so realizados mais de uma vez em forma de
looping.
int sE=digitalRead(31);
int sD=digitalRead(37);
So declaradas as variveis sE e sD (sensores ticos). DigitalRead um cdigo para configurar
portas digitais como entrada, no caso as portas 31 e 37, portanto o que for lido nas portas 31 e 37
ser considerado como sE e sD respectivamente.
if((sE == 0) && (sD == 0)){
int i = 45;
int j = 35 ;
7

md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
}
else if((sE == 1) && (sD == 0)){
int i = -45;
int j = 45 ;
md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
}
else if((sE == 0) && (sD == 1)){
int i = 45;
int j = -45 ;
md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
}
else if((sE ==1) && (sD == 1)){
int i=0;
md.setM1Speed(i);
md.setM2Speed(i);
stopIfFault();
k=1;
}
Todo o fragmento anterior em que foi usada a estrutura condicional if e else quer dizer que
dependendo do valor de sE e sD as variveis i e j sero os valores declarados em int e portanto
ser executado cdigo md.setM1Speed(i) e md.setM2Speed(j) e ao final de cada condio, h a
8

funo stopIfFault() para haver o controle de possveis erros. Todo esse fragmento representa a
programao do seguidor de linhas ( sE o sensor tico da eireita e sD o da direita) cada
condio mostrada a condio imposta para o funcionamento dos motores. por exemplo na
condio 1 que o primeiro if. Se ambos os sensores mostrarem valor binrio zero ( o que
significa que os sensores no esto captando nenhuma linha) as velodidades dos motores
( md.setM1Speed()) so ditadas pelas veriveis i e j, no caso 45 e35.
while (k==1){
A varivel k foi definida anteriormente como sendo zero, esse while coloca uma condio
quando o k fica com valor 1 , inicia-se a bussola.
int i,x,y,z;
Declaradas as variveis
double angle;
A varivel double assim como float tambm utilizada para valores de ponto flutuante, no
caso o ngulo.
Wire.beginTransmission(HMC5883_WriteAddress);
Wire.write(regb);
Wire.write(regbdata);
Wire.endTransmission();
// delay(100);
Wire.beginTransmission(HMC5883_WriteAddress); //Initiate a transmission with HMC5883
(Write address).
Wire.write(HMC5883_ModeRegisterAddress);

//Place the Mode Register Address in send-

buffer.
Wire.write(HMC5883_ContinuousModeCommand);

//Place the command for Continuous

operation Mode in send-buffer.


Wire.endTransmission();

//Send the send-buffer to HMC5883 and end the I2C

transmission.
//delay(100);
9

Wire.beginTransmission(HMC5883_WriteAddress); //Initiate a transmission with HMC5883


(Write address).
Wire.requestFrom(HMC5883_WriteAddress,6);

//Request 6 bytes of data from the address

specified.

// delay(100);

//Read the value of magnetic components X,Y and Z


if(6 <= Wire.available()) // If the number of bytes available for reading be <=6.
{

for(i=0;i<6;i++)
{
outputData[i]=Wire.read(); //Store the data in outputData buffer
}
}
x=outputData[0] << 8 | outputData[1]; //Combine MSB and LSB of X Data output register
z=outputData[2] << 8 | outputData[3]; //Combine MSB and LSB of Z Data output register
y=outputData[4] << 8 | outputData[5]; //Combine MSB and LSB of Y Data output register
/* Serial.print(" y ");
Serial.println(y);
Serial.print(" x ");
Serial.println(x);
Serial.print("z ");
Serial.println(z);*/
y = (double)y;
x=(double)x;
z=atan2((double)y,(double)x);
10

angle= (atan2((double)y,(double)x)) * (180 / 3.14159265)+180 ; // angle in degrees


Todo os comandos acima so parte de um cdigo que serve para gerar uma bssola no robo.
bool newData = false;
Varivel booleana que s aceita valores de verdadeiro ou falso.
unsigned long chars;
Unsigned long aceita apenas valoes de variveis positivos.
unsigned short sentences, failed;
// For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (Serial1.available())
{
char c = Serial1.read();
//Serial.write(c); // uncomment this line if you want to see the GPS data flowing
if (gps.encode(c)) // Did a new valid sentence come in?
newData = true;
float flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon, &age);
gps.stats(&chars, &sentences, &failed);
/*Serial.print(" CHARS=");
Serial.print(chars);
Serial.print(" SENTENCES=");
Serial.print(sentences);
Serial.print(" CSUM ERR=");
Serial.println(failed);*/
if (chars == 0)
Serial.println("** No characters received from GPS: check wiring **");
11

Quando nenhum dado encontrado a funo Serial.printIn mostra na tela o aviso "** No
characters received from GPS: check wiring **".
targetLat = waypointList[waypointNumber].getLat();
targetLong = waypointList[waypointNumber].getLong();
Serial.print("Latitude Atual: ");
Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
Serial.print (" Latitude do Waypoint: ");
Serial.println (targetLat,6);
Serial.print(" Longitude Atual: ");
Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
Serial.print (" Longitude do Waypoint: ");
Serial.println (targetLong,6);
Serial.print (" Angulo Atual: ");
Serial.println(angle);
Serial.print(" Angulo Alvo: ");
Serial.println(targetHeading);
Caso o GPS receba algum dado, ele envia para o serial monitor os valores da latitude e
longitude e armazena esses dados.
Abaixo comea o sistema de navegao:
targetHeading=courseToWaypoint();
float erro=targetHeading-angle;
distanceToWaypoint() ;
if (erro < -180)
erro += 360;
if (erro > 180)
erro -= 360;
Serial.print (" Erro: ");
Serial.println (erro);
12

if ((erro>0) && (erro>20)){


int i = 50;
int j = -50 ;
md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
}
else if ((erro<0) && (erro<-20)){
int i = -50;
int j = 50 ;
md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
}
else if (( erro <= 20 ) || (erro >= -20)){
int i = 50 ;
int j = 55 ;
md.setM1Speed(i);
md.setM2Speed(j);
stopIfFault();
Essas condies servem para corrigir erros de sentido. faz com que o robo vire para a direo
correta.
void nextWaypoint(void)
{
waypointNumber++;
targetLat = waypointList[waypointNumber].getLat();
13

targetLong = waypointList[waypointNumber].getLong();
if (waypointNumber >= NUMBER_WAYPOINTS)

// last waypoint reached?

{
md.setM1Speed(0);
md.setM2Speed(0);
stopIfFault();
while (1);
}
distanceToTarget = originalDistanceToTarget = distanceToWaypoint();
int distanceToWaypoint()
{
float delta = radians(flon );
float sdlong = sin(delta);
float cdlong = cos(delta);
float lat1 = radians(flat);
float lat2 = radians(targetLat);
float slat1 = sin(lat1);
float clat1 = cos(lat1);
float slat2 = sin(lat2);
float clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = sq(delta);
delta += sq(clat2 * sdlong);
delta = sqrt(delta);
float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
distanceToTarget = delta * 6372795;
if (abs(distanceToTarget )<= WAYPOINT_DIST_TOLERANE)
nextWaypoint();
Serial.print ("Distancia : ");
Serial.println (distanceToTarget);
return distanceToTarget;
14

}
int courseToWaypoint()
{
float dlon = radians(targetLong-flon);
float cLat = radians(flat);
float tLat = radians(targetLat);
float a1 = sin(dlon) * cos(tLat);
float a2 = sin(cLat) * cos(tLat) * cos(dlon);
a2 = cos(cLat) * sin(tLat) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
targetHeading = degrees(a2);
return targetHeading;
}
Por fim, nesse ltimo fragmento de programao, definido como o rob vai atingir os
pontos desejados. So utilizadas formulas de geometrias para serem obtidas as distncias.
3.2. Grupo Marcos Brasil/Evandro/Rafael (rob Scara)
// interface serial: enviar 3 valores
// (posicao1,posicao2,posicao3) (motor1, motor2, servo)
#include <Encoder.h> //BIBLIOTECA DO ENCODER
#include <Servo.h> //BIBLIOTECA DO SERVO
#include <math.h>
#define MAX 3
#define MIN(A,B) (((A)<(B))?(A):(B))
#define MAXI(A,B) (((A)>(B))?(A):(B))
Foram definidas as bibliotecas.
Servo myservo;
int IN1 = 44; // motor 1
int IN2 = 34; // motor 1
int IN3 = 35; // motor 2
int IN4 = 45; // motor 2

15

Foram definidas as variveis correspondentes ao motor 1 e 2 e seus respectivos pinos, no


caso, 44 34 35 45. Esses pinos so referentes aos fios que saem do motor e so frequentemente
ligados ao arduino usando-se uma ponte-h. As pontes-H geralmente so utilizadas no controle da
direo e velocidade de giro de motores.
int ENA = 8; // pwm motor 1
int ENB = 9; // pwm motor 2
As duas variveis acima posicionadas nos pinos oito e nove representam as sadas digitais
PWM que comandar o giro tanto do motor quanto dos servos.
int canal1 = 18; // encoder 1 canal A
int canal2 = 19; // encoder 1 canal B
int canal3 = 20; // encoder 2 canal A
int canal4 = 21; // encoder 2 canal B
O encoder um sensor que converte um movimento angular ou linear em uma srie de pulsos
digitais eltricos podendo assim traduzir o movimento do motor em ngulos ou mesmo em
distncia atraves da cinemtica. O encoder incremental fornece normalmente dois pulsos
quadrados defasados em 90, que so chamados usualmente de canal A e canal B. A leitura de
somente um canal fornece apenas a velocidade, enquanto que a leitura dos dois canais fornece
tambm o sentido do movimento.
Acima pode ser visto a declarao das variveis dos encoders com seus respectivos pinos.
unsigned int sensor1 = 53; // fim de curso 1
unsigned int sensor2 = 51; // fim de curso 2
Declarao das variveis referentes aos sensores de fim de curso com seus pinos. Foi usado o
tipo de varivel "unsigned int ". A varivel int pode armazenar 2 bytes (16 bits), ou seja, pode
guardar 2^16 - 1 valores diferentes ( 0 a 65535) incluindo valores negativos para obter apenas os
positivos tem de ser usado o tipo de varivel "unsigned".
long erro1; // erro 1
long erro2; // erro 2
long V1; //velocidade 1
long V2; //velocidade 2
Ser realizado um controle proporcional em malha fechada, o que significa que os erros daro
subsdios para o controle acontecer. Por isso foram declaradas as variveis erro. Tanto os erros de
cada motor quanto a veloidade foram declaradas usando-se o tipo de varivel "long". Ela usada
quando deseja-se nmeros maiores que os outros tipos de varveis podem armazenar evitando
assim overflow. 2^32 - 1 (o 2 vem do fato de serem valores binarios 1 e 0).
char buffer[10];
int bufferIndex;
O tipo "char" serve para armazenar UM, e somente UM, caractere. Usa-se a varivel char para
ler bytes.
No caso acima, deseja-se criar um buffer na memria do arduino que : uma parte da memria
de um computador que reservada como um local de armazenamento temporrio para dados que

16

esto sendo enviadas ou recebidas a partir de um dispositivo externo. O tamanho do buffer seria
de 10 bytes neste caso.
char caracter;
long posicao1;
long posicao2;
float posicaoq21;
float posicaoq22;
float posicaoq11;
float posicaoq12;
Variaveis declaradas sem um valor prvio com relao s posies dos motores e do braos
segundo a cinemtica.
long val;
float a1;
float a2;
Varivel para o comprimento dos braos do robo a1 e a2
bool dadoPronto = false;
Varivel booleana aceita apenas dois valores: verdadeiro e falso. Cada varivel booleana
ocupa 1 bit de memria.
int dadosRecebidos = 0;
float valoresRecebidos[MAX];
int posicaoRecebidos = 0;
Encoder Enc1(canal1, canal2);
Encoder Enc2(canal3, canal4);
Foram definidos os canais do encoder dos motores. A biblioteca Encoder monitora os 2 pinos e
atualiza uma contagem da mudana relativa na posio. A biblioteca atualiza sua contagem em
cada mudana que muitas vezes chamado de 4X contando, desde 4 contagens esto disponveis
para cada marca fsica ou buraco no hardware.
const float reducao = 17.442;
// Pulsos/ da saida
const float Kp1 = .3; //constante proporcional1
const float Kp2 = .2; //constante proporcional2
long a;
Segundo o relatrio: Como o rob possui uma inrcia e velocidade, ao chegar no valor este
acaba passando do ponto desejado, fazendo com que o erro mude o sinal e fazendo com que o
motor gire no sentido oposto, fazendo novamente que o brao passe do ponto desejado, repetindo
o ciclo. Para solucionar este problema foi criada uma constante Kp que ser multiplicada pelo
erro
void setup() {
17

A funo "setup ()" acionada quando um esboo comea. usada para inicializar variveis ,
modos de pino , comear a usar as bibliotecas , etc.
O procedimento ser executado apenas uma vez, aps cada inicializao ou reset do Arduino.
O "void" significa nada, ou seja, este procedimento no retorna nada. Isso no significa que ele
no faz nada, apenas que ele no tem um nmero tangvel ou qualquer outra coisa , para mostrar
quando o procedimento se completa).
pinMode(sensor1, INPUT_PULLUP);
pinMode(sensor2, INPUT_PULLUP);
Usa-se a afirmao "pinMode" para definir se um pino ser fisicamente usado como uma
sada ou como uma entrada. No caso, os pinos dos sensores 1 e 2 so usados como entradas e
ainda em PULLUP que significa que na montagem h um resistor entre o sensor e a alimentao
de 5V.
Serial.begin(115200);
Esse procedimento inicia uma comunicao serial. A comunicao serial (UART) na
plataforma Arduino um recurso que possibilita a comunicao entre a placa e um computador
ou entre a placa e outro dispositivo. atravs desse canal que realizado o upload do cdigo
para a placa. Nesse caso a comunicao se d uma taxa de 115200 bits.
a1 = 80;
a2 = 145;
Foram definidos os comprimentos dos braos do rob.
myservo.attach(46);
Anexar a varivel cervo a um pino, no caso o 46.
bufferIndex = 0;
Quantidade de espao de memria utilizado inicialmente.
pinMode(34, OUTPUT);
pinMode(44, OUTPUT);
pinMode(35, OUTPUT);
pinMode(45, OUTPUT);
start ();
}
Utilizao do pinMode para definir os pinos dos motores como sadas. O procedimento "start"
est chamando uma sub rotina explicitada em void mais a frente.
void loop() {
lePortaSerial();
O comando acima est chamando uma sub rotina que declarada e explicitada em void mais a
frente.
18

val = valoresRecebidos[2];
1023)

// reads the value of the potentiometer (value between 0 and

L o valor dado pelo potencimetro e o armazena na varivel val.


val = map(val, 0, 100, 20, 90);

// scale it to use it with the servo (value between 0 and 180)

Modifica de um interevalo de nmeros para outro intervalo mais conveniente, no caso de 0a


100 para 20 a 90.
myservo.write(val);
delay(15);

// sets the servo position according to the scaled value

Esse delay serve para esperar o posicionamento do servo.


//atualiza motor 1
posicao1 = Enc1.read();
Faz a leitura da varivel "Enc1" e a armazena na posio 1.
posicaoq21 = acos((valoresRecebidos[0] * valoresRecebidos[0] + valoresRecebidos[1] *
valoresRecebidos[1] - a1 * a1 - a2 * a2) / (2 * a1 * a2));
posicaoq22 = posicaoq21 * (57.296);
posicaoq11 = atan2(valoresRecebidos[1], valoresRecebidos[0]) - atan2((a2 * sin(posicaoq21)),
(a1 + a2 * cos(posicaoq21)));
posicaoq12 = posicaoq11 * (57.296);
Para a atualizao da posio do motor 1, foram utilizadas as equaes trigonomtricas
provenientes da cinemtica.
erro1 = (posicaoq12 * reducao * 4) - posicao1 + 69;
V1 = MIN(100, abs(erro1) * Kp1);
V1 = MAXI(55, V1);
selecionado o menor valor como velocidade. Porm como esta distncia diminui com o
tempo, ao chegar prximo do ponto desejado, o valor de velocidade ser diminudo, assim
necessrio criar uma segunda condio onde o valor de velocidade selecionada tem que ser o
maior valor entre o valor da multiplicao e 80, pois abaixo de 80 o motor no possui energia
suficiente para vencer a inrcia e atrito do sistema.
if ( erro1 > 0 ) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, (V1));
}
if (erro1 < 0) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
19

analogWrite(ENA, (V1));
}
O procedimento condicional serve nesse caso para, dependendo do valor do erro, enviar
comandos para o motor e gir-lo na direo certa e com a velocidade certa.
O procedimento digitalWrite envia informao para a entrada digital (pino chamado de INx
nesse programa em especfico), no caso do motor fazendo-o funcionar ou no com o HIGH e
LOW.
O procedimento analogWrite faz a mesma coisa que o digital mas para a sada ENA e
aplicando a velocidade V1 no motor.
//atualiza motor 2
posicao2 = Enc2.read();
erro2 = (posicaoq22 * reducao * 4) - posicao2 - 69;
V2 = MIN(200, abs(erro2) * Kp2);
V2 = MAXI(48, V2);
if ( erro2 > 0 ) {
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, abs(V2));
}
if (erro2 < 0) {
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, abs(V2));
}
//if(erro2 == 0){ //teoricamente no precisa
// digitalWrite(IN3,LOW);
//digitalWrite(IN4,LOW);
//}
A mesma coisa do motor 1 realizada para o motor 2.
if (dadoPronto) {
Serial.print("Dados recebidos: ");
Serial.println(dadosRecebidos);
}
Se houverem dados prontos disponveis so plotados na tela os dados recebidos.
dadoPronto = false;
dadosRecebidos = 0;
//retorna posio atual e erro
Serial.print(digitalRead(sensor1));
Serial.print(",");
Serial.print(posicao1);
Serial.print(",");
Serial.print(erro1);
Serial.print(",");
Serial.print(posicao2);
20

Serial.print(",");
Serial.print(erro2);
Serial.print(",");
Serial.print(V1);
Serial.print(",");
Serial.println(V2);
}
A funo serial print serve para tornar os dados em dados legveis na tela do computador.
void lePortaSerial() {
while (Serial.available() > 0) {
caracter = Serial.read();
Essa sub-rotina define que quando h disponveis valores seriais, esses valores lidos so
armazenados como a varivel caracter.
if (((caracter >= '0') && (caracter <= '9')) || (caracter == '-')) {
buffer[bufferIndex] = caracter;
bufferIndex++;
}
else
{
if ((caracter == ',') && (buffer > 0) && (posicaoRecebidos < MAX)) {
buffer[bufferIndex] = 0;
valoresRecebidos[posicaoRecebidos] = atoi(buffer);
posicaoRecebidos++;
bufferIndex = 0;
}
if (caracter == '\n') {
if ((buffer > 0) && (posicaoRecebidos < MAX)) {
buffer[bufferIndex] = 0;
valoresRecebidos[posicaoRecebidos] = atoi(buffer);
}
bufferIndex = 0;
dadosRecebidos = posicaoRecebidos + 1;
posicaoRecebidos = 0;
Serial.println("----");
for (int i = 0; i < MAX; i++) {
Serial.print("valor[");
Serial.print(i);
Serial.print("] = ");
Serial.println(valoresRecebidos[i]);
}
dadoPronto = true;
}
}
}
}
21

A partir dos condicionais acima analisada o estado da varivel caracter e do espao


reservado de memria buffer para no fim gerar o valor para a variavel "valoresRecebidos".
void start () {
Segundo o relatrio foi criada uma subrotina na qual solicitado mover manualmente o brao
at que seja ativado por meio do rasgo feito no brao, para isto o sensor ligado como
normalmente fechado e quando a haste do boto se encaixa neste rasgo ele envia um sinal,
atribuindo ngulos conhecidos nestas posies.
Serial.println("--------------------------------");
Serial.println("-----------Modo Manual----------");
Serial.println("--------------------------------");
while ((digitalRead(sensor1) == 0)) {
Quando o sensor ligado e est fechado na posio inicial como dito no relatrio, a leitura na
porta digital de sada 0 com relao varivel sensor1. Isso significa que tem que mexer o
eixo1 para a identificao das posies.
Serial.print("---------mova eixo 1------------ ");
Serial.print(digitalRead(sensor1));
Serial.print(", ");
Serial.println(posicao1);
So plotados o comando de mexer e a posio gerada na sada digital ao mover o eixo.
delay(100);
posicao1 = Enc1.read();
if (digitalRead(sensor1) == 1) {
Enc1.write(3400);
erro1 = 0;
Quando o estado do sensor 1 torna-se 1 por que est posicionado e identificado o
posicionamento.
}
}
while ((digitalRead(sensor2) == 0)) {
Serial.println("---------------------------------");
Serial.print("----------mova eixo 2------------ ");
Serial.print(digitalRead(sensor2));
Serial.print(", ");
Serial.println(posicao2);
delay(100);
posicao2 = Enc2.read();
if (digitalRead(sensor2) == 1) {
22

Enc2.write(-9100);
erro2 = 0;
}
}
A mesma coisa acontece com o sensor e eixo 2
valoresRecebidos[0] = 225;
valoresRecebidos[1] = 0;
valoresRecebidos[2] = 100;
Serial.println("--------------------------------");
Serial.println("-------Origem Reconhecida-------");
Serial.println("-333333333333333333333333333333-");
delay(500);
Serial.println("-222222222222222222222222222222-");
delay(500);
Serial.println("-111111111111111111111111111111-");
delay(500);
}
Ao final do posicionamento o programa avisa que a origem conhecida e pode-se continuar

3.3. Grupo Heitor/Helena/Mauro


#include <PID_v1.h>
#include <Encoder.h>
#include <Servo.h>
#include <SPI.h>
#include <Ethernet.h>
Foram registradas as bibliotecas de controle PID, do Encoder, dos servos, do serial peripheral
inteface (SPI) e library de coneo com a internet.
Serial Peripheral Interface (SPI) um protocolo de dados em srie sncrona usado por
microcontroladores para comunicar com um ou mais dispositivos perifricos rapidamente ao
longo de distncias curtas. Ele tambm pode ser usado para comunicao entre dois
microcontroladores. Um controlador PID calcula um valor de "erro" como a diferena entre a
medida [INPUT] e um ponto de ajuste desejado. O controlador tenta minimizar o erro ajustando
[OUTPUT]
byte mac[] = { // MAC address from Ethernet shield sticker under board
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
23

O MAC ( Media Access Control ) o endereo de hardware de seu escudo de ethernet para o
dispositivo (array de 6 bytes).
IPAddress ip(192, 168, 1, 3); // IP address, may need to change depending on network
EthernetServer server(80); // create a server at port 80
So declaradas as duas constantes anteriores cujo significado j foi explicaod em comentrio.
String HTTP_req; // stores the HTTP request
char angulo0[3], angulo1[3], angulo2[3], caracter;
int i = 0, j = 0, k = 0;
boolean pega0 = 0, pega1 = 0, pega2 = 0;
Definem-se algumas variveis e seus valores.
#define IN1 6 // -> Porta onde vai o fio amarelo (que vem da ponte H) do motor 1
#define IN2 7 // -> Porta onde vai o fio laranja (que vem da ponte H) do motor 1
#define ENA 5 // -> Porta onde vai o fio verde (que vem da ponte H) do motor 1
#define IN3 8 // -> Porta onde vai o fio amarelo (que vem da ponte H) do motor 2
#define IN4 9 // -> Porta onde vai o fio laranja (que vem da ponte H) do motor 2
#define ENB 4 // -> Porta onde vai o fio verde (que vem da ponte H) do motor 2
Foi utilizada uma ponte H, muito utilizada para controle de direo e velocidade de giro de
motores eltricos. Foram definidas cada uma portas referentes ao motor.
#define SER 44 // -> Porta onde vai o servo
#define FDC 20 // -> Porta onde vai o sensor de fim de curso
#define SOT 21 // -> Porta onde vai o sensor tico
#define Batente 180 // -> Limite para a posio do motor 1 []
#define Batente2 90 // -> Limite para a posio do motor 2 []
Encoder Enc1(19,18); // -> Portas onde vo os fios branco e verde do Encoder 1
Encoder Enc2(3,2); // -> Portas onde vo os fios branco e verde do Encoder 2
24

Assim como o grupo "Marcos", tambm foi usado motores com encoders acoplados.
double LimDir = 0, LimEsq = 0, Zero = 0;
Definidas variveis de limite.
Servo servo;
Chamada para a varivel servo da biblioteca.
#define interval 500 // -> Intervalo para o print das informaes [ms]
long previousMillis = 0; // -> Varivel auxiliar para definir o instante do print
#define LIM1 200 // -> Limite do Output do motor 1 [0,255]
#define LIM2 200 // -> Limite do Output do motor 2 [0,255]
#define MAX 3 // -> Nmero de dados recebidos pelo Serial
Os trs ltimos define referem-se velocidade dos motores.
//int valoresRecebidos[MAX];
int ang0 = 0, ang1 = 0, ang2 = 0;
double Setpoint1 = 0, Input1, Output1 = 0;
double Setpoint2 = 0, Input2, Output2 = 0;
#define MIN 1
#define Kp1 4.5 // -> Ganho proporcional
#define Ki1 0.6 // -> Ganho integral
#define Kd1 0.5 // -> Ganho derivativo
#define Kp2 5 // -> Ganho proporcional
#define Ki2 0.4 // -> Ganho integral
#define Kd2 0.35 // -> Ganho derivativo
PID PID1(&Input1, &Output1, &Setpoint1, Kp1, Ki1, Kd1, DIRECT);
PID PID2(&Input2, &Output2, &Setpoint2, Kp2, Ki2, Kd2, DIRECT);

25

Segundo o relatrio do grupo, A leitura dos encoders pode ser variada com um valor inicial
desejado, ou seja, um setpoint inicial, ou por alterao por uma influncia externa. Um valor de
Output lido dos encoders por meio de uma rotina presente na biblioteca. Assim como o grupo
citado anteriormente, a atuao do encoder facilita o controle proporcional pois cria parmetros
que podem ser comparados com os parmetros dos setpoints e assim encontram-se os erros e
pode-se fazer o controle. Novamente esse erro no zero o que gera a necessidade do controle
PID e assim a utilizao da biblioteca PID para obteno dos ganhos. Esses ganhos foram
definidos acima assim como a chamada para o controle PID.
void setup() {
Ethernet.begin(mac, ip); // initialize Ethernet device
server.begin();

// start to listen for clients

Diz ao servidor para comear captar as conexes que chegarem.


Serial.begin(9600);
Comunicao serial com transmisso de 9600 bps
Enc1.write(0);
Enc2.write(0);
servo.attach(SER, 544, 2400);
Anexa um servo disponvel a um pino. No caso o Pino o identificado pela varivel SER
declarada anteriormente e ainda mostra os limites de MIN (544) que corresponde a largura do
pulso , em microssegundos , o que corresponde a um mnimo (0 graus) de ngulo sobre o servo e
um mximo de 180 graus (2400).
servo.write(90);
Grava um valor para o servo. Em um servo padro , isto vai definir o ngulo do eixo (em
graus),movendo-se o eixo para a orientao desejada.
No caso o ngulo de 90 Graus.

26

pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ENB, OUTPUT);
Define os pinos relativos aos motores como sadas, pois esses pinos enviam informao aos
motores.
pinMode(FDC, INPUT);
pinMode(SOT, INPUT);
Define-se os pinos dos dois sensores como entrada, pois recebe-se a informao vinda dos
sensores.
Serial.println("------- Setup -------");
Regulagem para posicionamento e leitura desse posicionamento dos braos. (Setup).
if(digitalRead(SOT) == 1) {
Se a entrada digital acusar valor 1 significa que o brao est sendo captado pelo sensor.
Serial.println("Mova o braco longe do sensor otico");
while(digitalRead(SOT) == 1) {
delay(50);
escrito na tela do computador para mover o brao para longe do sensor enquanto o seu calor
for 1 ou seja, estiver captando o brao.
}
}
Serial.println("Mova o braco ate o sensor otico");
while(digitalRead(SOT) == 0) {
27

delay(50);
}
Enc1.write(0);
Serial.println("Encoste o braco no sensor da direita");
// Comeo da rotina da calibrao
while(digitalRead(FDC) == 1) {
LimDir = Enc2.read();
H um comando para o operador encostar o brao do rob no sensor da direita com isso a
entrada digital acusa 1 e assim pode-se registrar o valor lido pelo encoder na varivel LimDir
}
Serial.println(LimDir);
delay(500);
while(digitalRead(FDC) == 0) {
Quando o valor acusado 1, pode-se voltar o brao para o meio para iniciar a calibrao para
o outro lado.
Serial.println("Volte para o meio");
delay(500);
}
Serial.println("Encoste o brao no sensor da esquerda");
while(digitalRead(FDC) == 1) {
LimEsq = Enc2.read();
//NOvamente registrado o valor de distncia para uma varivel, no caso LimEsq, lido pelo
encoder.
}
Enc2.write((LimEsq-LimDir)/2);
Serial.println(LimEsq);
28

LimDir = ((abs(LimDir-LimEsq)/2)*360)/(334*75.0);
LimEsq = -LimDir;
Serial.println(LimDir);
Serial.println(LimEsq); // -> Fim da rotina de calibrao
Serial.setTimeout(10); // -> Tempo que a funo Serial.parseInt() leva para adquirir os dados
[ms]
PID1.SetOutputLimits(-LIM1, LIM1);
PID1.SetMode(AUTOMATIC);
PID2.SetOutputLimits(-LIM2, LIM2);
PID2.SetMode(AUTOMATIC);
Serial.println("------- Loop -------");
}
Ao final disso o rob est calibrado com as distncia permitidas para o movimento
registradas.
void loop() {
Rede();
lePortaSerial();
As duas chamadas acima so para subrotinas explicitadas mais abaixo no programa.
Input1 = ((Enc1.read()*360)/(334*75.0));
Setpoint1 = ang0;
Input2 = ((Enc2.read()*360)/(334*75.0));
Setpoint2 = ang1;
PID1.Compute();
PID2.Compute();
if(digitalRead(FDC) == LOW) {
Output2 = 0;
}
if(Output1 < 0) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
29

analogWrite(ENA, abs(Output1));
Estabeleceu-se que para um valor negativo do Erro, o motor rotaciona com potncia mxima
(ENA) em um sentido.
}
else {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, abs(Output1));
}
if(Output2 < 0) {
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENB, abs(Output2));
}
//De forma anloga, um valor positivo no Erro resulta no motor rotacionando com potncia
mxima no sentido oposto.
else {
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(ENB, abs(Output2));
}
servo.write(ang2+90);
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Serial.print("Posicoes: ");
Serial.print(Input1);
Serial.print(" deg, ");
Serial.print(Input2);
Serial.print(" deg, ");
30

Serial.print("Pedidos: ");
Serial.print(Setpoint1);
Serial.print(" deg, ");
Serial.print(Setpoint2);
Serial.print(" deg, ");
Serial.print(ang2);
Serial.print(" deg, ");
Serial.print("Fim de curso: ");
Serial.print(digitalRead(FDC));
Serial.print(", ");
Serial.print("Torques: ");
Serial.print(Output1);
Serial.print(", ");
Serial.println(Output2);
}
}
Assim como no grupo anterior, o loop serve para controle do motor e dos servos. Utilizandose dos imputs e outputs gerados pelo controle PID pode-se dar os comandos necessrios aos
controladores, e assim mover o robo e ainda ao final registrar com o Serial.print todos os
parmetros que demonstram o estado do robo como angulos, velocidades, posies etc.
void lePortaSerial() {
Encontrar os ngulos respectivos no link URL recebido do browser, e trabalhar os dados para
que sirvam de entrada para o controle PID, que d o sinal para os atuadores.
while (Serial.available() > 0) {
if(pega0){
ang0 = Serial.parseInt();
Serial.print("Junta 1: ");
Serial.println(ang0);
pega0 = 0;
}
31

if(pega1){
ang1 = Serial.parseInt();
Serial.print("Junta 2: ");
Serial.println(ang1);
pega1 = 0;
}
if(pega2){
ang2 = Serial.parseInt();
Serial.print("Junta 3: ");
Serial.println(ang2);
pega2 = 0;
}
caracter = Serial.read();
if ((caracter == 'b') && (i==0)){
i++;
}
else if ((caracter == 'a') && (i==1))
i++;
else if ((caracter == 's') && (i==2))
i++;
else if ((caracter == 'e') && (i==3))
i++;
else if ((caracter == '=') &&(i==4)){
i++;
pega0 = 1;
i = 0;
}
if ((caracter == 'i') && (j==0)){
j++;
}
else if ((caracter == 'n') && (j==1))
j++;
else if ((caracter == 'k') && (j==2))
j++;
32

else if ((caracter == '1') && (j==3))


j++;
else if ((caracter == '=') &&(j==4)){
j++;
pega1 = 1;
j = 0;
}
if ((caracter == 'i') && (k==0)){
k++;
}
else if ((caracter == 'n') && (k==1)){
k++;
}
else if ((caracter == 'k') && (k==2)){
k++;
}
else if ((caracter == '2') && (k==3)){
k++;
}
else if ((caracter == '=') &&(k==4)){
k++;
pega2 = 1;
k = 0;
}
}
}

33

4. Referncias Bibliogrficas

http://www.ladyada.net/learn/arduino/
https://www.arduino.cc/

Aprendendo a Programar em Arduino, Instituto Federal de Educao Cincia e


Tecnologia de Mato Grosso - Campus Cuiab.
https://learn.adafruit.com/category/learn-arduino
http://www.embarcados.com.br/arduino-comunicacao-serial/
https://www.pjrc.com/teensy/td_libs_Encoder.html

34

Das könnte Ihnen auch gefallen