Foram implementadas as funções básicas de girar para direita, girar para a esquerda, dar ré e seguir em linha reta. Além dessas, também existem as funções para que o nosso robô faça círculo e quadrado. Existe um trecho dedicado ao controle PD.
O quadrado é realizado com a chamada da função de seguir em linha reta seguida da função de girar para a direita. No caso do círculo, são feitas mais algumas contas, pois a roda de dentro deve percorrer uma distância menor que a roda de fora. Portanto, a roda de dentro deve ter uma velocidade menor que a de fora. Finalmente, a potência dirigida deve ser proporcional a cada uma das velocidades desejadas para cada roda, respeitando as relações estabelecidas e explicitadas nos itens anteriores.
/*************************** madeinbrasil.c ********************************/
/*
Test program for Handy Board
version 1.7 1/05
testmotors() updated to reduce strain on HB motor drivers
version 1.6 1/04
CMUcam test updated to use new library and serial handlers
version 1.5 5/03
Expanded by Dan Gates to add the CMUcam comm test.
Reqires serial.icb to be in the same directory.
version 1.4 1/02
Changed by Randy Sargent for IC 4.0 and to include srf04 sonar test.
version 1.3 1/01
Changed by Anne Wright for Botball to allow selecting which test
using the knob. Program previously called hb-expbd-test.c. Also
includes hbmenu.c.
version 1.2 11/00
tests IR emitter -dpm
version 1.1 7/98
Expanded by Dave Miller 7/13/98 dmiller@kipr.org
to include servo and to handle menuing.
version 1.0 -- 26 nov 95
Fred G. Martin (fredm@media.mit.edu)
*/
/* Parametros medidos:
- Diametro da Roda: 43 [mm]
- Distancia mais curta entre o Eixo-Motor ate sua respectiva roda: 35 [mm]
- Distancia entre as duas rodas: 105 [mm]
Extras:
1) Voltas necessarias para alcancar 30cm: 300/(2*PI*RAIO_RODA) [mm]
2) Num. Voltas x 24 dentes x 6 = Num. Passos necessarios
*/
//Parmetros modificveis
#define RAIO_RODA 21.5 //Raio efetivo da roda+pneu em milmetros [mm]
#define PULSOS_VOLTA 12.0*24.0 //De acordo com o disco do shaft encoder->6*2=12
//Parametros no-modificveis
#define PI 3.1416 //Constante PI
#define REDUCAO 24.0 //Reducao do motor ate a roda devido as engrenagens
#define VOLTA (2.0*PI*(float)RAIO_RODA) //Perimetro da roda [mm]
#define DX VOLTA/(PULSOS_VOLTA) //Menor delta de deslocamento [mm]
#define BITOLA 121.0 //Distancia entre rodas [mm]
#define MM300 300.0
#define MOTOR_RPS (int)(140/(REDUCAO*60)) //Rotacoes por segundo do motor utilizado [rps]
#define MOTOR_1 2 // Amarelo lado visor LCD/Laranja
#define MOTOR_2 3 // Roxo lado visor LCD/Cinza
#define ENCODER_1 0
#define ENCODER_2 1
#define RPSID1 18 //Velocidade do motor1 em RPS (default: 18)
#define RPSID2 18 //Velocidade do motor2 em RPS
#define MOVE 0 //Vai para frente ou faz curva
#define RIGHT 1 //Go to right
#define LEFT 2 //Go to left
#define KP 1 //Parmetro de controle Kp
#define KD 0.01 //Parametro de controle Kd
// Programa exemplo
#define TESTNUM 8
#use "cmucamlib.ic"
char buff[11];
void main()
{
char a[TESTNUM][16]={"Menu: Frente","Menu: Quadrado","Menu: Circulo",
"Menu: Direita", "Menu: Esquerda", "Menu: Re", "Menu: Mission", "Menu: RPSxPower"};
printf("Grupo MIB: Aperte START! %f ** %f",DX,PULSOS_VOLTA);
while(!start_button());
printf("Gire o KNOB para selecionar \n");
sleep(1.0);
// Habilita encoder do canal 0
enable_encoder(0);
// Habilita encoder do canal 1
enable_encoder(1);
while(1) {
int sel;
printf("Gire o KNOB para selecionar \n");
sleep(0.5);
sel = select_string(a,TESTNUM);
if(sel==0) Go(MM300);
else if(sel==1) RightSquare(MM300);
else if(sel==2) Circle(MM300);
else if(sel==3) Right();
else if(sel==4) Left();
else if(sel==5) Go(-MM300);
else if(sel==6) missionImpossible();
else if(sel==7) mapcalibration();
else if(sel==8) break;
}
printf("Pronto!\n");
}
//Desliga os motores
void StopMotors()
{
motor(MOTOR_1,0);
motor(MOTOR_2,0);
alloff();
}
//Funo de ramp up e ramp down para motores
//Obs.: Aumenta/Diminui gradativamente a velocidade do motor em 1s
void StartMotors(int speed1, int speed2)
{
int i;
int power1, power2;
power1 = (speed1/10);
power2 = (speed2/10);
for (i=0;i<=10;i++)
{
motor(MOTOR_1,i*power1); //Gira motor 1 com i*int(speed2/10) de velocidade
motor(MOTOR_2,i*power2); //Gira motor 2 com i*int(speed2/10) de velocidade
msleep(200L); //Aguarda movimento mecnico
}
}
//Gira para a direita
void Gira360()
{
float dist=0.0;
printf("Gira 360!\n"); //Imprime Status
reset_encoder(0);
StartMotors(50,-50); //Liga os motores e gira para a direita
while(dist <=(BITOLA*PI)) //uma volta = 360 graus
{
if(stop_button())
{ break;}
dist = (float)read_encoder(0);
dist = (dist*DX); //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist);
msleep(100L);
}
StopMotors(); //Desliga os motores
}
//Gira para a direita
void Right()
{
float dist1=0.0, dist2=0.0;
int erroant1=0, erroant2=0,encsum1=0,encsum2=0;
printf("Direita!\n"); //Imprime Status
reset_encoder(0);
reset_encoder(1);
//StartMotors(100,-80); //Liga os motores e gira para a direita
//motor(MOTOR_1,100);
//motor(MOTOR_2,-80);
while((dist1 < (((float)BITOLA*0.94*(float)(PI))/4.0)) || (dist2 <(((float)BITOLA*0.94*(float)(PI))/4.0))) //Meia volta = 90 graus
{
PDControl(20,20,&erroant1,&erroant2,RIGHT);
encsum1 = encsum1 + read_encoder(0);
encsum2 = encsum2 + read_encoder(1); //soma acumulativa dos encoders
reset_encoder(0);
reset_encoder(1);
dist1 = ((float)(encsum1))*DX; //Calcula a distancia percorrida
dist2 = ((float)(encsum2))*DX;
printf("Dist1.: %f mm Dist2.: %f mm\n",dist1,dist2); //Imprime distancia percorrida
msleep(30L); //Aguarda movimento mecanico
}
//Quando a distncia x for alcancada
StopMotors(); //Desliga os motores
sleep(0.5); //Aguarda movimento mecnico
dist1 = ((float)(encsum1))*DX; //Calcula a distancia percorrida
dist2 = ((float)(encsum2))*DX;
printf("D1.: %f mm D2.: %f mm\n",dist1,dist2); //Imprime distancia percorrida
sleep(0.5);
reset_encoder(0);
reset_encoder(1);
//printf("Parado.\n"); //Imprime Status
//while(!stop_button());
}
//Gira para a esquerda
void Left()
{
float dist=0.0;
int erroant1=0, erroant2=0,encsum=0;
/*teste*/
int enc1sum=0,enc2sum=0;
printf("Esquerda!\n"); //Imprime Status
reset_encoder(0);
reset_encoder(1);
//StartMotors(-100,80); //Liga os motores e gira para a esquerda
//motor(MOTOR_1,-100);
//motor(MOTOR_2,100);
while((dist <= (((float)BITOLA*(float)(PI))/4.0) )) //Meia volta = 90 graus
{
PDControl(18,18,&erroant1,&erroant2,LEFT);
//encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
enc1sum = enc1sum + read_encoder(0);
enc2sum = enc1sum + read_encoder(1);
reset_encoder(0);
reset_encoder(1);
dist = (float)((enc1sum + enc2sum)/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
msleep(30L); //Aguarda movimento mecanico
} //Gira at completar meia volta en cada roda
//Quando a distncia x for alcancada
StopMotors(); //Desliga os motores
sleep(1.0); //Aguarda movimento mecnico
//encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
enc1sum = enc1sum + read_encoder(0);
enc2sum = enc1sum + read_encoder(1);
dist = (float)((enc1sum+enc2sum)/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
reset_encoder(0);
reset_encoder(1);
//printf("Parado.\n"); //Imprime Status
//while(!stop_button());
}
//Desloca para frente x unidades de distncia [mm]
void Go(float x)
{
int enc1=0, enc2=0, speed1, speed2;
float dist=0.0;
int erroant1=0, erroant2=0,encsum=0;
// Habilita encoder do canal 0
reset_encoder(0);
reset_encoder(1);
if(x>=0.0)
{ printf("Indo pra frente!\n"); //Imprime Status
//StartMotors(100,80); //Liga os motores
motor(MOTOR_1,100);
motor(MOTOR_2,80);
}
else{
printf("Indo pra Tras!\n"); //Imprime Status
StartMotors(-100,-80); //Liga os motores
}
while ((dist<x)) //Enquanto dist<x e nao pressionar stop
{
PDControl(20,20,&erroant1,&erroant2,MOVE);
encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
reset_encoder(0);
reset_encoder(1);
dist = (float) ((encsum)/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
msleep(30L); //Aguarda movimento mecanico
}
//Quando a distncia x for alcancada
StopMotors(); //Desliga os motores
sleep(1.0); //Aguarda movimento mecnico
encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
dist = (float)(encsum/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
while(!stop_button());
reset_encoder(0);
reset_encoder(1);
//printf("Parado.\n"); //Imprime Status
//while(!stop_button());
}
void PDControl(int encid1, int encid2, int *erroant1, int *erroant2, int tipo)
{
int enc1=0, enc2=0;
int erro1=0, erro2=0;
int i, pterm1, pterm2, dterm1, dterm2;
int speed1=0,speed2=0;
int curve1[9]={9,13,14,16,17,18,19,19,20};
int curve2[9]={10,14,16,18,19,20,20,20,20};
enc1 = read_encoder(0);
enc1 = 5*enc1; //*5 = 30*enc1/6
enc2 = read_encoder(1);
enc2 = 5*enc2;
erro1 = (encid1-enc1);
erro2 = (encid2-enc2);
pterm1 = (int)((float)KP*(float)erro1+0.5);
pterm2 = (int)((float)KP*(float)erro2+0.5);
dterm1 = (int) ((float)KD*(float)(erro1-*erroant1)+0.5);
dterm2 = (int) ((float)KD*(float)(erro2-*erroant2)+0.5);
*erroant1 = erro1;
*erroant2 = erro2;
/*
integ = integ+erro;
deriv = (erro/tempo) - deriv;
*/
enc1 = encid1+pterm1+dterm1;
enc2 = encid2+pterm2+dterm2;
//relacao enc e speed
for(i=0;i<9;i++)
{
if(enc1>=curve1[i])
speed1=i*10+20;
if(enc2>=curve2[i])
speed2=i*10+20;
}
//Saturacao dos valores (manter por seguranca)
if (speed1<-100)
speed1=-100;
if(speed1>100)
speed1=100;
if(speed2<-100)
speed2=-100;
if(speed2>100)
speed2=100;
switch(tipo)
{
case 0: //Frente ou curva
motor(MOTOR_1,speed1);
motor(MOTOR_2,speed2);
break;
case 1: //Direita
motor(MOTOR_1,speed1);
motor(MOTOR_2,-speed2);
break;
case 2: //Esquerda
motor(MOTOR_1,-speed1);
motor(MOTOR_2,speed2);
break;
default: {
printf("Switch error!\n");
break;
}
}
}
//Desenha um quadrado de lado x mm girando para a direita
void RightSquare(float x)
{
int i=1;
while((i<13))
{ Go(x); //Desloca x mm pra frente
Right(); //Gira 90 graus para a direita
if(stop_button())
break;
i++;
}
}
//Desenha um crculo de raio x mm
void Circle(float x)
{
float dist=0.0;
float L1=0.0,L2=0.0;
int encsum=0,erroant1=0,erroant2=0;
int pid=0;
pid = start_process(missionImpossible());
L1 = x-(BITOLA/2.0); //Comprimento do arco da roda interna [mm]
L2 = x+(BITOLA/2.0); //Comprimento do arco da roda EXTERNA [mm]
while((dist<=3.0*(2.0*PI*x)))
{
PDControl((20),((int)(20.0*(L1/L2)+0.5)),&erroant1,&erroant2,MOVE);
encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
reset_encoder(0);
reset_encoder(1);
dist = (float) ((encsum)/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
msleep(30L); //Aguarda movimento mecanico
if(stop_button())
break;
}
//Quando a distncia x for alcancada
StopMotors(); //Desliga os motores
sleep(1.0); //Aguarda movimento mecnico
encsum = encsum + read_encoder(0) + read_encoder(1); //soma acumulativa dos encoders
dist = (float)(encsum/2)*DX; //Calcula a distancia percorrida
printf("Dist.: %f mm\n",dist); //Imprime distancia percorrida
reset_encoder(0);
reset_encoder(1);
kill_process(pid);
//printf("Parado.\n"); //Imprime Status
//while(!stop_button());
}
void testmotors(void)
{
int pulsos1,rps1;
int pulsos2,rps2;
int aux = 0;
int cont=2;
printf("Testando motor, HoldSTOP para finalizar. \n");
for(cont=1;cont<11;cont++)
{
motor(MOTOR_1,cont*10);
motor(MOTOR_2,cont*10);
while ((!stop_button())||(aux<=10))
{
reset_encoder(0);
reset_encoder(1);
msleep(500L);
// Le o numero de pulsos
pulsos1 = read_encoder(0);
rps1 = 2*pulsos1/6;
pulsos2 = read_encoder(1);
rps2 = 2*pulsos2/6;
aux = aux+1;
printf("RPS1: %d RPS2: %d \n",rps1,rps2);
}
StopMotors();
beep();
msleep(500L);
}
StopMotors();
beep();
}
//Mapeamento da tabela de controle
void mapcalibration()
{
//
float rps1=0.0,rps2=0.0;
int pulsos1=0, pulsos2=0;
int i=0,k=0;
for(i=10;i<101;i++)
{
while(k<(2*3)) // k < 2*[N segundos]
{
//Limpa contadores de encoder
reset_encoder(0);
reset_encoder(1);
//define potencia do motor
motor(MOTOR_1,i);
motor(MOTOR_2,i);
msleep(500L);
// Le o numero de pulsos
pulsos1 = read_encoder(0);
rps1 = (float)(pulsos1)/3.0;
pulsos2 = read_encoder(1);
rps2 = (float)(pulsos2)/3.0;
printf("S1: %f S2: %f *i: %d\n",rps1,rps2,i);
beep();
k++;
}
k=0;
}
}
void missionImpossible()
{
float B = 493.88;
float Bb= 466.16;
float E = 659.25;
float G = 783.99;
float G_Grave = 392.00;
float A = 880.00;
float A_Grave = 440.00;
float D = 587.33;
float Eb = 622.25;
int i=0;
for(i=0;i<5;i++)
{
if(stop_button())
break;
//1
tone(E,0.5);
tone(E,0.5);
sleep(0.05);
tone(G,0.3);
tone(A,0.3);
tone(E,0.5);
tone(E,0.5);
sleep(0.05);
tone(D,0.3);
tone(Eb,0.3);
//2
tone(E,0.5);
tone(E,0.5);
sleep(0.05);
tone(G,0.3);
tone(A,0.3);
tone(E,0.5);
tone(E,0.5);
sleep(0.05);
tone(D,0.3);
tone(Eb,0.3);
//3
tone(G,0.2);
tone(E,0.2);
tone(B,1.0);
sleep(0.25);
//4
tone(G,0.2);
tone(E,0.2);
tone(Bb,1.0);
sleep(0.25);
//5
tone(G,0.2);
tone(E,0.2);
tone(A_Grave,1.0);
sleep(0.25);
tone(G_Grave,0.2);
tone(A_Grave,0.2);
sleep(0.25);
}
}
void hb_ir_transmit_on()
{
bit_set(0x1000,0b01000000);
}
/****************************** hbmenu.c ********************************/
/* Menu functions which also allow variables to be set via the knob
and selection buttons
Version 1.0
Written for MIT 6.270 contest by Anne Wright 11/14/1991
Version 2.0
Converted for Handy Board for Botball by Anne Wright 1/13/2001
*/
/* abstractions for chosen_button */
#define NEITHER_B 0
#define START_B 1
#define STOP_B 2
/* abstractions for wait_button */
#define UP_B 3
#define DOWN_B 4
#define CYCLE_B 5
/*****************************button routines*************************/
/* Return minimum of two integers */
/* defined in cmucam3.ic which is loaded by this file -dpm 1/03
int min(int a,int b)
{
if(a<b)
return(a);
else
return(b);
}
*/
/* Return minimum of two floats */
float fmin(float a,float b)
{
if(a<b)
return(a);
else
return(b);
}
/* Returns which button is depressed using definitions above. If
both are pressed, start has precedence */
int chosen_button()
{
if(start_button())
return START_B;
else if(stop_button())
return STOP_B;
else
return NEITHER_B;
}
/* wait until button is depressed(DOWN_B), released(UP_B), or
both(CYCLE_B) and return which button if any activated the
sequence */
int wait_button(int i)
{
if(i==DOWN_B){
while(!(start_button() || stop_button()));
return chosen_button();
}
else if (i==UP_B) {
int b;
b=chosen_button();
while(start_button() || stop_button());
return b;
}
else {
int b;
while(!(start_button() || stop_button()));
b=chosen_button();
while(start_button() || stop_button());
return b;
}
}
/********************* Knob to Number routines*****************************/
/* Returns an integer value from min_val to max_val based on the current
position of the knob */
int knob_int_value(int min_val,int max_val)
{
int val, coarseness=(255)/(max_val-min_val),selection;
val=min((knob())/coarseness+min_val,max_val);
return min(val,max_val);
}
/* Returns an float value from min_val to max_val based on the current
position of the knob */
float knob_float_value(float min_val,float max_val)
{
float val, coarseness=(255.)/(max_val-min_val),selection;
val=fmin(((float)knob())/coarseness+min_val,max_val);
return fmin(val,max_val);
}
/******************** Menu selection routines ****************************/
/* While waiting for a button press, display the string passed in and
the val, the integer value betwen min_val and max_val for the knob.
If the button pressed is the start button, returns the final value
of val. If the button pressed is the stop button, returns -1. */
int select_int_value(char s[],int min_val,int max_val)
{
int val, button;
printf("%s %d to %d\n",s,min_val, max_val);
sleep(0.8);
/* Wait until no button is pressed */
wait_button(UP_B);
/* While no button is pressed, display the string passed in and the
current value of val */
while((button = chosen_button())==NEITHER_B) {
val=knob_int_value(min_val,max_val);
printf("%s %d\n",s,val);
msleep(100L);
}
/* Wait until no button is pressed */
wait_button(UP_B);
if(button==STOP_B)
return(-1); /** -1 means stop pressed -- do not reset value **/
else
return(val); /* Stop not pressed, return val */
}
/* While waiting for a button press, display the string passed in and
the val, the float value betwen min_val and max_val for the knob.
If the button pressed is the start button, returns the final value
of val. If the button pressed is the stop button, returns -1. */
float select_float_value(char s[],float min_val,float max_val)
{
float val;
int button;
printf("%s %f to %f\n",s,min_val, max_val);
sleep(0.8);
/* Wait until no button is pressed */
wait_button(UP_B);
/* While no button is pressed, display the string passed in and the
current value of val */
while((button = chosen_button())==NEITHER_B) {
val=knob_float_value(min_val,max_val);
printf("%s %f\n",s,val);
msleep(100L);
}
/* Wait until no button is pressed */
wait_button(UP_B);
if(button==STOP_B)
return(-1.0); /** -1 means stop pressed -- do not reset value **/
else
return(val); /* Stop not pressed, return val */
}
/* While waiting for a button press, display the string from the array
of strings passed in which corresponds to the current position of
the knob (see select_int_value). If the button pressed is the
start button, returns the index of the string selected (0 to n-1).
If the button pressed is the stop button, returns -1. */
int select_string(char choices[][],int n)
{
int selection,last_selection=-1,button;
if(n>_array_size(choices))
n=_array_size(choices);
/* Wait until no button is pressed */
wait_button(UP_B);
/* While no button is pressed, display the string from the array
of strings passed in which corresponds to the current position
of the knob */
while((button = chosen_button())==NEITHER_B) {
selection=knob_int_value(0,n-1);
if(selection!=last_selection) {
printf("%s\n",choices[selection]);
msleep(150L);
last_selection=selection;
}
}
/* Wait until no button is pressed */
wait_button(UP_B);
if(button==STOP_B)
return(-1); /** -1 means stop pressed -- do not reset value **/
else
return(selection); /* Stop not pressed, return val */
}
/*
* Local variables:
* comment-column: 40
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/