Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Servo TCS3200 TextLCD2 X_NUCLEO_IHM01A1 mbed
Fork of PROJETO by
main.cpp
00001 #include "TextLCD.h" 00002 #include "L6474.h" 00003 #include "TCS3200.h" 00004 #include "Servo.h" 00005 00006 00007 // Set do display LCD 20x4 com o módulo I2C 00008 00009 I2C i2c_lcd(D14,D15); 00010 TextLCD_I2C lcd(&i2c_lcd, 0x7E,TextLCD::LCD20x4); 00011 00012 /*-----Declaração dos pinos e suas funções-----*/ 00013 00014 //PINOS DE INTERRUPÇÃO. 00015 00016 InterruptIn jog_button_pos(PC_12); // Botão para jog+ e navegação no menu 00017 InterruptIn jog_button_neg(PA_15); // Botão para jog- e navegação no menu 00018 00019 InterruptIn btnX(PC_3); // Botão para selecionar o eixo X 00020 InterruptIn btnY(PC_2); // Botão para selecionar o eixo Y 00021 InterruptIn btnZ(PC_0); // Botão para selecionar o eixo Z 00022 00023 InterruptIn confirma(PC_13); // Botão OK do menu (pino do botão do usuario) 00024 InterruptIn back_btn(PB_7); // Botão para a função "voltar" do menu 00025 00026 InterruptIn FDC(PC_5); // Fim de curso para o eixo Z 00027 InterruptIn FDC2(PC_8); // Fim de curso para o eixo X 00028 InterruptIn FDC3(PC_6); // Fim de curso para o eixo Y 00029 00030 /*-----Declaração de variaveis globais do código-----*/ 00031 00032 bool referZ = false; // Parametro para o referenciamento do motor 1 00033 bool referX = false; // Parametro para o referenciamento do motor 2 00034 bool referY = false; // Parametro para o referenciamento do motor 3 00035 00036 bool save_pos = false; // Parametro para definir o fim da rotina de save pick\drop 00037 00038 bool dirx = false; // Indicador que o motor ira se movimentar no eixo x 00039 bool diry = false; // Indicador que o motor ira se movimentar no eixo y 00040 bool dirz = false; // Indicador que o motor ira se movimentar no eixo z 00041 00042 bool jog_pos = false; // Indicador para a movimentação do motor no jog (+) 00043 bool jog_neg = false; // Indicador para a movimentação do motor no jog (-) 00044 bool ref_cycle = true; // Indicador para a realização do ciclo Pick/Place 00045 00046 bool enable = false; // Variavel auxiliar para navegação no motor 00047 bool flag = true; // Variavel auxiliar para utilizar mais de uma vez as funções disponiveis no menu 00048 00049 signed char change = 0; // Numero que varia de 0 a 2, indicando qual set de velocidade será usado 00050 signed char ref_cursor = 0; // Numero de referência para a posição do cursor 00051 unsigned char ref_menu = 0; // Numero para indicar o menu atual 00052 00053 /*Criação de uma struct (basicamente, uma classe) para sets de velocidades e acelerações 00054 diferentes. Cada objeto dessa struct possui os argumentos de velocidades max e min e 00055 aceleração e desaceleração. 00056 */ 00057 00058 struct set_velocidades { 00059 unsigned int maxspeed; 00060 unsigned int minspeed; 00061 unsigned int ac; 00062 unsigned int dc; 00063 }; 00064 00065 struct set_velocidades set[3]; /* Cria um objeto da struct set_velocidades com três 00066 objetos dentro dele (basicamente, um objeto triplo). 00067 */ 00068 00069 //Struct para sets de coordenadas, com argumentos de posição em x,y e z. 00070 00071 struct Coordenadas { 00072 int posx; 00073 int posy; 00074 int posz; 00075 }; 00076 00077 struct Coordenadas PickPos,DropPos[3]; //Cria objeto unico para posição de pick, e objeto triplo para posição de place. 00078 00079 // Perfil de incialização do motor 00080 00081 L6474_init_t init = { 00082 160, /* Acceleration rate in pps^2. Range: (0..+inf). */ 00083 160, /* Deceleration rate in pps^2. Range: (0..+inf). */ 00084 1600, /* Maximum speed in pps. Range: (30..10000]. */ 00085 800, /* Minimum speed in pps. Range: [30..10000). */ 00086 1000, /* Torque regulation current in mA. Range: 31.25mA to 4000mA. */ 00087 L6474_OCD_TH_1500mA, /* Overcurrent threshold (OCD_TH register). */ 00088 L6474_CONFIG_OC_SD_ENABLE, /* Overcurrent shutwdown (OC_SD field of CONFIG register). */ 00089 L6474_CONFIG_EN_TQREG_TVAL_USED, /* Torque regulation method (EN_TQREG field of CONFIG register). */ 00090 L6474_STEP_SEL_1_8, /* Step selection (STEP_SEL field of STEP_MODE register). */ 00091 L6474_SYNC_SEL_1_2, /* Sync selection (SYNC_SEL field of STEP_MODE register). */ 00092 L6474_FAST_STEP_12us, /* Fall time value (T_FAST field of T_FAST register). Range: 2us to 32us. */ 00093 L6474_TOFF_FAST_8us, /* Maximum fast decay time (T_OFF field of T_FAST register). Range: 2us to 32us. */ 00094 3, /* Minimum ON time in us (TON_MIN register). Range: 0.5us to 64us. */ 00095 21, /* Minimum OFF time in us (TOFF_MIN register). Range: 0.5us to 64us. */ 00096 L6474_CONFIG_TOFF_044us, /* Target Swicthing Period (field TOFF of CONFIG register). */ 00097 L6474_CONFIG_SR_320V_us, /* Slew rate (POW_SR field of CONFIG register). */ 00098 L6474_CONFIG_INT_16MHZ, /* Clock setting (OSC_CLK_SEL field of CONFIG register). */ 00099 L6474_ALARM_EN_OVERCURRENT | 00100 L6474_ALARM_EN_THERMAL_SHUTDOWN | 00101 L6474_ALARM_EN_THERMAL_WARNING | 00102 L6474_ALARM_EN_UNDERVOLTAGE | 00103 L6474_ALARM_EN_SW_TURN_ON | 00104 L6474_ALARM_EN_WRONG_NPERF_CMD /* Alarm (ALARM_EN register). */ 00105 }; 00106 00107 // Declaração dos motores utilizados 00108 00109 L6474 *motorZ; 00110 L6474 *motorX; 00111 L6474 *motorY; 00112 00113 /*-----Declaração de funções auxiliares----*/ 00114 00115 /* FUNÇÕES "sobe_cursor(void)" E "desce_cursor(void)": 00116 1-) Adiciona ou subtrai 1 da variavel ref_cursor; 00117 2-) Atribui o valor de linha máx ou mín se o ref_cursor atravessar algum 00118 extremo da tela LCD; 00119 3-) O cursor se posiciona de acordo com a posição designada; 00120 */ 00121 void sobe_cursor(void) 00122 { 00123 ref_cursor += 1; 00124 if (ref_cursor > 3) { 00125 ref_cursor = 0; 00126 } 00127 } 00128 00129 void desce_cursor(void) 00130 { 00131 ref_cursor -= 1; 00132 if (ref_cursor < 0) { 00133 ref_cursor = 3; 00134 } 00135 } 00136 00137 /* FUNÇÃO "conclusao(char n)": 00138 1-)Desliga o cursor; 00139 2-)Apresenta uma mensagem de conclusão do salvamento das posições: 00140 -> Se n = 0, apresenta a mensagem de conclusão do PICK; 00141 -> Se n != 0, apresenta a mensagem de alguma das posições de DROP (depende do valor de n); 00142 */ 00143 00144 void conclusao(char n) 00145 { 00146 lcd.setCursor(TextLCD::CurOff_BlkOff); 00147 if (n == 0) { 00148 lcd.cls(); 00149 lcd.locate(4,0); 00150 lcd.printf("PICK POSITION"); 00151 lcd.locate(7,1); 00152 lcd.printf("SALVA!"); 00153 wait(2); 00154 lcd.cls(); 00155 } 00156 if (n > 0) { 00157 lcd.cls(); 00158 lcd.locate(3,0); 00159 lcd.printf("DROP POSITION %d", n); 00160 lcd.locate(7,1); 00161 lcd.printf("SALVA!"); 00162 wait(2); 00163 lcd.cls(); 00164 } 00165 } 00166 00167 /*FUNÇÃO "menu_jog(void)": 00168 -> Prepara a estrutura para printar no LCD as posições atuais de cada eixo. 00169 */ 00170 00171 void menu_jog(void) 00172 { 00173 lcd.cls(); 00174 lcd.locate(0,1); 00175 lcd.printf("X: "); 00176 lcd.locate(0,2); 00177 lcd.printf("Y: "); 00178 lcd.locate(0,3); 00179 lcd.printf("Z: "); 00180 } 00181 00182 /*FUNÇÃO "menu_passivo(char n)": 00183 -> A função apresenta um menu estático diferente de acordo com o valor n recebido. 00184 Os menus aqui disponiveis são estáticos pois são temporários e não possibilitam 00185 seleção de funções ou movimento do cursor. 00186 -> Os menus estáticos são chamados para avisar ao usuário da realização de alguma 00187 função, da inicialização da maquina e seu estado de operação. 00188 */ 00189 00190 void menu_passivo(char n) 00191 { 00192 switch(n) { 00193 00194 // Menu estático 1 é o menu de abertura (ao ligar a máquina) 00195 case 1: { 00196 lcd.cls(); 00197 lcd.locate(6,0); 00198 lcd.printf("Maquina"); 00199 lcd.locate(3,1); 00200 lcd.printf("Pick-and-Place"); 00201 lcd.locate(5,2); 00202 lcd.printf("RAWCAMBOLE"); 00203 wait(3); 00204 lcd.cls(); 00205 break; 00206 } 00207 // Menu estático 2 é o menu chamado durante a ação de referenciamento da máquina 00208 case 2: { 00209 lcd.cls(); 00210 lcd.printf("Setando ponto de"); 00211 lcd.locate(5,1); 00212 lcd.printf("origem!"); 00213 lcd.locate(5,3); 00214 lcd.printf("AGUARDE..."); 00215 break; 00216 } 00217 // Menu estático 3 é chamado durante o ciclo infinito 00218 case 3: { 00219 lcd.cls(); 00220 lcd.printf("Maquina operando"); 00221 lcd.locate(2,1); 00222 lcd.printf(" em ciclo"); 00223 lcd.locate(2,3); 00224 lcd.printf("STOP-> Press Back"); 00225 break; 00226 } 00227 // Menu estático 4 é chamado durante o ciclo único 00228 case 4: { 00229 lcd.cls(); 00230 lcd.printf("Maquina operando"); 00231 lcd.locate(2,1); 00232 lcd.printf("apenas um ciclo"); 00233 break; 00234 } 00235 00236 } 00237 } 00238 00239 /* FUNÇÕES "jog_(...)": 00240 -> As funções de jog vem em pares de "on" e "off", um par para cada direção. 00241 1-) A função "on" apenas seta uma variavel em TRUE, possibilitando a movimentação 00242 em determinada direção; 00243 2-) A função "off" seta o valor mesma variavel em FALSE e para a movimentação do motor, 00244 terminando com a operação de jog em determinada direção; 00245 */ 00246 00247 void jog_pos_on(void) 00248 { 00249 jog_pos = true; 00250 } 00251 00252 void jog_pos_off(void) 00253 { 00254 jog_pos = false; 00255 motorZ->hard_stop(); 00256 motorX->hard_stop(); 00257 motorY->hard_stop(); 00258 } 00259 00260 void jog_neg_on(void) 00261 { 00262 jog_neg = true; 00263 } 00264 00265 void jog_neg_off(void) 00266 { 00267 jog_neg = false; 00268 motorZ->hard_stop(); 00269 motorX->hard_stop(); 00270 motorY->hard_stop(); 00271 } 00272 00273 /* FUNÇÕES "motorN_off(void)": 00274 1-) Para a movimentação do motor; 00275 2-) Seta uma variavel booleana em TRUE para indicar que o referenciamento de tal 00276 eixo está pronto; 00277 */ 00278 00279 void motorZ_off(void) 00280 { 00281 motorZ->hard_stop(); 00282 referZ = true; 00283 } 00284 00285 void motorX_off(void) 00286 { 00287 motorX->hard_stop(); 00288 referX = true; 00289 } 00290 00291 void motorY_off(void) 00292 { 00293 motorY->hard_stop(); 00294 referY = true; 00295 } 00296 00297 /*FUNÇÕES "set_aceleracoesN(...)": 00298 -> Função recebe os seguintes parâmetros: 00299 1-) Velocidade máxima; 00300 2-) Velocidade mínima; 00301 3-) Aceleração; 00302 4-) Desaceleração; 00303 -> Função seta esses valores no motor N 00304 */ 00305 void set_aceleracoesZ(int maxspeed,int minspeed,int ac,int dc) 00306 { 00307 motorZ->set_max_speed(maxspeed)/2; 00308 motorZ->set_min_speed(minspeed)/2; 00309 motorZ->set_acceleration(ac)/2; 00310 motorZ->set_deceleration(dc)/2; 00311 } 00312 00313 void set_aceleracoesX(int maxspeed,int minspeed,int ac,int dc) 00314 { 00315 motorX->set_max_speed(maxspeed); 00316 motorX->set_min_speed(minspeed); 00317 motorX->set_acceleration(ac); 00318 motorX->set_deceleration(dc); 00319 } 00320 00321 void set_aceleracoesY(int maxspeed,int minspeed,int ac,int dc) 00322 { 00323 motorY->set_max_speed(maxspeed); 00324 motorY->set_min_speed(minspeed); 00325 motorY->set_acceleration(ac); 00326 motorY->set_deceleration(dc); 00327 } 00328 00329 /*FUNÇÕES "save_pick_pos()" E "save_dropN": 00330 1-) Função captura as posições atuais dos 3 motores e armazenam seus valores 00331 nos atributos respectivos de seu objeto respectivo. 00332 2-) Altera o valor de uma variavel booleana para TRUE, indicando o fim da 00333 operação de jog. 00334 */ 00335 00336 void save_pick_pos(void) 00337 { 00338 PickPos.posx = motorX->get_position(); 00339 PickPos.posy = motorY->get_position(); 00340 PickPos.posz = motorZ->get_position(); 00341 save_pos = true; 00342 } 00343 00344 void save_drop1() 00345 { 00346 DropPos[0].posx = motorX->get_position(); 00347 DropPos[0].posy = motorY->get_position(); 00348 DropPos[0].posz = motorZ->get_position(); 00349 save_pos = true; 00350 } 00351 00352 void save_drop2() 00353 { 00354 DropPos[1].posx = motorX->get_position(); 00355 DropPos[1].posy = motorY->get_position(); 00356 DropPos[1].posz = motorZ->get_position(); 00357 save_pos = true; 00358 } 00359 00360 void save_drop3() 00361 { 00362 DropPos[2].posx = motorX->get_position(); 00363 DropPos[2].posy = motorY->get_position(); 00364 DropPos[2].posz = motorZ->get_position(); 00365 save_pos = true; 00366 } 00367 00368 /* FUNÇÃO "reconhecimento_peca()": 00369 1-) Função primeiro usa o sensor de cor para identificar a cor predominante: 00370 verde, vermelho ou azul e também o indutivo para identificar o material; 00371 -> De acordo com a leitura do sensor, definiram-se apenas duas opções: ver- 00372 de ou não verde (se não verde, ele retorna vermelho); 00373 2-) Um reconhecimento é feito a cada 0.1 segundos por 1 segundo, e cada um dos três resultados 00374 possiveis recebe um tag: 00375 -> Tag 0 = etiqueta verde e metal; 00376 -> Tag 1 = etiqueta verde e polimero; 00377 -> Tag 2 = etiqueta vermelha, qualquer material; 00378 O valor do tag de cada medição é armazenado em uma array. 00379 3-) Em um par de loops, avalia-se qual foi o tag que mais apareceu. O que for 00380 a maioria, será considerado como o tag (ou cor) verdadeiro, que é o valor 00381 retornado pela função; 00382 4-) Esse tag servirá como o indice da struct de structs "DropPos", indicando 00383 para qual posição de DROP ele deveria ir 00384 */ 00385 00386 int reconhecimento_peca(void) 00387 { 00388 TCS3200 color(PC_4, PB_14, PB_1, PB_13, PB_15); // Declara os pinos para o sensor RGB 00389 DigitalIn sensor(PB_2); // Declara pino para o sensor indutivo 00390 long red, green, blue, clear; // Valores de leitura para cada cor 00391 int tagy, i = 0, j = 0, tag[10]; 00392 int contador = 0, contador_max = 0, elemento; 00393 00394 // Modo de operação do sensor 00395 color.SetMode(TCS3200::SCALE_20); 00396 00397 while(i <= 9) { 00398 00399 red = color.ReadRed(); 00400 green = color.ReadGreen(); 00401 blue = color.ReadBlue(); 00402 clear = color.ReadClear(); 00403 00404 if(green > 30) { 00405 tagy = 2; 00406 } 00407 if((green <= 30)&&(sensor)) { 00408 tagy = 0; 00409 } 00410 if((green <= 30) && (!sensor)) { 00411 00412 tagy = 1; 00413 } 00414 00415 tag[i] = tagy; 00416 i = i + 1; 00417 wait(0.1); 00418 00419 } 00420 00421 // Loops para avaliar qual tag aparece mais 00422 00423 for (i = 0; i <= 9; i++) { 00424 for (j = 0; j <= 9; j++) { 00425 if (tag[i] == tag[j]) { 00426 contador += 1; 00427 } 00428 } 00429 if (contador > contador_max) { 00430 contador_max = contador; 00431 elemento = tag[i]; 00432 } 00433 contador = 0; 00434 } 00435 00436 return elemento; 00437 } 00438 00439 /* FUNÇÃO "sefta_origem()": 00440 -> A função realiza o referenciamento completo para os 3 eixos, um de cada vez; 00441 -> Por ser uma função mais longa, o processo é detalhado dentro da própria função; 00442 */ 00443 00444 void seta_origem() 00445 { 00446 menu_passivo(2); 00447 00448 //Seta uma alta velocidade para o referenciamento 00449 00450 set_aceleracoesZ(3500/2,1200,100/2,100/2); 00451 set_aceleracoesX(4000,3000,100,100); 00452 set_aceleracoesY(4000,3000,100,100); 00453 00454 InterruptIn confirma(PC_13); 00455 confirma.mode(PullUp); 00456 00457 while(1) { 00458 00459 00460 InterruptIn FDC(PC_5); 00461 FDC.fall(&motorZ_off); 00462 FDC.mode(PullUp); 00463 00464 confirma.fall(&motorZ_off); 00465 00466 //Chamada do fim de curso para a função de interrupção 00467 00468 00469 if (referZ == false) { 00470 motorZ->run(StepperMotor::BWD); 00471 motorZ->wait_while_active(); 00472 } 00473 00474 // Se a interrupção for chamada, a variavel referZ se torna TRUE, acionando 00475 // os comandos a seguir. 00476 00477 else { 00478 motorZ->move(StepperMotor::FWD,1000); //Leve recuo 00479 motorZ->wait_while_active(); 00480 motorZ->set_home(); // Seta posição de Home 00481 int HomePosition = motorZ->get_position(); 00482 printf("Posicao Home = %d\r\n",HomePosition); //Verificar que HomePosition = 0 00483 referZ = false; 00484 break; //Quebra do loop while, pois referenciamento do motor foi feito 00485 } 00486 00487 } 00488 00489 while(1) { 00490 00491 // Motor continua andando em uma só direção enquanto variavel referX estiver 00492 // em FALSE 00493 00494 InterruptIn FDC(PC_5); 00495 FDC.fall(&motorX_off); 00496 FDC.mode(PullUp); 00497 00498 if (referX == false) { 00499 motorX->run(StepperMotor::BWD); 00500 motorX->wait_while_active(); 00501 } 00502 00503 00504 // Se a interrupção for chamada, a variavel referX se torna TRUE, acionando 00505 // os comandos a seguir. 00506 00507 else { 00508 motorX->move(StepperMotor::FWD,1000); //Leve recuo 00509 motorX->wait_while_active(); 00510 motorX->set_home(); // Seta posição de Home 00511 int HomePosition = motorX->get_position(); 00512 referX = false; 00513 break; //Quebra do loop while, pois referenciamento do motor foi feito 00514 } 00515 00516 } 00517 00518 referY = false; //Caso os botôes de fim de curso sejam apertados sem querer antes de seus zeramentos, tem certeza que vai entrar no loop, ja que são interrupçõs 00519 00520 while(1) { 00521 00522 00523 InterruptIn FDC(PC_5); 00524 FDC.fall(&motorY_off); 00525 FDC.mode(PullUp); 00526 //Motor continua andando em uma só direção enquanto variavel referX estiver 00527 // em FALSE 00528 00529 if (referY == false) { 00530 motorY->run(StepperMotor::BWD); 00531 motorY->wait_while_active(); 00532 } 00533 00534 // Se a interrupção for chamada, a variavel referX se torna TRUE, acionando 00535 // os comandos a seguir. 00536 00537 else { 00538 motorY->move(StepperMotor::FWD,1000); //Leve recuo 00539 motorY->wait_while_active(); 00540 motorY->set_home(); // Seta posição de Home 00541 int HomePosition = motorY->get_position(); 00542 printf("Posicao Home = %d\r\n", HomePosition); //Verificar que HomePosition = 0 00543 referY = false; 00544 break; //Quebra do loop while, pois referenciamento do motor foi feito 00545 } 00546 00547 } 00548 } 00549 00550 /* FUNÇÃO "muda_velocidade(void)": 00551 1-) Acrescenta-se 1 à variavel "change", que indica qual dos sets será sele- 00552 cionado. 00553 2-) De acordo com o valor da variável "change", um dos sets é ativado para 00554 todos os motores. 00555 3-) De acordo com o valor da variáve l "change", um dos três leds é aceso 00556 para indicar a velocidade atual. 00557 */ 00558 00559 void muda_velocidade(void) 00560 { 00561 change += 1; 00562 00563 // O valor máximo de "change" é 2, então ao chegar em 3, é zerado novamente 00564 if (change == 3) { 00565 change = 0; 00566 } 00567 set_aceleracoesZ(set[change].maxspeed/2,set[change].minspeed/2,set[change].ac/2,set[change].dc/2); 00568 set_aceleracoesX(set[change].maxspeed,set[change].minspeed,set[change].ac,set[change].dc); 00569 set_aceleracoesY(set[change].maxspeed,set[change].minspeed,set[change].ac,set[change].dc); 00570 00571 switch(change) { 00572 case 0: { 00573 DigitalOut LED1(PC_1); 00574 LED1 = 1; 00575 DigitalOut LED2(PA_1); 00576 LED2 = 0; 00577 DigitalOut LED3(PA_4); 00578 LED3 = 0; 00579 break; 00580 } 00581 case 1: { 00582 DigitalOut LED1(PC_1); 00583 LED1 = 0; 00584 DigitalOut LED2(PA_1); 00585 LED2 = 1; 00586 DigitalOut LED3(PA_4); 00587 LED3 = 0; 00588 break; 00589 } 00590 case 2: { 00591 DigitalOut LED1(PC_1); 00592 LED1 = 0; 00593 DigitalOut LED2(PA_1); 00594 LED2 = 0; 00595 DigitalOut LED3(PA_4); 00596 LED3 = 1; 00597 break; 00598 } 00599 } 00600 00601 } 00602 00603 /* FUNÇÃO "ativa_eixoN(void)": 00604 -> Desativa a variável referente aos outros eixos, setando-as como "false", 00605 e ativa a do eixo N, setando-a como TRUE 00606 */ 00607 00608 void ativa_eixoX(void) 00609 { 00610 dirx = true; 00611 dirz = false; 00612 diry = false; 00613 muda_velocidade(); 00614 } 00615 00616 void ativa_eixoY(void) 00617 { 00618 dirx = false; 00619 dirz = false; 00620 diry = true; 00621 muda_velocidade(); 00622 } 00623 00624 void ativa_eixoZ(void) 00625 { 00626 dirx = false; 00627 dirz = true; 00628 diry = false; 00629 muda_velocidade(); 00630 } 00631 00632 /* FUNÇÃO "selecao_funcao(void)": 00633 -> A função apenas coloca o valor de "enable" em TRUE. No loop principal do 00634 programa, o enable em TRUE permite a seleção de alguma das funções do menu 00635 por parte do usuário. 00636 */ 00637 00638 void selecao_funcao(void) 00639 { 00640 enable = true; 00641 } 00642 00643 /* FUNÇÃO "disco_disco(void)": 00644 -> Função completamente inútil, feita apenas para divertir o usuário; 00645 */ 00646 00647 void disco_disco(void) { 00648 unsigned char i = 0; 00649 while (i < 50) { 00650 lcd.cls(); 00651 lcd.setBacklight(TextLCD::LightOn); 00652 lcd.printf(" DI$CO DI$CO DI$CO"); 00653 lcd.locate(0,1); 00654 lcd.printf(" DI$CO DI$CO DI$CO"); 00655 lcd.locate(0,2); 00656 lcd.printf(" DI$CO DI$CO DI$CO"); 00657 lcd.locate(0,3); 00658 lcd.printf(" DI$CO DI$CO DI$CO"); 00659 wait(0.05); 00660 lcd.setBacklight(TextLCD::LightOff); 00661 wait(0.05); 00662 i += 1; 00663 } 00664 lcd.setBacklight(TextLCD::LightOn); 00665 } 00666 00667 /* FUNÇÃO "menu_dinamico(char n)": 00668 -> Um "menu_dinamico" é considerado, neste programa, como um menu em que o 00669 usuario consegue movimentar o cursor e selecionar funções (ou seja, é a 00670 parte interativa do menu). 00671 1-) Os botões "Confirma","Jog_button_pos" e "Jog_button_neg" são setados para 00672 chamar certas funções relacionadas à navegação no menu ao detectar uma 00673 borda de subida (comando "rise"); 00674 2-) Há dois menus dinâmicos no projeto: 00675 A-) A tela inicial, contendo as opções: 00676 ->Cycle Start (inicia a operação ciclica de Pick/Place); 00677 ->Set positions (transição para o próximo menu dinâmico); 00678 ->Referenciamento (realiza operação de zeramento dos eixos novamente); 00679 ->Disco Disco! (executa a função "disco_disco"); 00680 B-) A tela referente às posições à serem salvas: 00681 ->Set Pick (inicia o jog para salvar a posição de Pick); 00682 ->Set Drop 1 (inicia o jog para salvar a posição de Drop 1); 00683 ->Set Drop 2 (inicia o jog para salvar a posição de Drop 2); 00684 ->Set Drop 3 (inicia o jog para salvar a posição de Drop 3); 00685 3-) A variável "n" que entra como input da função define qual dos menus é 00686 chamado. 00687 */ 00688 00689 void menu_dinamico(char n) 00690 { 00691 00692 confirma.fall(&selecao_funcao); 00693 jog_button_pos.fall(&sobe_cursor); 00694 jog_button_neg.fall(&desce_cursor); 00695 00696 switch(n) { 00697 case 0: { 00698 lcd.setCursor(TextLCD::CurOn_BlkOn); 00699 lcd.cls(); 00700 lcd.locate(1,0); 00701 lcd.printf("->Cycle start"); 00702 lcd.locate(1,1); 00703 lcd.printf("->Set positions"); 00704 lcd.locate(1,2); 00705 lcd.printf("->Referenciamento"); 00706 lcd.setAddress(0,ref_cursor); 00707 lcd.locate(1,3); 00708 lcd.printf("->DISCO DISCO!"); 00709 lcd.setAddress(0,ref_cursor); 00710 break; 00711 } 00712 case 1: { 00713 lcd.setCursor(TextLCD::CurOn_BlkOn); 00714 lcd.cls(); 00715 lcd.locate(1,0); 00716 lcd.printf("->Set Pick"); 00717 lcd.locate(1,1); 00718 lcd.printf("->Set Drop 1"); 00719 lcd.locate(1,2); 00720 lcd.printf("->Set Drop 2"); 00721 lcd.locate(1,3); 00722 lcd.printf("->Set Drop 3"); 00723 lcd.setAddress(0,ref_cursor); 00724 break; 00725 } 00726 case 2: { 00727 lcd.setCursor(TextLCD::CurOn_BlkOn); 00728 lcd.cls(); 00729 lcd.locate(1,0); 00730 lcd.printf("->Ciclo infinito"); 00731 lcd.locate(1,1); 00732 lcd.printf("->Ciclo unico"); 00733 lcd.setAddress(0,ref_cursor); 00734 break; 00735 } 00736 } 00737 } 00738 00739 /*FUNÇÕES "cycle_stop(void)" E "cycle(char n)": 00740 A-) "cycle_stop(void)": função seta a variável "ref_cycle" como FALSE, parâ- 00741 metro que irá finalizar o ciclo ao final da rotina; 00742 B-) "cycle": 00743 -> Seta o botão "back" para chamar a função "cycle_stop" e finalizar a 00744 operação em ciclo; 00745 1-) Leva o motor para a posição de HOME (apenas uma vez); 00746 2-) Motor vai até a posição de PICK; 00747 3-) Ativa a função "reconhecimento_peca()" para determinar aonde a peça 00748 será levada (posição de DROP); 00749 4-) Vai para a posição de DROP e solta a peça; 00750 5-) Retorna para o PICK, reiniciando o ciclo; 00751 -> OBS: A função "cycle" recebe um parâmetro n. Se esse parâmetro for 1, o 00752 ciclo é realizado apenas uma vez. Se for 0, o ciclo se repetirá até o u- 00753 suário pressionar o botão de "back". 00754 */ 00755 00756 void cycle_stop(void) 00757 { 00758 ref_cycle = false; 00759 } 00760 00761 void cycle(char n) 00762 { 00763 Servo garra(PA_11); // Declaração do servo 00764 garra.calibrate(0.001,90); // Calibração de sua abertura 00765 00766 back_btn.fall(&cycle_stop); 00767 00768 if (n == 0) { 00769 menu_passivo(3); // Ciclo infinito 00770 } 00771 00772 if (n == 1) { 00773 menu_passivo(4); // Ciclo único 00774 } 00775 00776 int tag; // Tag que sairá como resultado da função de reconhecimento da peça 00777 00778 printf("Comeco do ciclo!\r\n"); 00779 00780 //Alta velocidade para retornar para a posição de home 00781 00782 set_aceleracoesZ(set[2].maxspeed/2,set[2].minspeed/2,set[2].ac/2,set[2].dc/2); 00783 set_aceleracoesX(set[2].maxspeed,set[2].minspeed,set[2].ac,set[2].dc); 00784 set_aceleracoesY(set[2].maxspeed,set[2].minspeed,set[2].ac,set[2].dc); 00785 00786 motorZ->go_home(); 00787 motorZ->wait_while_active(); 00788 00789 motorX->go_home(); 00790 motorX->wait_while_active(); 00791 00792 motorY->go_home(); 00793 motorY->wait_while_active(); 00794 00795 00796 // Seta velocidaes/acelerações para o ciclo 00797 00798 set_aceleracoesZ(set[0].maxspeed,set[0].minspeed,set[0].ac,set[0].dc); 00799 set_aceleracoesX(set[1].maxspeed,set[1].minspeed,set[1].ac,set[1].dc); 00800 set_aceleracoesY(set[1].maxspeed,set[1].minspeed,set[1].ac,set[1].dc); 00801 00802 ref_cycle = true; 00803 00804 garra = 1; 00805 00806 while(1) { 00807 00808 // Vai para a posição de PICK 00809 motorX->go_to(PickPos.posx); 00810 motorX->wait_while_active(); 00811 motorY->go_to(PickPos.posy); 00812 motorY->wait_while_active(); 00813 motorZ->go_to(PickPos.posz - 1000); 00814 motorZ->wait_while_active(); 00815 00816 tag = reconhecimento_peca(); // Reconhece a peça e qual posição de Drop irá 00817 garra = 0.7; // Fecha a garra 00818 wait(1); 00819 00820 // Vai para a posição de DROP 00821 motorZ->move(StepperMotor::BWD,3000); 00822 motorZ->wait_while_active(); 00823 motorY->go_to(DropPos[tag].posy); 00824 motorY->wait_while_active(); 00825 motorX->go_to(DropPos[tag].posx); 00826 motorX->wait_while_active(); 00827 motorZ->go_to(DropPos[tag].posz); 00828 motorZ->wait_while_active(); 00829 wait(1); 00830 garra = 1; // Garra abre e deixa o objeto 00831 00832 /*Se a chamada para finalizar o ciclo foi chamada, volta-se para o menu 00833 inicial e quebra o loop while; */ 00834 00835 if ((ref_cycle == false) || (n == 1)) { 00836 enable = false; 00837 menu_dinamico(ref_menu); 00838 break; 00839 } 00840 00841 } 00842 } 00843 00844 /* FUNÇÕES DE "jog_(...)": 00845 -> Chama o layout para o menu do jog; 00846 -> O botão "Confirma" é setado para salvar a posição; 00847 -> Basicamente, cada botão de jog, ao ser segurado (borda de descida) faz o motor 00848 seguir em movimento. Ao ser solto (borda de subida) faz o motor parar; 00849 -> Habilitam-se os botões dos eixos para que o usuário possa mover um eixo de 00850 cada vez. Quando o usuario apertar um desses botões, a velocidade é alterada 00851 também; 00852 */ 00853 00854 void paradaZ(void) 00855 { 00856 motorZ->hard_stop(); 00857 wait(1); 00858 int posicao = motorZ->get_position(); 00859 if (posicao < 0) { 00860 motorZ->move(StepperMotor::FWD,2000); 00861 } 00862 else { 00863 motorZ->move(StepperMotor::BWD,2000); 00864 } 00865 } 00866 00867 void paradaX(void) 00868 { 00869 motorX->hard_stop(); 00870 wait(1); 00871 int posicao = motorX->get_position(); 00872 if (posicao < 0) { 00873 motorX->move(StepperMotor::FWD,3000); 00874 } 00875 else { 00876 motorX->move(StepperMotor::BWD,3000); 00877 } 00878 } 00879 void paradaY(void) 00880 { 00881 motorY->hard_stop(); 00882 wait(1); 00883 int posicao = motorY->get_position(); 00884 if (posicao < 0) { 00885 motorY->move(StepperMotor::FWD,3000); 00886 } 00887 else { 00888 motorY->move(StepperMotor::BWD,3000); 00889 } 00890 } 00891 00892 void jog(char n) { 00893 menu_jog(); 00894 lcd.locate(3,0); 00895 /* 00896 De acordo com o valor de entrada "n", seta-se o botão "Confirma" para 00897 salvar a posição de Save,Drop1, Drop2 ou Drop3; 00898 */ 00899 InterruptIn confirma(PC_13); 00900 confirma.mode(PullUp); 00901 00902 switch(n) { 00903 case 0: { 00904 printf("Posicao de Save\r\n"); 00905 lcd.printf("PICK POSITION"); 00906 confirma.fall(&save_pick_pos); 00907 break; 00908 } 00909 case 1: { 00910 lcd.locate(3,0); 00911 lcd.printf("DROP POSITION %d",n); 00912 confirma.fall(&save_drop1); 00913 break; 00914 } 00915 case 2: { 00916 lcd.locate(3,0); 00917 lcd.printf("DROP POSITION %d",n); 00918 confirma.fall(&save_drop2); 00919 break; 00920 } 00921 case 3: { 00922 lcd.locate(3,0); 00923 lcd.printf("DROP POSITION %d",n); 00924 confirma.fall(&save_drop3); 00925 break; 00926 } 00927 } 00928 00929 InterruptIn jog_button_pos(PC_12); 00930 jog_button_pos.mode(PullUp); 00931 InterruptIn jog_button_neg(PA_15); 00932 jog_button_neg.mode(PullUp); 00933 00934 jog_button_pos.fall(&jog_pos_on); 00935 jog_button_neg.fall(&jog_neg_on); 00936 00937 jog_button_pos.rise(&jog_pos_off); 00938 jog_button_neg.rise(&jog_neg_off); 00939 00940 btnX.fall(&ativa_eixoX); 00941 btnY.fall(&ativa_eixoY); 00942 btnZ.fall(&ativa_eixoZ); 00943 00944 while(save_pos == false) { 00945 00946 float posz = motorZ->get_position(); 00947 float posx = motorX->get_position(); 00948 float posy = motorY->get_position(); 00949 lcd.locate(3,1); 00950 lcd.printf("%.2f mm",posx*3/800); 00951 lcd.locate(3,2); 00952 lcd.printf("%.2f mm",posy*3/800); 00953 lcd.locate(3,3); 00954 lcd.printf("%.2f mm",posz*5/800); 00955 00956 if (jog_pos == true) { 00957 if (dirx == true) { 00958 InterruptIn FDC(PC_5); 00959 FDC.mode(PullUp); 00960 FDC.fall(¶daX); 00961 motorX->run(StepperMotor::FWD); 00962 motorX->wait_while_active(); 00963 } 00964 if (diry == true) { 00965 InterruptIn FDC(PC_5); 00966 FDC.mode(PullUp); 00967 FDC.fall(¶daY); 00968 motorY->run(StepperMotor::FWD); 00969 motorY->wait_while_active(); 00970 } 00971 if (dirz == true) { 00972 InterruptIn FDC(PC_5); 00973 FDC.mode(PullUp); 00974 FDC.fall(¶daZ); 00975 motorZ->run(StepperMotor::FWD); 00976 motorZ->wait_while_active(); 00977 } 00978 } 00979 00980 if (jog_neg == true) { 00981 if (dirx == true) { 00982 InterruptIn FDC(PC_5); 00983 FDC.mode(PullUp); 00984 FDC.fall(¶daX); 00985 motorX->run(StepperMotor::BWD); 00986 motorX->wait_while_active(); 00987 } 00988 if (diry == true) { 00989 InterruptIn FDC(PC_5); 00990 FDC.mode(PullUp); 00991 FDC.fall(¶daY); 00992 motorY->run(StepperMotor::BWD); 00993 motorY->wait_while_active(); 00994 } 00995 if (dirz == true) { 00996 InterruptIn FDC(PC_5); 00997 FDC.mode(PullUp); 00998 FDC.fall(¶daZ); 00999 motorZ->run(StepperMotor::BWD); 01000 motorZ->wait_while_active(); 01001 } 01002 } 01003 } 01004 save_pos = false; 01005 ref_menu = 1; 01006 flag = true; 01007 conclusao(n); 01008 menu_dinamico(ref_menu); 01009 } 01010 01011 /* FUNÇÃO "back_op(void)": 01012 -> Se a tela for referente a um sub-menu, a função irá fazer retornar para o 01013 menu principal. Caso contrário, nada ocorre; 01014 */ 01015 01016 void back_op(void) 01017 { 01018 ref_cursor = 4; // O valor de ref_cursor em 4 chama um case que chama a primeira tela dinâmica; 01019 enable = true; 01020 printf("BACK\r\n"); 01021 } 01022 01023 int main() 01024 { 01025 //Prepara os 3 sets de velocidade, com velocidaes e acelerações variadas. 01026 01027 set[0].maxspeed = 2000; 01028 set[0].minspeed = 1000; 01029 set[0].ac = 100; 01030 set[0].dc = 100; 01031 01032 set[1].maxspeed = 4000; 01033 set[1].minspeed = 3000; 01034 set[1].ac = 100; 01035 set[1].dc = 100; 01036 01037 set[2].maxspeed = 4200; 01038 set[2].minspeed = 3500; 01039 set[2].ac = 100; 01040 set[2].dc = 100; 01041 01042 01043 //Seta comunicação SPI 01044 DevSPI dev_spi(D11, D12, D13); 01045 01046 //Inicialização dos componentes dos motores 01047 motorZ = new L6474(D2, D8, D7, D9, D10, dev_spi); 01048 motorX = new L6474(D2, D8, D4, D3, D10, dev_spi); 01049 motorY = new L6474(D2, D8, D5, D6, D10, dev_spi); 01050 01051 if (motorZ->init(&init) != COMPONENT_OK) { 01052 exit(EXIT_FAILURE); 01053 } 01054 if (motorX->init(&init) != COMPONENT_OK) { 01055 exit(EXIT_FAILURE); 01056 } 01057 if (motorY->init(&init) != COMPONENT_OK) { 01058 exit(EXIT_FAILURE); 01059 } 01060 01061 // Seta todos os motores para que trabalhem com microstep de 8 01062 motorZ->set_step_mode(StepperMotor::STEP_MODE_1_4); 01063 motorX->set_step_mode(StepperMotor::STEP_MODE_1_4); 01064 motorY->set_step_mode(StepperMotor::STEP_MODE_1_4); 01065 01066 //Seta velocidades e acelerações inciciais 01067 set_aceleracoesZ(set[0].maxspeed,set[0].minspeed,set[0].ac,set[0].dc); 01068 set_aceleracoesX(set[0].maxspeed,set[0].minspeed,set[0].ac,set[0].dc); 01069 set_aceleracoesY(set[0].maxspeed,set[0].minspeed,set[0].ac,set[0].dc); 01070 01071 lcd.setCursor(TextLCD::CurOn_BlkOn); // Liga o cursor 01072 01073 lcd.setBacklight(TextLCD::LightOn); // Liga o backlight do LCD 01074 lcd.setAddress(0,0); 01075 lcd.setCursor(TextLCD::CurOff_BlkOff); // Desliga o cursor para o menu estático 01076 menu_passivo(1); 01077 01078 lcd.setCursor(TextLCD::CurOn_BlkOn); // Liga o cursor novamente pro usuario poder mexe-lo 01079 menu_dinamico(0); 01080 01081 01082 /* Loops principais do funcionamento do motor: 01083 01084 -> Os dois loops aninhados (while e do_while) definem o funcionamento conti- 01085 nuo da máquina. 01086 -> O funcionamento geral é o seguinte: 01087 1-) O do_while depende de um parametro booleano chamado "flag". O flag 01088 permanece em TRUE até alguma função do menu ser chamada. Qualquer fun- 01089 ção chamada no Menu que resulte em uma ação seta o flag como FALSE. 01090 Por exemplo, cliquar em alguma opção do menu que leve para outro sub 01091 menu não setaria o "flag" como FALSE, pois nenhuma ação real foi feita. 01092 Agora, entrar em qualquer operação de jog ou de ciclo, setaria a variavel 01093 em FALSE, finalizando o do_while após o término da ação. 01094 2-) Para evitar que a máquina pare de funcionar depois do término de uma ação, 01095 aninha-se o do_while em um loop infinito while(1). Ao sair do do_while, o 01096 flag retorna para TRUE, permitindo que o usuario possa escolher alguma ação 01097 novamente. 01098 -> Variaveis importantes: 01099 a) "ref_menu": Seu valor indica em qual dos menus o usuário está no momento; 01100 b) "ref_cursor": Seu valor indica em qual das linhas o cursor está localizado; 01101 c) "enable": A variavel "enable" possui FALSE como estado padrão. Quando o botão 01102 de "confirma" for pressionado, ele comuta para TRUE. Quando isso acontece, 01103 avalia-se o valor de "ref_menu" e "ref_cursor" para indicar que ação deve 01104 ocorrer naquele momento (ir para outro submenu, referenciar, jog, etc.). 01105 Seu valor sempre retorna para FALSE após qualquer operação ou ao fim do 01106 do_while; 01107 -> Cada menu dinâmico disponivel tem seu aninhamento com switch-case para avaliar 01108 as funções que podem ser chamadas dentro dele; 01109 -> OBS: O ref_cursor só vai de 0 a 3 (linha 1 a 4 do LCD). Entretanto, coloca-se nos 01110 dois sub-menus um case em que ref_cursor vale 4. No uso normal do cursor, isso nunca 01111 vai ocorrer. Esse valor é SETADO para o ref_cursor forçadamente quando o usuario apertar 01112 o botão de BACK. Isso faz com que acione-se uma operação unica para este botão, retornando 01113 para o menu principal. 01114 */ 01115 while(1) { 01116 01117 /* Redeclaração da maioria dos pinos. Isso é feito para evitar qualquer 01118 confito entre as chamadas de cada pino. Muitos são desativados quando 01119 o sensor RGB é declarado, então esse processo faz com que nenhuma função 01120 seja perdida no meio do uso da máquina */ 01121 01122 InterruptIn confirma(PC_13); 01123 confirma.mode(PullUp); 01124 InterruptIn jog_button_pos(PC_12); 01125 jog_button_pos.mode(PullUp); 01126 InterruptIn jog_button_neg(PA_15); 01127 jog_button_neg.mode(PullUp); 01128 InterruptIn btnX(PC_3); // Botão para selecionar o eixo X 01129 btnX.mode(PullUp); 01130 InterruptIn btnY(PC_2); // Botão para selecionar o eixo Y 01131 btnY.mode(PullUp); 01132 InterruptIn btnZ(PC_0); // Botão para selecionar o eixo Z 01133 btnZ.mode(PullUp); 01134 01135 InterruptIn back_btn(PB_7); 01136 back_btn.mode(PullUp); 01137 01138 confirma.fall(&selecao_funcao); 01139 01140 jog_button_pos.fall(&sobe_cursor); 01141 jog_button_neg.fall(&desce_cursor); 01142 01143 btnX.fall(&ativa_eixoX); 01144 btnY.fall(&ativa_eixoY); 01145 btnZ.fall(&ativa_eixoZ); 01146 01147 do { 01148 wait(0.1); 01149 lcd.locate(0,ref_cursor); // Movimentação do cursor 01150 01151 // Menu prinicipal 01152 if (ref_menu == 0) { 01153 if (enable == true) { 01154 switch(ref_cursor) { 01155 case 0: { 01156 // Mudança para o submenu com as opções de ciclo 01157 ref_cursor = 0; 01158 lcd.locate(0,ref_cursor); 01159 ref_menu = 2; 01160 menu_dinamico(ref_menu); 01161 enable = false; 01162 break; 01163 } 01164 case 1: { 01165 // Mudança para o submenu com as 4 posições a serem salvas 01166 ref_cursor = 0; 01167 lcd.locate(0,ref_cursor); 01168 ref_menu = 1; 01169 menu_dinamico(ref_menu); 01170 enable = false; 01171 break; 01172 } 01173 case 2: { 01174 // Operação de referenciamento 01175 //int tag = reconhecimento_peca(); 01176 seta_origem(); 01177 flag = false; 01178 break; 01179 } 01180 case 3: { 01181 // Operação disco-disco 01182 disco_disco(); 01183 flag = false; 01184 break; 01185 } 01186 } 01187 } 01188 } 01189 01190 // Sub-menu para as posições a serem salvas 01191 01192 if(ref_menu == 1) { 01193 back_btn.mode(PullUp); 01194 back_btn.fall(&back_op); 01195 if (enable == true) { 01196 switch(ref_cursor) { 01197 case 0: { 01198 // Posição de Pick 01199 jog(0); 01200 flag = false; 01201 InterruptIn back_btn(PB_7); 01202 back_btn.mode(PullUp); 01203 back_btn.fall(&back_op); 01204 break; 01205 } 01206 case 1: { 01207 // Posição de Drop 1 01208 jog(1); 01209 flag = false; 01210 InterruptIn back_btn(PB_7); 01211 back_btn.mode(PullUp); 01212 back_btn.fall(&back_op); 01213 break; 01214 } 01215 case 2: { 01216 // Posição de Drop 2 01217 jog(2); 01218 flag = false; 01219 InterruptIn back_btn(PB_7); 01220 back_btn.mode(PullUp); 01221 back_btn.fall(&back_op); 01222 break; 01223 } 01224 case 3: { 01225 // Posição de Drop 3 01226 jog(3); 01227 flag = false; 01228 InterruptIn back_btn(PB_7); 01229 back_btn.mode(PullUp); 01230 back_btn.fall(&back_op); 01231 break; 01232 } 01233 case 4: { 01234 // Case para quando botão BACK for pressionado. Retorna para o menu inicial 01235 ref_cursor = 0; 01236 lcd.locate(0,ref_cursor); 01237 ref_menu = 0; 01238 menu_dinamico(ref_menu); 01239 enable = false; 01240 break; 01241 } 01242 } 01243 } 01244 } 01245 01246 if (ref_menu == 2) { 01247 back_btn.fall(&back_op); 01248 back_btn.mode(PullUp); 01249 if (enable == true) { 01250 switch(ref_cursor) { 01251 case 0: { 01252 // Opção para ciclo infinito 01253 cycle(0); 01254 flag = false; 01255 break; 01256 } 01257 case 1: { 01258 // Opção para ciclo único 01259 cycle(1); 01260 flag = false; 01261 break; 01262 } 01263 case 4: { 01264 // Case para quando botão BACK for pressionado. Retorna para o menu inicial 01265 ref_cursor = 0; 01266 lcd.locate(0,ref_cursor); 01267 ref_menu = 0; 01268 menu_dinamico(ref_menu); 01269 enable = false; 01270 break; 01271 } 01272 } 01273 } 01274 } 01275 01276 } while(flag == true); 01277 01278 flag = true; 01279 enable = false; 01280 menu_dinamico(ref_menu); 01281 } 01282 }
Generated on Thu Jul 28 2022 19:44:49 by
1.7.2
