Вы находитесь на странице: 1из 36

Códigos ejemplo para el robot Pololu Zumo 32U4

Laboratorio Remoto de Robótica Móvil

Escuela de Ciencias Básicas, Tecnología e Ingeniería (ECBTI)


Universidad Nacional Abierta y a Distancia (UNAD)

Semillero Industria 4.0 - CEAD Medellín

7 de noviembre de 2019
Índice general

Información general 2

Códigos ejemplo para el robot Pololu Zumo 32U4 4


Botones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Demostración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Encoders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Seguidor de línea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Prueba sensor de línea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Control remoto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

i
Indice de Códigos

1. Botones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Demostración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3. Encoders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4. Seguidor de línea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5. Prueba sensor de línea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6. Control remoto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

ii
Códigos ejemplo para el robot
Pololu Zumo 32U4

1
Información general

Figura 1: Pololu Zumo 32U4

El robot Zumo 32U4 es un robot completo y versátil controlado por un microcontrolador ATmega32U4 compatible
con Arduino. Cuando se ensambla, el robot con seguimiento de bajo perfil mide menos de 10 cm en cada lado, por lo
que es adecuado para competiciones de Mini-Sumo.
En el corazón del Zumo 32U4 hay un microcontrolador AVR ATmega32U4 integrado de Atmel, junto con dos
controladores de puente H que alimentan los motores del robot. El robot también presenta una variedad de sensores,
incluidos codificadores de cuadratura y sensores de inercia (acelerómetro y giroscopio) en la placa principal, junto con
sensores de reflectancia y proximidad en la matriz de sensores frontal. Los botones pulsadores integrados ofrecen una
interfaz conveniente para la entrada del usuario, y una pantalla LCD, un zumbador y LED indicadores le permiten
al robot proporcionar retroalimentación.

2
INDICE DE CÓDIGOS 3

Al igual que nuestros controladores programables A-Star 32U4 [https://www.pololu.com/category/149/


a-star-programmablecontrollers], el Zumo 32U4 presenta una interfaz USB y viene precargado con un
cargador de arranque compatible con Arduino.
Proporcionamos un complemento de software que facilita la programación del Zumo 32U4 desde el entorno Arduino,
así como un conjunto de bibliotecas Arduino para ayudar a interactuar con su hardware integrado.
Comparación con el kit de robot Zumo para Arduino (con Zumo Shield)
Nuestro robot Zumo más antiguo para Arduino [https://www.pololu.com/product/2510], construido con un
escudo Zumo [https://www.pololu.com/product/2508], es otra plataforma robótica compatible con Arduino
basado en el chasis Zumo.
El Zumo Shield está diseñado para una placa con un factor de forma Arduino estándar, como un Arduino Uno
[https://www.pololu.com/product/2191], Arduino Leonardo [https://www.pololu.com/product/2192] o
A-Star 32U4 Prime [https://www.pololu.com/category/165/a-star-32u4-prime], para enchufarlo y
actuar como su controlador.
Por el contrario, el Zumo 32U4 incluye un microcontrolador ATmega32U4 incorporado (el mismo que se usa en los
tableros Leonardo y A-Star 32U4), combinando las funciones del Zumo Shield y el controlador Arduino en una sola
placa y habilitando el robot resultante para ser aún más compacto. Sin embargo, sigue siendo tan fácil de programar
como un Arduino estándar, gracias a su interfaz USB y al gestor de arranque precargado compatible con Arduino. El
Zumo 32U4 también agrega muchas características que no se encuentran en el Zumo Shield, incluidos codificadores,
una pantalla LCD y detección de proximidad.
Algunas de las asignaciones de pines y las bibliotecas de software difieren entre el Zumo 32U4 y el robot Zumo para
Arduino, por lo que los programas escritos para un robot generalmente deben modificarse para funcionar en el otro.
Códigos ejemplo para el robot
Pololu Zumo 32U4

Todos estos ejemplos los pueden consultar directamente en el IDE de Arduino, una vez descarguen e instalen la
biblioteca correspondiente.

Figura 2: Ejemplos Zumo 32U4 en el IDE de Arduino

Botones
1 /* This example demonstrates three different ways to
2 interface with a user pushbutton on the Zumo 32U4. */
3
4 #include <Wire.h>
5 #include <Zumo32U4.h>
6

4
INDICE DE CÓDIGOS 5

7 // These objects provide access to the Zumo 32U4’s


8 // on-board buttons.
9 Zumo32U4ButtonA buttonA;
10 Zumo32U4ButtonB buttonB;
11 Zumo32U4ButtonC buttonC;
12 Zumo32U4LCD lcd;
13
14 void setup()
15 {
16 lcd.clear();
17 lcd.print(F("Press A"));
18
19 /* Method 1: Use the waitForButton() function, which blocks and
20 * doesn’t return until a button press and release are
21 * detected. This function takes care of button debouncing. */
22 buttonA.waitForButton();
23
24 lcd.clear();
25 }
26
27 void loop()
28 {
29 /* Method 2: Directly read the state of the button with the
30 * isPressed() function. This method is non-blocking and
31 * provides no debouncing. */
32 if (buttonB.isPressed())
33 {
34 // Whenever the button is pressed, turn on the yellow LED.
35 ledYellow(1);
36 }
37 else
38 {
39 // Whenever the button is not pressed, turn off the yellow
40 // LED.
41 ledYellow(0);
42 }
43
44 /* Method 3: Call getSingleDebouncedPress() regularly in a
45 * loop, which returns true to report a single button press or
46 * false otherwise. This function is non-blocking and takes
47 * care of button debouncing. */
48 static int cPressedCount = 0;
49 if (buttonC.getSingleDebouncedPress())
50 {
51 cPressedCount += 1;
52 Serial.print(F("Button C was pressed "));
53 Serial.print(cPressedCount);
54 Serial.println(F(" times."));
55
56 lcd.clear();
57 lcd.print(cPressedCount);
58 }
59
60 /* If you use non-blocking functions like isPressed() and
61 * getSingleDebouncedPress(), then you can monitor multiple
62 * buttons at the same time and also take care of other tasks
INDICE DE CÓDIGOS 6

63 * at the same time. In this example, we blink the red LED


64 * while monitoring the buttons. */
65 ledRed(millis() % 1024 < 100);
66 }
Código 1: Botones

Demostración
1 /* This demo program shows many features of the Zumo 32U4.
2
3 It uses the buttons, LCD, and buzzer to provide a user interface.
4 It presents a menu to the user that lets the user select from
5 several different demos.
6
7 To use this demo program, you will need to have the LCD connected
8 to the Zumo 32U4. If you cannot see any text on the LCD,
9 try rotating the contrast potentiometer. */
10
11 #include <Wire.h>
12 #include <Zumo32U4.h>
13
14 Zumo32U4LCD lcd;
15 Zumo32U4Buzzer buzzer;
16 Zumo32U4ButtonA buttonA;
17 Zumo32U4ButtonB buttonB;
18 Zumo32U4ButtonC buttonC;
19 Zumo32U4LineSensors lineSensors;
20 Zumo32U4ProximitySensors proxSensors;
21 LSM303 compass;
22 L3G gyro;
23 Zumo32U4Motors motors;
24 Zumo32U4Encoders encoders;
25
26 char buttonMonitor();
27
28 class Menu
29 {
30 public:
31 struct Item
32 {
33 const char * name;
34 void (* action)();
35 };
36
37 Menu(Item * items, uint8_t itemCount)
38 {
39 this->items = items;
40 this->itemCount = itemCount;
41 lcdItemIndex = 0;
42 }
43
44 void lcdUpdate(uint8_t index)
45 {
46 lcd.clear();
INDICE DE CÓDIGOS 7

47 lcd.print(items[index].name);
48 lcd.gotoXY(0, 1);
49 lcd.print(F("\x7f" "A \xa5" "B C\x7e"));
50 }
51
52 void action(uint8_t index)
53 {
54 items[index].action();
55 }
56
57 // Prompts the user to choose one of the menu items,
58 // then runs it, then returns.
59 void select()
60 {
61 lcdUpdate(lcdItemIndex);
62
63 while (1)
64 {
65 switch (buttonMonitor())
66 {
67 case ’A’:
68 // The A button was pressed so decrement the index.
69 if (lcdItemIndex == 0)
70 {
71 lcdItemIndex = itemCount - 1;
72 }
73 else
74 {
75 lcdItemIndex--;
76 }
77 lcdUpdate(lcdItemIndex);
78 break;
79
80 case ’C’:
81 // The C button was pressed so increase the index.
82 if (lcdItemIndex >= itemCount - 1)
83 {
84 lcdItemIndex = 0;
85 }
86 else
87 {
88 lcdItemIndex++;
89 }
90 lcdUpdate(lcdItemIndex);
91 break;
92
93 case ’B’:
94 // The B button was pressed so run the item and return.
95 action(lcdItemIndex);
96 return;
97 }
98 }
99 }
100
101 private:
102 Item * items;
INDICE DE CÓDIGOS 8

103 uint8_t itemCount;


104 uint8_t lcdItemIndex;
105 };
106
107
108 // A couple of simple tunes, stored in program space.
109 const char beepBrownout[] PROGMEM = "<c8";
110 const char beepWelcome[] PROGMEM = ">g32>>c32";
111 const char beepThankYou[] PROGMEM = ">>c32>g32";
112 const char beepButtonA[] PROGMEM = "!c32";
113 const char beepButtonB[] PROGMEM = "!e32";
114 const char beepButtonC[] PROGMEM = "!g32";
115
116 // Custom characters for the LCD:
117
118 // This character is a back arrow.
119 const char backArrow[] PROGMEM = {
120 0b00000,
121 0b00010,
122 0b00001,
123 0b00101,
124 0b01001,
125 0b11110,
126 0b01000,
127 0b00100,
128 };
129
130 // This character is two chevrons pointing up.
131 const char forwardArrows[] PROGMEM = {
132 0b00000,
133 0b00100,
134 0b01010,
135 0b10001,
136 0b00100,
137 0b01010,
138 0b10001,
139 0b00000,
140 };
141
142 // This character is two chevrons pointing down.
143 const char reverseArrows[] PROGMEM = {
144 0b00000,
145 0b10001,
146 0b01010,
147 0b00100,
148 0b10001,
149 0b01010,
150 0b00100,
151 0b00000,
152 };
153
154 // This character is two solid arrows pointing up.
155 const char forwardArrowsSolid[] PROGMEM = {
156 0b00000,
157 0b00100,
158 0b01110,
INDICE DE CÓDIGOS 9

159 0b11111,
160 0b00100,
161 0b01110,
162 0b11111,
163 0b00000,
164 };
165
166 // This character is two solid arrows pointing down.
167 const char reverseArrowsSolid[] PROGMEM = {
168 0b00000,
169 0b11111,
170 0b01110,
171 0b00100,
172 0b11111,
173 0b01110,
174 0b00100,
175 0b00000,
176 };
177
178 void loadCustomCharacters()
179 {
180 // The LCD supports up to 8 custom characters. Each character
181 // has a number between 0 and 7. We assign #7 to be the back
182 // arrow; other characters are loaded by individual demos as
183 // needed.
184
185 lcd.loadCustomCharacter(backArrow, 7);
186 }
187
188 // Assigns #0-6 to be bar graph characters.
189 void loadCustomCharactersBarGraph()
190 {
191 static const char levels[] PROGMEM = {
192 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 63, 63, 63
193 };
194 lcd.loadCustomCharacter(levels + 0, 0); // 1 bar
195 lcd.loadCustomCharacter(levels + 1, 1); // 2 bars
196 lcd.loadCustomCharacter(levels + 2, 2); // 3 bars
197 lcd.loadCustomCharacter(levels + 3, 3); // 4 bars
198 lcd.loadCustomCharacter(levels + 4, 4); // 5 bars
199 lcd.loadCustomCharacter(levels + 5, 5); // 6 bars
200 lcd.loadCustomCharacter(levels + 6, 6); // 7 bars
201 }
202
203 // Assigns #0-4 to be arrow symbols.
204 void loadCustomCharactersMotorDirs()
205 {
206 lcd.loadCustomCharacter(forwardArrows, 0);
207 lcd.loadCustomCharacter(reverseArrows, 1);
208 lcd.loadCustomCharacter(forwardArrowsSolid, 2);
209 lcd.loadCustomCharacter(reverseArrowsSolid, 3);
210 }
211
212 // Clears the LCD and puts [back_arrow]B on the second line
213 // to indicate to the user that the B button goes back.
214 void displayBackArrow()
INDICE DE CÓDIGOS 10

215 {
216 lcd.clear();
217 lcd.gotoXY(0,1);
218 lcd.print(F("\7B"));
219 lcd.gotoXY(0,0);
220 }
221
222 // Blinks all three LEDs in sequence.
223 void ledDemo()
224 {
225 displayBackArrow();
226
227 uint8_t state = 3;
228 static uint16_t lastUpdateTime = millis() - 2000;
229 while (buttonMonitor() != ’B’)
230 {
231 if ((uint16_t)(millis() - lastUpdateTime) >= 500)
232 {
233 lastUpdateTime = millis();
234 state = state + 1;
235 if (state >= 4) { state = 0; }
236
237 switch (state)
238 {
239 case 0:
240 buzzer.play("c32");
241 lcd.gotoXY(0, 0);
242 lcd.print(F("Red "));
243 ledRed(1);
244 ledGreen(0);
245 ledYellow(0);
246 break;
247
248 case 1:
249 buzzer.play("e32");
250 lcd.gotoXY(0, 0);
251 lcd.print(F("Green"));
252 ledRed(0);
253 ledGreen(1);
254 ledYellow(0);
255 break;
256
257 case 2:
258 buzzer.play("g32");
259 lcd.gotoXY(0, 0);
260 lcd.print(F("Yellow"));
261 ledRed(0);
262 ledGreen(0);
263 ledYellow(1);
264 break;
265 }
266 }
267 }
268
269 ledRed(0);
270 ledYellow(0);
INDICE DE CÓDIGOS 11

271 ledGreen(0);
272 }
273
274 void printBar(uint8_t height)
275 {
276 if (height > 8) { height = 8; }
277 static const char barChars[] = {’ ’, 0, 1, 2, 3, 4, 5, 6, 255};
278 lcd.print(barChars[height]);
279 }
280
281 // Display line sensor readings. Holding button C turns off
282 // the IR emitters.
283 void lineSensorDemo()
284 {
285 loadCustomCharactersBarGraph();
286 displayBackArrow();
287 lcd.gotoXY(6, 1);
288 lcd.print(’C’);
289
290 uint16_t lineSensorValues[3];
291 char c;
292
293 while (buttonMonitor() != ’B’)
294 {
295 bool emittersOff = buttonC.isPressed();
296
297 if (emittersOff)
298 {
299 lineSensors.read(lineSensorValues, QTR_EMITTERS_OFF);
300 }
301 else
302 {
303 lineSensors.read(lineSensorValues, QTR_EMITTERS_ON);
304 }
305
306 lcd.gotoXY(1, 0);
307 for (uint8_t i = 0; i < 3; i++)
308 {
309 uint8_t barHeight = map(lineSensorValues[i], 0, 2000, 0, 8);
310 printBar(barHeight);
311 lcd.print(’ ’);
312 }
313
314 // Display an indicator of whether emitters are on or
315 // off.
316 lcd.gotoXY(7, 1);
317 if (emittersOff)
318 {
319 lcd.print(’\xa5’); // centered dot
320 }
321 else
322 {
323 lcd.print(’*’);
324 }
325 }
326 }
INDICE DE CÓDIGOS 12

327
328 // Display proximity sensor readings.
329 void proxSensorDemo()
330 {
331 loadCustomCharactersBarGraph();
332 displayBackArrow();
333
334 while (buttonMonitor() != ’B’)
335 {
336 bool proxLeftActive = proxSensors.readBasicLeft();
337 bool proxFrontActive = proxSensors.readBasicFront();
338 bool proxRightActive = proxSensors.readBasicRight();
339 proxSensors.read();
340
341 lcd.gotoXY(0, 0);
342 printBar(proxSensors.countsLeftWithLeftLeds());
343 printBar(proxSensors.countsLeftWithRightLeds());
344 lcd.print(’ ’);
345 printBar(proxSensors.countsFrontWithLeftLeds());
346 printBar(proxSensors.countsFrontWithRightLeds());
347 lcd.print(’ ’);
348 printBar(proxSensors.countsRightWithLeftLeds());
349 printBar(proxSensors.countsRightWithRightLeds());
350
351 // On the last 3 characters of the second line, display
352 // basic readings of the sensors taken without sending
353 // IR pulses.
354 lcd.gotoXY(5, 1);
355 printBar(proxLeftActive);
356 printBar(proxFrontActive);
357 printBar(proxRightActive);
358 }
359 }
360
361 // Starts I2C and initializes the inertial sensors.
362 void initInertialSensors()
363 {
364 Wire.begin();
365 compass.init();
366 compass.enableDefault();
367 gyro.init();
368 gyro.enableDefault();
369 }
370
371 // Given 3 readings for axes x, y, and z, prints the sign
372 // and axis of the largest reading unless it is below the
373 // given threshold.
374 void printLargestAxis(int16_t x, int16_t y, int16_t z, uint16_t threshold)
375 {
376 int16_t largest = x;
377 char axis = ’X’;
378
379 if (abs(y) > abs(largest))
380 {
381 largest = y;
382 axis = ’Y’;
INDICE DE CÓDIGOS 13

383 }
384 if (abs(z) > abs(largest))
385 {
386 largest = z;
387 axis = ’Z’;
388 }
389
390 if (abs(largest) < threshold)
391 {
392 lcd.print(" ");
393 }
394 else
395 {
396 bool positive = (largest > 0);
397 lcd.print(positive ? ’+’ : ’-’);
398 lcd.print(axis);
399 }
400 }
401
402 // Print the direction of the largest rotation rate measured
403 // by the gyro and the up direction based on the
404 // accelerometer’s measurement of gravitational acceleration
405 // (assuming gravity is the dominant force acting on the
406 // Zumo).
407 void inertialDemo()
408 {
409 displayBackArrow();
410
411 lcd.gotoXY(3, 0);
412 lcd.print(F("Rot"));
413 lcd.gotoXY(4, 1);
414 lcd.print(F("Up"));
415
416 while (buttonMonitor() != ’B’)
417 {
418 compass.read();
419 gyro.read();
420
421 lcd.gotoXY(6, 0);
422 printLargestAxis(gyro.g.x, gyro.g.y, gyro.g.z, 2000);
423 lcd.gotoXY(6, 1);
424 printLargestAxis(compass.a.x, compass.a.y, compass.a.z, 200);
425 }
426 }
427
428 // Provides an interface to test the motors. Holding button A or C
429 // causes the left or right motor to accelerate; releasing the
430 // button causes the motor to decelerate. Tapping the button while
431 // the motor is not running reverses the direction it runs.
432 //
433 // If the showEncoders argument is true, encoder counts are
434 // displayed on the first line of the LCD; otherwise, an
435 // instructional message is shown.
436 void motorDemoHelper(bool showEncoders)
437 {
438 loadCustomCharactersMotorDirs();
INDICE DE CÓDIGOS 14

439 lcd.clear();
440 lcd.gotoXY(1, 1);
441 lcd.print(F("A \7B C"));
442
443 int16_t leftSpeed = 0, rightSpeed = 0;
444 int8_t leftDir = 1, rightDir = 1;
445 uint16_t lastUpdateTime = millis() - 100;
446 uint8_t btnCountA = 0, btnCountC = 0, instructCount = 0;
447
448 int16_t encCountsLeft = 0, encCountsRight = 0;
449 char buf[4];
450
451 while (buttonMonitor() != ’B’)
452 {
453 encCountsLeft += encoders.getCountsAndResetLeft();
454 if (encCountsLeft < 0) { encCountsLeft += 1000; }
455 if (encCountsLeft > 999) { encCountsLeft -= 1000; }
456
457 encCountsRight += encoders.getCountsAndResetRight();
458 if (encCountsRight < 0) { encCountsRight += 1000; }
459 if (encCountsRight > 999) { encCountsRight -= 1000; }
460
461 // Update the LCD and motors every 50 ms.
462 if ((uint16_t)(millis() - lastUpdateTime) > 50)
463 {
464 lastUpdateTime = millis();
465
466 lcd.gotoXY(0, 0);
467 if (showEncoders)
468 {
469 sprintf(buf, " %03d", encCountsLeft);
470 lcd.print(buf);
471 lcd.gotoXY(5, 0);
472 sprintf(buf, " %03d", encCountsRight);
473 lcd.print(buf);
474 }
475 else
476 {
477 // Cycle the instructions every 2 seconds.
478 if (instructCount == 0)
479 {
480 lcd.print("Hold=run");
481 }
482 else if (instructCount == 40)
483 {
484 lcd.print("Tap=flip");
485 }
486 if (++instructCount == 80) { instructCount = 0; }
487 }
488
489 if (buttonA.isPressed())
490 {
491 if (btnCountA < 4)
492 {
493 btnCountA++;
494 }
INDICE DE CÓDIGOS 15

495 else
496 {
497 // Button has been held for more than 200 ms, so
498 // start running the motor.
499 leftSpeed += 15;
500 }
501 }
502 else
503 {
504 if (leftSpeed == 0 && btnCountA > 0 && btnCountA < 4)
505 {
506 // Motor isn’t running and button was pressed for
507 // 200 ms or less, so flip the motor direction.
508 leftDir = -leftDir;
509 }
510 btnCountA = 0;
511 leftSpeed -= 30;
512 }
513
514 if (buttonC.isPressed())
515 {
516 if (btnCountC < 4)
517 {
518 btnCountC++;
519 }
520 else
521 {
522 // Button has been held for more than 200 ms, so
523 // start running the motor.
524 rightSpeed += 15;
525 }
526 }
527 else
528 {
529 if (rightSpeed == 0 && btnCountC > 0 && btnCountC < 4)
530 {
531 // Motor isn’t running and button was pressed for
532 // 200 ms or less, so flip the motor direction.
533 rightDir = -rightDir;
534 }
535 btnCountC = 0;
536 rightSpeed -= 30;
537 }
538
539 leftSpeed = constrain(leftSpeed, 0, 400);
540 rightSpeed = constrain(rightSpeed, 0, 400);
541
542 motors.setSpeeds(leftSpeed * leftDir, rightSpeed * rightDir);
543
544 // Display arrows pointing the appropriate direction
545 // (solid if the motor is running, chevrons if not).
546 lcd.gotoXY(0, 1);
547 if (leftSpeed == 0)
548 {
549 lcd.print((leftDir > 0) ? ’\0’ : ’\1’);
550 }
INDICE DE CÓDIGOS 16

551 else
552 {
553 lcd.print((leftDir > 0) ? ’\2’ : ’\3’);
554 }
555 lcd.gotoXY(7, 1);
556 if (rightSpeed == 0)
557 {
558 lcd.print((rightDir > 0) ? ’\0’ : ’\1’);
559 }
560 else
561 {
562 lcd.print((rightDir > 0) ? ’\2’ : ’\3’);
563 }
564 }
565 }
566 motors.setSpeeds(0, 0);
567 }
568
569
570 // Motor demo with instructions.
571 void motorDemo()
572 {
573 motorDemoHelper(false);
574 }
575
576 // Motor demo with encoder counts.
577 void encoderDemo()
578 {
579 motorDemoHelper(true);
580 }
581
582 const char fugue[] PROGMEM =
583 "! T120O5L16agafaea dac+adaea fa<aa<bac#a dac#adaea f"
584 "O6dcd<b-d<ad<g d<f+d<gd<ad<b- d<dd<ed<f+d<g d<f+d<gd<ad"
585 "L8MS<b-d<b-d MLe-<ge-<g MSc<ac<a MLd<fd<f O5MSb-gb-g"
586 "ML>c#e>c#e MS afaf ML gc#gc# MS fdfd ML e<b-e<b-"
587 "O6L16ragafaea dac#adaea fa<aa<bac#a dac#adaea faeadaca"
588 "<b-acadg<b-g egdgcg<b-g <ag<b-gcf<af dfcf<b-f<af"
589 "<gf<af<b-e<ge c#e<b-e<ae<ge <fe<ge<ad<fd"
590 "O5e>ee>ef>df>d b->c#b->c#a>df>d e>ee>ef>df>d"
591 "e>d>c#>db>d>c#b >c#agaegfe fO6dc#dfdc#<b c#4";
592
593 const char fugueTitle[] PROGMEM =
594 " Fugue in D Minor - by J.S. Bach ";
595
596 // Play a song on the buzzer and display its title.
597 void musicDemo()
598 {
599 displayBackArrow();
600
601 uint8_t fugueTitlePos = 0;
602 uint16_t lastShiftTime = millis() - 2000;
603
604 while (buttonMonitor() != ’B’)
605 {
606 // Shift the song title to the left every 250 ms.
INDICE DE CÓDIGOS 17

607 if ((uint16_t)(millis() - lastShiftTime) > 250)


608 {
609 lastShiftTime = millis();
610
611 lcd.gotoXY(0, 0);
612 for (uint8_t i = 0; i < 8; i++)
613 {
614 char c = pgm_read_byte(fugueTitle + fugueTitlePos + i);
615 lcd.print(c);
616 }
617 fugueTitlePos++;
618
619 if (fugueTitlePos + 8 >= strlen(fugueTitle))
620 {
621 fugueTitlePos = 0;
622 }
623 }
624
625 if (!buzzer.isPlaying())
626 {
627 buzzer.playFromProgramSpace(fugue);
628 }
629 }
630 }
631
632 // Display the the battery (VIN) voltage and indicate whether USB
633 // power is detected.
634 void powerDemo()
635 {
636 displayBackArrow();
637
638 uint16_t lastDisplayTime = millis() - 2000;
639 char buf[6];
640
641 while (buttonMonitor() != ’B’)
642 {
643 if ((uint16_t)(millis() - lastDisplayTime) > 250)
644 {
645 bool usbPower = usbPowerPresent();
646
647 uint16_t batteryLevel = readBatteryMillivolts();
648
649 lastDisplayTime = millis();
650 lcd.gotoXY(0, 0);
651 sprintf(buf, " %5d", batteryLevel);
652 lcd.print(buf);
653 lcd.print(F(" mV"));
654 lcd.gotoXY(3, 1);
655 lcd.print(F("USB="));
656 lcd.print(usbPower ? ’Y’ : ’N’);
657 }
658 }
659 }
660
661 Menu::Item mainMenuItems[] = {
662 { "LEDs", ledDemo },
INDICE DE CÓDIGOS 18

663 { "LineSens", lineSensorDemo },


664 { "ProxSens", proxSensorDemo },
665 { "Inertial", inertialDemo },
666 { "Motors", motorDemo },
667 { "Encoders", encoderDemo },
668 { "Music", musicDemo },
669 { "Power", powerDemo },
670 };
671 Menu mainMenu(mainMenuItems, 8);
672
673 // This function watches for button presses. If a button is
674 // pressed, it beeps a corresponding beep and it returns ’A’,
675 // ’B’, or ’C’ depending on what button was pressed. If no
676 // button was pressed, it returns 0. This function is meant to
677 // be called repeatedly in a loop.
678 char buttonMonitor()
679 {
680 if (buttonA.getSingleDebouncedPress())
681 {
682 buzzer.playFromProgramSpace(beepButtonA);
683 return ’A’;
684 }
685
686 if (buttonB.getSingleDebouncedPress())
687 {
688 buzzer.playFromProgramSpace(beepButtonB);
689 return ’B’;
690 }
691
692 if (buttonC.getSingleDebouncedPress())
693 {
694 buzzer.playFromProgramSpace(beepButtonC);
695 return ’C’;
696 }
697
698 return 0;
699 }
700
701 void setup()
702 {
703 lineSensors.initThreeSensors();
704 proxSensors.initThreeSensors();
705 initInertialSensors();
706
707 loadCustomCharacters();
708
709 // The brownout threshold on the ATmega32U4 is set to 4.3
710 // V. If VCC drops below this, a brownout reset will
711 // occur, preventing the AVR from operating out of spec.
712 //
713 // Note: Brownout resets usually do not happen on the Zumo
714 // 32U4 because the voltage regulator goes straight from 5
715 // V to 0 V when VIN drops too low.
716 //
717 // The bootloader is designed so that you can detect
718 // brownout resets from your sketch using the following
INDICE DE CÓDIGOS 19

719 // code:
720 bool brownout = MCUSR >> BORF & 1;
721 MCUSR = 0;
722
723 if (brownout)
724 {
725 // The board was reset by a brownout reset
726 // (VCC dropped below 4.3 V).
727 // Play a special sound and display a note to the user.
728
729 buzzer.playFromProgramSpace(beepBrownout);
730 lcd.clear();
731 lcd.print(F("Brownout"));
732 lcd.gotoXY(0, 1);
733 lcd.print(F(" reset! "));
734 delay(1000);
735 }
736 else
737 {
738 buzzer.playFromProgramSpace(beepWelcome);
739 }
740
741 lcd.clear();
742 lcd.print(F(" Zumo"));
743 lcd.gotoXY(2, 1);
744 lcd.print(F("32U4"));
745
746 delay(1000);
747
748 lcd.clear();
749 lcd.print(F("Demo"));
750 lcd.gotoXY(0, 1);
751 lcd.print(F("Program"));
752 delay(1000);
753
754 lcd.clear();
755 lcd.print(F("Use B to"));
756 lcd.gotoXY(0, 1);
757 lcd.print(F("select."));
758 delay(1000);
759
760 lcd.clear();
761 lcd.print(F("Press B"));
762 lcd.gotoXY(0, 1);
763 lcd.print(F("-try it!"));
764
765 while (buttonMonitor() != ’B’){}
766
767 buzzer.playFromProgramSpace(beepThankYou);
768 lcd.clear();
769 lcd.print(F(" Thank"));
770 lcd.gotoXY(0, 1);
771 lcd.print(F(" you!"));
772 delay(1000);
773 }
774
INDICE DE CÓDIGOS 20

775 // This function prompts the user to choose something from the
776 // main menu, runs their selection, and then returns.
777 void mainMenuSelect()
778 {
779 lcd.clear();
780 lcd.print(F(" Main"));
781 lcd.gotoXY(0, 1);
782 lcd.print(F(" Menu"));
783 delay(1000);
784 mainMenu.select();
785 }
786
787 void loop()
788 {
789 mainMenuSelect();
790 }
Código 2: Demostración

Encoders
1 /* This program shows how to read the encoders on the Zumo 32U4.
2 The encoders can tell you how far, and in which direction each
3 motor has turned.
4
5 You can press button A on the Zumo to drive both motors forward
6 at full speed. You can press button C to drive both motors
7 in reverse at full speed.
8
9 Encoder counts are printed to the LCD and to the serial monitor.
10
11 On the LCD, the top line shows the counts from the left encoder,
12 and the bottom line shows the counts from the right encoder.
13 Encoder errors should not happen, but if one does happen then the
14 buzzer will beep and an exclamation mark will appear temporarily
15 on the LCD.
16
17 In the serial monitor, the first and second numbers represent
18 counts from the left and right encoders, respectively. The third
19 and fourth numbers represent errors from the left and right
20 encoders, respectively. */
21
22 #include <Wire.h>
23 #include <Zumo32U4.h>
24
25 Zumo32U4Encoders encoders;
26 Zumo32U4LCD lcd;
27 Zumo32U4Buzzer buzzer;
28 Zumo32U4Motors motors;
29 Zumo32U4ButtonA buttonA;
30 Zumo32U4ButtonC buttonC;
31
32 const char encoderErrorLeft[] PROGMEM = "!<c2";
33 const char encoderErrorRight[] PROGMEM = "!<e2";
34
INDICE DE CÓDIGOS 21

35 char report[80];
36
37 void setup()
38 {
39
40 }
41
42 void loop()
43 {
44 static uint8_t lastDisplayTime;
45 static uint8_t displayErrorLeftCountdown = 0;
46 static uint8_t displayErrorRightCountdown = 0;
47
48 if ((uint8_t)(millis() - lastDisplayTime) >= 100)
49 {
50 lastDisplayTime = millis();
51
52 int16_t countsLeft = encoders.getCountsLeft();
53 int16_t countsRight = encoders.getCountsRight();
54
55 bool errorLeft = encoders.checkErrorLeft();
56 bool errorRight = encoders.checkErrorRight();
57
58 if(encoders.checkErrorLeft())
59 {
60 // An error occurred on the left encoder channel.
61 // Display it on the LCD for the next 10 iterations and
62 // also beep.
63 displayErrorLeftCountdown = 10;
64 buzzer.playFromProgramSpace(encoderErrorLeft);
65 }
66
67 if(encoders.checkErrorRight())
68 {
69 // An error occurred on the left encoder channel.
70 // Display it on the LCD for the next 10 iterations and
71 // also beep.
72 displayErrorRightCountdown = 10;
73 buzzer.playFromProgramSpace(encoderErrorRight);
74 }
75
76 // Update the LCD with encoder counts and error info.
77 lcd.clear();
78 lcd.print(countsLeft);
79 lcd.gotoXY(0, 1);
80 lcd.print(countsRight);
81
82 if (displayErrorLeftCountdown)
83 {
84 // Show an exclamation point on the first line to
85 // indicate an error from the left encoder.
86 lcd.gotoXY(7, 0);
87 lcd.print(’!’);
88 displayErrorLeftCountdown--;
89 }
90
INDICE DE CÓDIGOS 22

91 if (displayErrorRightCountdown)
92 {
93 // Show an exclamation point on the second line to
94 // indicate an error from the left encoder.
95 lcd.gotoXY(7, 1);
96 lcd.print(’!’);
97 displayErrorRightCountdown--;
98 }
99
100 // Send the information to the serial monitor also.
101 snprintf_P(report, sizeof(report),
102 PSTR(" %6d %6d %1d %1d"),
103 countsLeft, countsRight, errorLeft, errorRight);
104 Serial.println(report);
105 }
106
107 if (buttonA.isPressed())
108 {
109 motors.setSpeeds(400, 400);
110 }
111 else if (buttonC.isPressed())
112 {
113 motors.setSpeeds(-400, -400);
114 }
115 else
116 {
117 motors.setSpeeds(0, 0);
118 }
119 }
Código 3: Encoders

Seguidor de línea
1 /* This example uses the line sensors on the Zumo 32U4 to follow
2 a black line on a white background, using a PID-based algorithm.
3 It works decently on courses with smooth, 6" radius curves and
4 has been tested with Zumos using 75:1 HP motors. Modifications
5 might be required for it to work well on different courses or
6 with different motors.
7
8 This demo requires a Zumo 32U4 Front Sensor Array to be
9 connected, and jumpers on the front sensor array must be
10 installed in order to connect pin 4 to DN4 and pin 20 to DN2. */
11
12 #include <Wire.h>
13 #include <Zumo32U4.h>
14
15 // This is the maximum speed the motors will be allowed to turn.
16 // A maxSpeed of 400 lets the motors go at top speed. Decrease
17 // this value to impose a speed limit.
18 const uint16_t maxSpeed = 400;
19
20 Zumo32U4Buzzer buzzer;
21 Zumo32U4LineSensors lineSensors;
INDICE DE CÓDIGOS 23

22 Zumo32U4Motors motors;
23 Zumo32U4ButtonA buttonA;
24 Zumo32U4LCD lcd;
25
26 int16_t lastError = 0;
27
28 #define NUM_SENSORS 5
29 unsigned int lineSensorValues[NUM_SENSORS];
30
31 // Sets up special characters in the LCD so that we can display
32 // bar graphs.
33 void loadCustomCharacters()
34 {
35 static const char levels[] PROGMEM = {
36 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 63, 63, 63
37 };
38 lcd.loadCustomCharacter(levels + 0, 0); // 1 bar
39 lcd.loadCustomCharacter(levels + 1, 1); // 2 bars
40 lcd.loadCustomCharacter(levels + 2, 2); // 3 bars
41 lcd.loadCustomCharacter(levels + 3, 3); // 4 bars
42 lcd.loadCustomCharacter(levels + 4, 4); // 5 bars
43 lcd.loadCustomCharacter(levels + 5, 5); // 6 bars
44 lcd.loadCustomCharacter(levels + 6, 6); // 7 bars
45 }
46
47 void printBar(uint8_t height)
48 {
49 if (height > 8) { height = 8; }
50 const char barChars[] = {’ ’, 0, 1, 2, 3, 4, 5, 6, 255};
51 lcd.print(barChars[height]);
52 }
53
54 void calibrateSensors()
55 {
56 lcd.clear();
57
58 // Wait 1 second and then begin automatic sensor calibration
59 // by rotating in place to sweep the sensors over the line
60 delay(1000);
61 for(uint16_t i = 0; i < 120; i++)
62 {
63 if (i > 30 && i <= 90)
64 {
65 motors.setSpeeds(-200, 200);
66 }
67 else
68 {
69 motors.setSpeeds(200, -200);
70 }
71
72 lineSensors.calibrate();
73 }
74 motors.setSpeeds(0, 0);
75 }
76
77 // Displays a bar graph of sensor readings on the LCD.
INDICE DE CÓDIGOS 24

78 // Returns after the user presses A.


79 void showReadings()
80 {
81 lcd.clear();
82
83 while(!buttonA.getSingleDebouncedPress())
84 {
85 lineSensors.readCalibrated(lineSensorValues);
86
87 lcd.gotoXY(0, 0);
88 for (uint8_t i = 0; i < NUM_SENSORS; i++)
89 {
90 uint8_t barHeight = map(lineSensorValues[i], 0, 1000, 0, 8);
91 printBar(barHeight);
92 }
93 }
94 }
95
96 void setup()
97 {
98 // Uncomment if necessary to correct motor directions:
99 //motors.flipLeftMotor(true);
100 //motors.flipRightMotor(true);
101
102 lineSensors.initFiveSensors();
103
104 loadCustomCharacters();
105
106 // Play a little welcome song
107 buzzer.play(">g32>>c32");
108
109 // Wait for button A to be pressed and released.
110 lcd.clear();
111 lcd.print(F("Press A"));
112 lcd.gotoXY(0, 1);
113 lcd.print(F("to calib"));
114 buttonA.waitForButton();
115
116 calibrateSensors();
117
118 showReadings();
119
120 // Play music and wait for it to finish before we start driving.
121 lcd.clear();
122 lcd.print(F("Go!"));
123 buzzer.play("L16 cdegreg4");
124 while(buzzer.isPlaying());
125 }
126
127 void loop()
128 {
129 // Get the position of the line. Note that we *must* provide
130 // the "lineSensorValues" argument to readLine() here, even
131 // though we are not interested in the individual sensor
132 // readings.
133 int16_t position = lineSensors.readLine(lineSensorValues);
INDICE DE CÓDIGOS 25

134
135 // Our "error" is how far we are away from the center of the
136 // line, which corresponds to position 2000.
137 int16_t error = position - 2000;
138
139 // Get motor speed difference using proportional and derivative
140 // PID terms (the integral term is generally not very useful
141 // for line following). Here we are using a proportional
142 // constant of 1/4 and a derivative constant of 6, which should
143 // work decently for many Zumo motor choices. You probably
144 // want to use trial and error to tune these constants for your
145 // particular Zumo and line course.
146 int16_t speedDifference = error / 4 + 6 * (error - lastError);
147
148 lastError = error;
149
150 // Get individual motor speeds. The sign of speedDifference
151 // determines if the robot turns left or right.
152 int16_t leftSpeed = (int16_t)maxSpeed + speedDifference;
153 int16_t rightSpeed = (int16_t)maxSpeed - speedDifference;
154
155 // Constrain our motor speeds to be between 0 and maxSpeed.
156 // One motor will always be turning at maxSpeed, and the other
157 // will be at maxSpeed-|speedDifference| if that is positive,
158 // else it will be stationary. For some applications, you
159 // might want to allow the motor speed to go negative so that
160 // it can spin in reverse.
161 leftSpeed = constrain(leftSpeed, 0, (int16_t)maxSpeed);
162 rightSpeed = constrain(rightSpeed, 0, (int16_t)maxSpeed);
163
164 motors.setSpeeds(leftSpeed, rightSpeed);
165 }
Código 4: Seguidor de línea

Prueba sensor de línea


1 /** This example shows how to read the raw values from the five
2 line sensors on the Zumo32U4 Front Sensor Array. This example is
3 useful if you are having trouble with the sensors or just want to
4 characterize their behavior.
5
6 The raw (uncalibrated) values are reported to the serial monitor,
7 and also displayed on the LCD. The first line of the LCD
8 displays a bar graph of all five readings. The upper right
9 corner shows a an "E" if the IR emitters are being used (the
10 default) or an "e" if they are not being used. The second line
11 displays the raw reading for the currently-selected sensor.
12
13 You can press the "A" and "B" buttons to change which sensor is
14 selected.
15
16 You can press the "C" button to toggle whether the IR emitters
17 are on during the reading.
18
INDICE DE CÓDIGOS 26

19 In order for the second and forth sensors to work, jumpers on the
20 front sensor array must be installed in order to connect pin 4 to
21 DN4 and pin 20 to DN2. */
22
23 #include <Wire.h>
24 #include <Zumo32U4.h>
25
26 Zumo32U4LCD lcd;
27 Zumo32U4ButtonA buttonA;
28 Zumo32U4ButtonB buttonB;
29 Zumo32U4ButtonC buttonC;
30 Zumo32U4LineSensors lineSensors;
31 Zumo32U4ProximitySensors proxSensors;
32
33 #define NUM_SENSORS 5
34 uint16_t lineSensorValues[NUM_SENSORS];
35
36 bool useEmitters = true;
37
38 uint8_t selectedSensorIndex = 0;
39
40 void setup()
41 {
42 lineSensors.initFiveSensors();
43
44 loadCustomCharacters();
45 }
46
47 void loadCustomCharacters()
48 {
49 static const char levels[] PROGMEM = {
50 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 63, 63, 63
51 };
52 lcd.loadCustomCharacter(levels + 0, 0); // 1 bar
53 lcd.loadCustomCharacter(levels + 1, 1); // 2 bars
54 lcd.loadCustomCharacter(levels + 2, 2); // 3 bars
55 lcd.loadCustomCharacter(levels + 3, 3); // 4 bars
56 lcd.loadCustomCharacter(levels + 4, 4); // 5 bars
57 lcd.loadCustomCharacter(levels + 5, 5); // 6 bars
58 lcd.loadCustomCharacter(levels + 6, 6); // 7 bars
59 }
60
61 void printBar(uint8_t height)
62 {
63 if (height > 8) { height = 8; }
64 const char barChars[] = {’ ’, 0, 1, 2, 3, 4, 5, 6, 255};
65 lcd.print(barChars[height]);
66 }
67
68 void printReadingsToLCD()
69 {
70 // On the first line of the LCD, display the bar graph.
71 lcd.gotoXY(0, 0);
72 for (uint8_t i = 0; i < 5; i++)
73 {
74 uint8_t barHeight = map(lineSensorValues[i], 0, 2000, 0, 8);
INDICE DE CÓDIGOS 27

75 printBar(barHeight);
76 }
77
78 // Print "E" if the emitters are on, "e" if they are off.
79 lcd.gotoXY(7, 0);
80 lcd.print(useEmitters ? ’E’ : ’e’);
81
82 // On the second line of the LCD, display one raw reading.
83 lcd.gotoXY(0, 1);
84 lcd.print(selectedSensorIndex);
85 lcd.print(F(": "));
86 lcd.print(lineSensorValues[selectedSensorIndex]);
87 lcd.print(F(" "));
88 }
89
90 // Prints a line with all the sensor readings to the serial
91 // monitor.
92 void printReadingsToSerial()
93 {
94 char buffer[80];
95 sprintf(buffer, " %4d %4d %4d %4d %4d %c\n",
96 lineSensorValues[0],
97 lineSensorValues[1],
98 lineSensorValues[2],
99 lineSensorValues[3],
100 lineSensorValues[4],
101 useEmitters ? ’E’ : ’e’
102 );
103 Serial.print(buffer);
104 }
105
106 void loop()
107 {
108 static uint16_t lastSampleTime = 0;
109
110 if ((uint16_t)(millis() - lastSampleTime) >= 100)
111 {
112 lastSampleTime = millis();
113
114 // Read the line sensors.
115 lineSensors.read(lineSensorValues, useEmitters ? QTR_EMITTERS_ON : QTR_EMITTERS_OFF);
116
117 // Send the results to the LCD and to the serial monitor.
118 printReadingsToLCD();
119 printReadingsToSerial();
120 }
121
122 // If button A is pressed, select the previous sensor.
123 if (buttonA.getSingleDebouncedPress())
124 {
125 selectedSensorIndex = (selectedSensorIndex + NUM_SENSORS - 1) % NUM_SENSORS;
126 }
127
128 // If button B is pressed, select the next sensor.
129 if (buttonB.getSingleDebouncedPress())
130 {
INDICE DE CÓDIGOS 28

131 selectedSensorIndex = (selectedSensorIndex + 1) % NUM_SENSORS;


132 }
133
134 // If button C is pressed, toggle the state of the emitters.
135 if (buttonC.getSingleDebouncedPress())
136 {
137 useEmitters = !useEmitters;
138 }
139 }
Código 5: Prueba sensor de línea

Control remoto
1 /* This example shows how to use the receivers for the infrared
2 proximity sensors on the Zumo 32U4 to detect and decode commands
3 from an infrared remote. This code is designed to work with the
4 Mini IR Remote Control available from Pololu:
5
6 https://www.pololu.com/product/2777
7
8 For this code to work, jumpers on the front sensor array should
9 be installed in order to connect pin 4 to RGT and connect pin 20
10 to LFT.
11
12 The arrow buttons control the robot’s movement, while the number
13 buttons from 1 to 3 play different notes on the buzzer.
14
15 To change what actions are performed when a button press is
16 detected, you should change the processRemoteCommand and
17 stopCurrentCommand functions.
18
19 If you have a different remote that uses the NEC protocol with a
20 38 kHz, 940 nm infrared emitter, it should be possible to make it
21 work with this code. You can use this code to decode the
22 messages from your remote, and then you can edit the constants in
23 RemoteConstants.h to match what was transmitted from your
24 remote. */
25
26 #include <Wire.h>
27 #include <Zumo32U4.h>
28 #include "RemoteConstants.h"
29 #include "RemoteDecoder.h"
30
31 // This variable sets the amount of time (in milliseconds) that
32 // we wait before considering the current message from the remote
33 // to have expired. This type of remote typically sends a repeat
34 // command every 109 ms, so a timeout value of 115 was chosen.
35 // You can increase this timeout to 230 if you want to be more
36 // tolerant of errors that occur while you are holding down the
37 // button, but it will make the robot slower to respond when you
38 // release the button.
39 const uint16_t messageTimeoutMs = 115;
40
41 // This variable is true if the last message received from the
INDICE DE CÓDIGOS 29

42 // remote is still active, meaning that we are still performing


43 // the action specified by the message. A message will be active
44 // if the remote button is being held down and the robot has been
45 // successfully receiving messages from the remote since the
46 // button was pressed.
47 bool messageActive = false;
48
49 // This is the time that the current message from the remote was
50 // last verified, in milliseconds. It is used to implement the
51 // timeout defined above.
52 uint16_t lastMessageTimeMs = 0;
53
54 Zumo32U4LCD lcd;
55 Zumo32U4Motors motors;
56 Zumo32U4Buzzer buzzer;
57 Zumo32U4ButtonA buttonA;
58
59 RemoteDecoder decoder;
60
61 void setup()
62 {
63 decoder.init();
64
65 lcd.clear();
66 lcd.print(F("Waiting"));
67 }
68
69 void loop()
70 {
71 decoder.service();
72
73 // Turn on the yellow LED if a message is active.
74 ledYellow(messageActive);
75
76 // Turn on the red LED if we are in the middle of receiving a
77 // new message from the remote. You should see the red LED
78 // blinking about 9 times per second while you hold a remote
79 // button down.
80 ledRed(decoder.criticalTime());
81
82 if (decoder.criticalTime())
83 {
84 // We are in the middle of receiving a message from the
85 // remote, so we should avoid doing anything that might take
86 // more than a few tens of microseconds, and call
87 // decoder.service() as often as possible.
88 }
89 else
90 {
91 // We are not in a critical time, so we can do other things
92 // as long as they do not take longer than about 7.3 ms.
93 // Delays longer than that can cause some remote control
94 // messages to be missed.
95
96 processRemoteEvents();
97 }
INDICE DE CÓDIGOS 30

98
99 // Check how long ago the current message was last verified.
100 // If it is longer than the timeout time, then the message has
101 // expired and we should stop executing it.
102 if (messageActive && (uint16_t)(millis() - lastMessageTimeMs) > messageTimeoutMs)
103 {
104 messageActive = false;
105 stopCurrentCommand();
106 }
107 }
108
109 void processRemoteEvents()
110 {
111 if (decoder.getAndResetMessageFlag())
112 {
113 // The remote decoder received a new message, so record what
114 // time it was received and process it.
115 lastMessageTimeMs = millis();
116 messageActive = true;
117 processRemoteMessage(decoder.getMessage());
118 }
119
120 if (decoder.getAndResetRepeatFlag())
121 {
122 // The remote decoder receiver a "repeat" command, which is
123 // sent about every 109 ms while the button is being held
124 // down. It contains no data. We record what time the
125 // repeat command was received so we can know that the
126 // current message is still active.
127 lastMessageTimeMs = millis();
128 }
129 }
130
131 void processRemoteMessage(const uint8_t * message)
132 {
133 // Print the raw message on the first line of the LCD, in hex.
134 // The first two bytes are usually an address, and the third
135 // byte is usually a command. The last byte is supposed to be
136 // the bitwise inverse of the third byte, and if that is the
137 // case, then we don’t print it.
138 lcd.clear();
139 char buffer[9];
140 if (message[2] + message[3] == 0xFF)
141 {
142 sprintf(buffer, " %02X %02X %02X ",
143 message[0], message[1], message[2]);
144 }
145 else
146 {
147 sprintf(buffer, " %02X %02X %02X %02X",
148 message[0], message[1], message[2], message[3]);
149 }
150 lcd.print(buffer);
151
152 // Go to the next line of the LCD.
153 lcd.gotoXY(0, 1);
INDICE DE CÓDIGOS 31

154
155 // Make sure the address matches what we expect.
156 if (message[0] != remoteAddressByte0 ||
157 message[1] != remoteAddressByte1)
158 {
159 lcd.print(F("bad addr"));
160 return;
161 }
162
163 // Make sure that the last byte is the logical inverse of the
164 // command byte.
165 if (message[2] + message[3] != 0xFF)
166 {
167 lcd.print(F("bad cmd"));
168 return;
169 }
170
171 stopCurrentCommand();
172 processRemoteCommand(message[2]);
173 }
174
175 // Start running the new command.
176 void processRemoteCommand(uint8_t command)
177 {
178 switch(command)
179 {
180 case remoteUp:
181 lcd.print(F("up"));
182 motors.setSpeeds(400, 400);
183 break;
184
185 case remoteDown:
186 lcd.print(F("down"));
187 motors.setSpeeds(-400, -400);
188 break;
189
190 case remoteLeft:
191 lcd.print(F("left"));
192 motors.setSpeeds(-250, 250);
193 break;
194
195 case remoteRight:
196 lcd.print(F("right"));
197 motors.setSpeeds(250, -250);
198 break;
199
200 case remoteStopMode:
201 lcd.print(F("stop"));
202 break;
203
204 case remoteEnterSave:
205 lcd.print(F("enter"));
206 break;
207
208 case remoteVolMinus:
209 lcd.print(F("vol-"));
INDICE DE CÓDIGOS 32

210 break;
211
212 case remoteVolPlus:
213 lcd.print(F("vol+"));
214 break;
215
216 case remotePlayPause:
217 lcd.print(F("play"));
218 break;
219
220 case remoteSetup:
221 lcd.print(F("setup"));
222 break;
223
224 case remoteBack:
225 lcd.print(F("back"));
226 break;
227
228 case remote0:
229 lcd.print(F("0"));
230 break;
231
232 case remote1:
233 lcd.print(F("1"));
234 buzzer.playNote(NOTE_C(4), 200, 15);
235 break;
236
237 case remote2:
238 lcd.print(F("2"));
239 buzzer.playNote(NOTE_D(4), 200, 15);
240 break;
241
242 case remote3:
243 lcd.print(F("3"));
244 buzzer.playNote(NOTE_E(4), 200, 15);
245 break;
246
247 case remote4:
248 lcd.print(F("4"));
249 break;
250
251 case remote5:
252 lcd.print(F("5"));
253 break;
254
255 case remote6:
256 lcd.print(F("6"));
257 break;
258
259 case remote7:
260 lcd.print(F("7"));
261 break;
262
263 case remote8:
264 lcd.print(F("8"));
265 break;
INDICE DE CÓDIGOS 33

266
267 case remote9:
268 lcd.print(F("9"));
269 break;
270 }
271 }
272
273 // Stops the current remote control command. This is called when
274 // a new command is received or if the current command has
275 // expired.
276 void stopCurrentCommand()
277 {
278 motors.setSpeeds(0, 0);
279 buzzer.stopPlaying();
280 }
Código 6: Control remoto

Вам также может понравиться