sistemas mecatrônicos arduino

45
CURSO DE ENGENHARIA MECÂNICA Sistemas Mecatrônicos Proponente:

Upload: gustavogfp

Post on 12-Dec-2015

221 views

Category:

Documents


1 download

DESCRIPTION

dicas e explicações sobre programaçao em arduino.

TRANSCRIPT

Page 1: Sistemas Mecatrônicos Arduino

CURSO DE ENGENHARIA MECÂNICA

Sistemas Mecatrônicos

Proponente:

Agosto de 2015

Page 2: Sistemas Mecatrônicos Arduino

Resumo

O presente trabalho apresenta a leitura, analise e descrição de três diferentes relatórios

de três grupos de alunos que, ao longo da disciplina de Sistemas Mecatrônicos,

desenvolveram um projeto, desde a concepção até a construção, de sistemas robóticos

utilizando a plataforma de prototipagem eletrônica conhecida como Arduino. Será explicado

com detralhes a programação utilizada nos referidos relatórios.

1

Page 3: Sistemas Mecatrônicos Arduino

1. Introdução

Arduino é uma plataforma de prototipagem eletrônica, criada por Massimo Banzi e David

Cuartielles em 2005 com objetivo de permitir o desenvolvimento de controle de sistemas

interativos, de baixo custo e acessível a todos.

O projeto foi criado pensando em artistas e amadores, ou seja, não é necessário ter

conhecimentos prévios em eletrônica ou programação para iniciar-se no mundo Arduino.

Com o Arduino é possível também enviar e receber informações de praticamente qualquer outro

sistema eletrônico. Desta forma é possível contruir por exemplo, um sistema de captação de

dados de sensores, como temperatura, iluminação, processar e enviar esses dados para um

sistema remoto por exemplo. Outra característica 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 eletrônica que possui todos componentes necessários

para a maioria dos projetos e contém uma eletrônica que permite usar a placa com diversas

fontes de energia, baterias e fontes de alimentação. O hardware também permite o acoplamento

de circuitos externos através de pinos de conexão em posições padronizadas.

Já com relação ao software, o Arduino é um compilador gcc (C e C++) baseado em Wiring e

que usa uma interface gráfica contruída 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.

2

Page 4: Sistemas Mecatrônicos Arduino

Ambiente de desenvolvimento do Arduino

Depois de criar o programa e compilar usando a IDE, o código gerado é enviado para a placa

onde é gravado dentro do chip controlador. Esse software que roda na placa chama-se

FIRMWARE. As funções da IDE do Arduino são basicamente duas: Permitir o desenvolvimento

de um software e enviá-lo à placa para que possa ser executado.

3

Page 5: Sistemas Mecatrônicos Arduino

2. Objetivos

Ler o relatório de cada um dos três grupos de projeto.

Entender o código.

Escrever um texto explicando ** passo a passo ** como e porque o código fonte

(programa) do Arduino funciona. Sempre que tiver entradas e saídas, explicar a que

entradas e saídas o código está relacionado.

4

Page 6: Sistemas Mecatrônicos Arduino

3. Desenvolvimento

O desenvolvimento será apresentado mostrando-se os trechos da programação de cada grupo com a explicação 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 é responsável pelo código de bússola.

#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

Page 7: Sistemas Mecatrônicos Arduino

DualVNH5019MotorShield md; // ESCUDO DO MOTOR

int k=0;

char c;

int regb=0x01;

int regbdata=0x40;

Essas variáveis são responsáveis pela bussola

int outputData[6];

void stopIfFault()

Void é usado para declarações de funções, neste caso usado para contorlar o motor em caso

do carro não seguir a condição.

{

if (md.getM1Fault())

{

Serial.println("M1 fault");

Para monitorar os erros do motor, utiliza-se if e while.

If(condição) { código },ou seja, se a condição for verdadeira o programa realiza o código.

while(1);

}

if (md.getM2Fault())

{

Serial.println("M2 fault");

while(1);

}

}

Essa parte anterior com programação condicional apresenta o código para que o robo siga a

linha

void setup()

{

Serial.begin(115200);

6

Page 8: Sistemas Mecatrônicos Arduino

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 bússola).

A função void setup() funciona como uma “função de inicialização”, o que estará contido nela

rodará apenas uma vez no programa.

Na comunicação serial, é possível 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 comunicação serial com a função "Serial.begin(taxa); cada dispositivo é

configurado para receber uma taxa de bits específica (9600 é a taxa do computador) a função

"Serial.print" Envia dados para a porta serial como texto legível ASII.

void loop() {

Os procedimentos colocados nessa função são realizados mais de uma vez em forma de

“looping”.

int sE=digitalRead(31);

int sD=digitalRead(37);

São declaradas as variáveis sE e sD (sensores óticos). DigitalRead é um código 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

Page 9: Sistemas Mecatrônicos Arduino

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 variáveis i e j serão os valores declarados em int e portanto

será executado código md.setM1Speed(i) e md.setM2Speed(j) e ao final de cada condição, há a

8

Page 10: Sistemas Mecatrônicos Arduino

função stopIfFault() para haver o controle de possíveis erros. Todo esse fragmento representa a

programação do seguidor de linhas ( sE é o sensor ótico da eireita e sD o da direita) cada

condição mostrada é a condição imposta para o funcionamento dos motores. por exemplo na

condição 1 que é o primeiro if. Se ambos os sensores mostrarem valor binário zero ( o que

significa que os sensores não estão captando nenhuma linha) as velodidades dos motores

( md.setM1Speed()) são ditadas pelas veriáveis i e j, no caso 45 e35.

while (k==1){

A variável k foi definida anteriormente como sendo zero, esse while coloca uma condição

quando o k fica com valor 1 , inicia-se a bussola.

int i,x,y,z;

Declaradas as variáveis

double angle;

A variável double assim como float também é 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

Page 11: Sistemas Mecatrônicos Arduino

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

Page 12: Sistemas Mecatrônicos Arduino

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

Todo os comandos acima são parte de um código que serve para gerar uma bússola no robo.

bool newData = false;

Variável booleana que só aceita valores de verdadeiro ou falso.

unsigned long chars;

Unsigned long aceita apenas valoes de variáveis 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

Page 13: Sistemas Mecatrônicos Arduino

Quando nenhum dado é encontrado a função 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 começa o sistema de navegação:

targetHeading=courseToWaypoint();

float erro=targetHeading-angle;

distanceToWaypoint() ;

if (erro < -180)

erro += 360;

if (erro > 180)

erro -= 360;

Serial.print (" Erro: ");

Serial.println (erro);

12

Page 14: Sistemas Mecatrônicos Arduino

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 condições servem para corrigir erros de sentido. faz com que o robo vire para a direção

correta.

void nextWaypoint(void)

{

waypointNumber++;

targetLat = waypointList[waypointNumber].getLat();

13

Page 15: Sistemas Mecatrônicos Arduino

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

Page 16: Sistemas Mecatrônicos Arduino

}

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 programação, é definido como o robô vai atingir os

pontos desejados. São utilizadas formulas de geometrias para serem obtidas as distâncias.

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 1int IN3 = 35; // motor 2int IN4 = 45; // motor 2

15

Page 17: Sistemas Mecatrônicos Arduino

Foram definidas as variáveis correspondentes ao motor 1 e 2 e seus respectivos pinos, no caso, 44 34 35 45. Esses pinos são referentes aos fios que saem do motor e são frequentemente ligados ao arduino usando-se uma ponte-h. As pontes-H geralmente são utilizadas no controle da direção e velocidade de giro de motores.

int ENA = 8; // pwm motor 1int ENB = 9; // pwm motor 2

As duas variáveis acima posicionadas nos pinos oito e nove representam as saídas digitais PWM que comandará o giro tanto do motor quanto dos servos.

int canal1 = 18; // encoder 1 canal Aint canal2 = 19; // encoder 1 canal Bint canal3 = 20; // encoder 2 canal Aint canal4 = 21; // encoder 2 canal B

O encoder é um sensor que converte um movimento angular ou linear em uma série de pulsos digitais elétricos podendo assim traduzir o movimento do motor em ângulos ou mesmo em distância atraves da cinemática. O encoder incremental fornece normalmente dois pulsos quadrados defasados em 90º, que são 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 também o sentido do movimento.

Acima pode ser visto a declaração das variáveis dos encoders com seus respectivos pinos.

unsigned int sensor1 = 53; // fim de curso 1unsigned int sensor2 = 51; // fim de curso 2

Declaração das variáveis referentes aos sensores de fim de curso com seus pinos. Foi usado o tipo de variável "unsigned int ". A variável 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 variável "unsigned".

long erro1; // erro 1long erro2; // erro 2long V1; //velocidade 1long V2; //velocidade 2

Será realizado um controle proporcional em malha fechada, o que significa que os erros darão subsídios para o controle acontecer. Por isso foram declaradas as variáveis erro. Tanto os erros de cada motor quanto a veloidade foram declaradas usando-se o tipo de variável "long". Ela é usada quando deseja-se números maiores que os outros tipos de varáveis 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 variável char para ler bytes.

No caso acima, deseja-se criar um buffer na memória do arduino que é: uma parte da memória de um computador que é reservada como um local de armazenamento temporário para dados que

16

Page 18: Sistemas Mecatrônicos Arduino

estão 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 prévio com relação às posições dos motores e do braços segundo a cinemática.

long val;float a1;float a2;

Variável para o comprimento dos braços do robo a1 e a2

bool dadoPronto = false;

Variável booleana aceita apenas dois valores: verdadeiro e falso. Cada variável booleana ocupa 1 bit de memória.

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 mudança relativa na posição. A biblioteca atualiza sua contagem em cada mudança que é muitas vezes chamado de 4X contando, desde 4 contagens estão disponíveis para cada marca física ou buraco no hardware.

const float reducao = 17.442;

// Pulsos/° da saida

const float Kp1 = .3; //constante proporcional1const float Kp2 = .2; //constante proporcional2long a;

Segundo o relatório: Como o robô possui uma inércia 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 braço passe do ponto desejado, repetindo o ciclo. Para solucionar este problema foi criada uma constante Kp que será multiplicada pelo erro

void setup() {

17

Page 19: Sistemas Mecatrônicos Arduino

A função "setup ()" é acionada quando um esboço começa. É usada para inicializar variáveis , modos de pino , começar a usar as bibliotecas , etc.

O procedimento será executado apenas uma vez, após cada inicialização ou reset do Arduino. O "void" significa nada, ou seja, este procedimento não retorna nada. Isso não significa que ele não faz nada, apenas que ele não tem um número tangível ou qualquer outra coisa , para mostrar quando o procedimento se completa). pinMode(sensor1, INPUT_PULLUP); pinMode(sensor2, INPUT_PULLUP);

Usa-se a afirmação "pinMode" para definir se um pino será fisicamente usado como uma saída ou como uma entrada. No caso, os pinos dos sensores 1 e 2 são usados como entradas e ainda em PULLUP que significa que na montagem há um resistor entre o sensor e a alimentação de 5V. Serial.begin(115200);

Esse procedimento inicia uma comunicação serial. A comunicação serial (UART) na plataforma Arduino é um recurso que possibilita a comunicação entre a placa e um computador ou entre a placa e outro dispositivo. É através desse canal que é realizado o upload do código para a placa. Nesse caso a comunicação se dá à uma taxa de 115200 bits.

a1 = 80; a2 = 145;

Foram definidos os comprimentos dos braços do robô. myservo.attach(46);

Anexar a variável cervo a um pino, no caso o 46.

bufferIndex = 0;

Quantidade de espaço de memória utilizado inicialmente. pinMode(34, OUTPUT); pinMode(44, OUTPUT); pinMode(35, OUTPUT); pinMode(45, OUTPUT); start ();}

Utilização do pinMode para definir os pinos dos motores como saídas. 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

Page 20: Sistemas Mecatrônicos Arduino

val = valoresRecebidos[2]; // reads the value of the potentiometer (value between 0 and 1023)

Lê o valor dado pelo potenciômetro e o armazena na variável 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 números para outro intervalo mais conveniente, no caso de 0a 100 para 20 a 90. myservo.write(val); // sets the servo position according to the scaled value delay(15);

Esse delay serve para esperar o posicionamento do servo. //atualiza motor 1

posicao1 = Enc1.read();

Faz a leitura da variável "Enc1" e a armazena na posição 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 atualização da posição do motor 1, foram utilizadas as equações trigonométricas provenientes da cinemática. erro1 = (posicaoq12 * reducao * 4) - posicao1 + 69;

V1 = MIN(100, abs(erro1) * Kp1); V1 = MAXI(55, V1);

É selecionado o menor valor como velocidade. Porém como esta distância diminui com o tempo, ao chegar próximo do ponto desejado, o valor de velocidade será diminuído, assim é necessário criar uma segunda condição onde o valor de velocidade selecionada tem que ser o maior valor entre o valor da multiplicação e 80, pois abaixo de 80 o motor não possui energia suficiente para vencer a inércia 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

Page 21: Sistemas Mecatrônicos Arduino

analogWrite(ENA, (V1)); }

O procedimento condicional serve nesse caso para, dependendo do valor do erro, enviar comandos para o motor e girá-lo na direção certa e com a velocidade certa. O procedimento digitalWrite envia informação para a entrada digital (pino chamado de INx nesse programa em específico), no caso do motor fazendo-o funcionar ou não com o HIGH e LOW. O procedimento analogWrite faz a mesma coisa que o digital mas para a saída 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 n�o 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 disponíveis são plotados na tela os dados recebidos. dadoPronto = false; dadosRecebidos = 0;

//retorna posi��o atual e erro Serial.print(digitalRead(sensor1)); Serial.print(","); Serial.print(posicao1); Serial.print(","); Serial.print(erro1); Serial.print(","); Serial.print(posicao2);

20

Page 22: Sistemas Mecatrônicos Arduino

Serial.print(","); Serial.print(erro2); Serial.print(","); Serial.print(V1); Serial.print(","); Serial.println(V2);}

A função serial print serve para tornar os dados em dados legíveis na tela do computador.

void lePortaSerial() { while (Serial.available() > 0) { caracter = Serial.read();

Essa sub-rotina define que quando há disponíveis valores seriais, esses valores lidos são armazenados como a variável 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

Page 23: Sistemas Mecatrônicos Arduino

A partir dos condicionais acima é analisada o estado da variável caracter e do espaço reservado de memória buffer para no fim gerar o valor para a variavel "valoresRecebidos".

void start () {

Segundo o relatório foi criada uma subrotina na qual é solicitado mover manualmente o braço até que seja ativado por meio do rasgo feito no braço, para isto o sensor é ligado como normalmente fechado e quando a haste do botão se encaixa neste rasgo ele envia um sinal, atribuindo ângulos conhecidos nestas posições. Serial.println("--------------------------------"); Serial.println("-----------Modo Manual----------"); Serial.println("--------------------------------");

while ((digitalRead(sensor1) == 0)) {

Quando o sensor é ligado e está fechado na posição inicial como dito no relatório, a leitura na porta digital de saída é 0 com relação à variável sensor1. Isso significa que tem que mexer o eixo1 para a identificação das posições.

Serial.print("---------mova eixo 1------------ "); Serial.print(digitalRead(sensor1)); Serial.print(", "); Serial.println(posicao1);

São plotados o comando de mexer e a posição gerada na saída 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

Page 24: Sistemas Mecatrônicos Arduino

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 coneão com a internet.

Serial Peripheral Interface (SPI) é um protocolo de dados em série síncrona usado por

microcontroladores para comunicar com um ou mais dispositivos periféricos rapidamente ao

longo de distâncias curtas. Ele também pode ser usado para comunicação entre dois

microcontroladores. Um controlador PID calcula um valor de "erro" como a diferença 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

Page 25: Sistemas Mecatrônicos Arduino

O MAC ( Media Access Control )é o endereço 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

São declaradas as duas constantes anteriores cujo significado já foi explicaod em comentário.

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 variáveis 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 direção e velocidade de giro de

motores elétricos. 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 posição do motor 1 [°]

#define Batente2 90 // -> Limite para a posição do motor 2 [°]

Encoder Enc1(19,18); // -> Portas onde vão os fios branco e verde do Encoder 1

Encoder Enc2(3,2); // -> Portas onde vão os fios branco e verde do Encoder 2

24

Page 26: Sistemas Mecatrônicos Arduino

Assim como o grupo "Marcos", também foi usado motores com encoders acoplados.

double LimDir = 0, LimEsq = 0, Zero = 0;

Definidas variáveis de limite.

Servo servo;

Chamada para a variável servo da biblioteca.

#define interval 500 // -> Intervalo para o print das informações [ms]

long previousMillis = 0; // -> Variável 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 // -> Número de dados recebidos pelo Serial

Os três ú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

Page 27: Sistemas Mecatrônicos Arduino

Segundo o relatório do grupo, A leitura dos encoders pode ser variada com um valor inicial

desejado, ou seja, um setpoint inicial, ou por alteração por uma influência externa. Um valor de

Output é lido dos encoders por meio de uma rotina presente na biblioteca. Assim como o grupo

citado anteriormente, a atuação do encoder facilita o controle proporcional pois cria parâmetros

que podem ser comparados com os parâmetros dos setpoints e assim encontram-se os erros e

pode-se fazer o controle. Novamente esse erro não é zero o que gera a necessidade do controle

PID e assim a utilização da biblioteca PID para obtenção 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 começar captar as conexões que chegarem.

Serial.begin(9600);

Comunicação serial com transmissão de 9600 bps

Enc1.write(0);

Enc2.write(0);

servo.attach(SER, 544, 2400);

Anexa um servo disponível a um pino. No caso o Pino é o identificado pela variável SER

declarada anteriormente e ainda mostra os limites de MIN (544) que corresponde a largura do

pulso , em microssegundos , o que corresponde a um mínimo (0 graus) de ângulo sobre o servo e

um máximo de 180 graus (2400).

servo.write(90);

Grava um valor para o servo. Em um servo padrão , isto vai definir o ângulo do eixo (em

graus),movendo-se o eixo para a orientação desejada.

No caso o ângulo é de 90 Graus.

26

Page 28: Sistemas Mecatrônicos Arduino

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 saídas, pois esses pinos enviam informação aos

motores.

pinMode(FDC, INPUT);

pinMode(SOT, INPUT);

Define-se os pinos dos dois sensores como entrada, pois recebe-se a informação vinda dos

sensores.

Serial.println("------- Setup -------");

Regulagem para posicionamento e leitura desse posicionamento dos braços. (Setup).

if(digitalRead(SOT) == 1) {

Se a entrada digital acusar valor 1 significa que o braço 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 braço para longe do sensor enquanto o seu calor

for 1 ou seja, estiver captando o braço.

}

}

Serial.println("Mova o braco ate o sensor otico");

while(digitalRead(SOT) == 0) {

27

Page 29: Sistemas Mecatrônicos Arduino

delay(50);

}

Enc1.write(0);

Serial.println("Encoste o braco no sensor da direita");

// Começo da rotina da calibração

while(digitalRead(FDC) == 1) {

LimDir = Enc2.read();

Há um comando para o operador encostar o braço do robô no sensor da direita com isso a

entrada digital acusa 1 e assim pode-se registrar o valor lido pelo encoder na variável LimDir

}

Serial.println(LimDir);

delay(500);

while(digitalRead(FDC) == 0) {

Quando o valor acusado é 1, pode-se voltar o braço para o meio para iniciar a calibração para

o outro lado.

Serial.println("Volte para o meio");

delay(500);

}

Serial.println("Encoste o braço no sensor da esquerda");

while(digitalRead(FDC) == 1) {

LimEsq = Enc2.read();

//NOvamente é registrado o valor de distância para uma variável, no caso LimEsq, lido pelo

encoder.

}

Enc2.write((LimEsq-LimDir)/2);

Serial.println(LimEsq);

28

Page 30: Sistemas Mecatrônicos Arduino

LimDir = ((abs(LimDir-LimEsq)/2)*360)/(334*75.0);

LimEsq = -LimDir;

Serial.println(LimDir);

Serial.println(LimEsq); // -> Fim da rotina de calibração

Serial.setTimeout(10); // -> Tempo que a função 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 distância permitidas para o movimento

registradas.

void loop() {

Rede();

lePortaSerial();

As duas chamadas acima são 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

Page 31: Sistemas Mecatrônicos Arduino

analogWrite(ENA, abs(Output1));

Estabeleceu-se que para um valor negativo do Erro, o motor rotaciona com potência máxima

(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 análoga, um valor positivo no Erro resulta no motor rotacionando com potência

máxima 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

Page 32: Sistemas Mecatrônicos Arduino

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. Utilizando-

se dos imputs e outputs gerados pelo controle PID pode-se dar os comandos necessários aos

controladores, e assim mover o robo e ainda ao final registrar com o Serial.print todos os

parâmetros que demonstram o estado do robo como angulos, velocidades, posições 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

Page 33: Sistemas Mecatrônicos Arduino

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

Page 34: Sistemas Mecatrônicos Arduino

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

Page 35: Sistemas Mecatrônicos Arduino

4. Referências Bibliográficas

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

https://www.arduino.cc/

Aprendendo a Programar em Arduino, Instituto Federal de Educação Ciência 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