1#include <Servo.h>
2#include <Modulino.h>
3#include "Arduino_LED_Matrix.h"
4
5// JBR-001 hardware
6Servo headServo;
7Servo leftArmServo;
8Servo rightArmServo;
9
10ModulinoBuzzer buzzer;
11ModulinoDistance distanceSensor;
12
13ArduinoLEDMatrix matrix;
14
15// Servo pins
16const int HEAD_SERVO_PIN = 9;
17const int LEFT_ARM_SERVO_PIN = 10;
18const int RIGHT_ARM_SERVO_PIN = 11;
19
20// Servo resting positions
21const int HEAD_CENTER = 90;
22const int LEFT_ARM_CENTER = 90;
23const int RIGHT_ARM_CENTER = 90;
24
25// Distance detection
26const float DETECTION_DISTANCE = 200.0;
27const float RESET_DISTANCE = 250.0;
28
29bool objectDetected = false;
30
31// Small heart
32// flipped to match display orientation
33uint8_t heartSmall[8][13] = {
34  {0,0,0,0,0,0,0,0,0,0,0,0,0},
35  {0,0,0,0,0,1,1,1,0,0,0,0,0},
36  {0,0,0,0,1,1,1,1,1,0,0,0,0},
37  {0,0,0,1,1,1,1,1,1,1,0,0,0},
38  {0,0,1,1,1,1,1,1,1,1,1,0,0},
39  {0,0,1,1,1,1,0,1,1,1,1,0,0},
40  {0,0,0,1,1,0,0,0,1,1,0,0,0},
41  {0,0,0,0,0,0,0,0,0,0,0,0,0}
42};
43
44
45// Large heart
46// flipped to match display orientation
47uint8_t heartLarge[8][13] = {
48  {0,0,0,0,1,1,1,1,1,0,0,0,0},
49  {0,0,0,1,1,1,1,1,1,1,0,0,0},
50  {0,0,1,1,1,1,1,1,1,1,1,0,0},
51  {0,1,1,1,1,1,1,1,1,1,1,1,0},
52  {1,1,1,1,1,1,1,1,1,1,1,1,1},
53  {1,1,1,1,1,1,1,1,1,1,1,1,1},
54  {0,1,1,1,1,1,0,1,1,1,1,1,0},
55  {0,0,1,1,1,0,0,0,1,1,1,0,0}
56};
57
58// Heartbeat animation
59unsigned long heartbeatTimer = 0;
60int heartbeatStep = 0;
61
62void heartbeat() {
63  unsigned long now = millis();
64
65  switch (heartbeatStep) {
66
67    case 0:
68      matrix.renderBitmap(heartLarge, 8, 13);
69      heartbeatTimer = now;
70      heartbeatStep = 1;
71      break;
72
73    case 1:
74      if (now - heartbeatTimer >= 120) {
75        matrix.renderBitmap(heartSmall, 8, 13);
76        heartbeatTimer = now;
77        heartbeatStep = 2;
78      }
79      break;
80
81    case 2:
82      if (now - heartbeatTimer >= 100) {
83        matrix.renderBitmap(heartLarge, 8, 13);
84        heartbeatTimer = now;
85        heartbeatStep = 3;
86      }
87      break;
88
89    case 3:
90      if (now - heartbeatTimer >= 160) {
91        matrix.renderBitmap(heartSmall, 8, 13);
92        heartbeatTimer = now;
93        heartbeatStep = 4;
94      }
95      break;
96
97    case 4:
98      if (now - heartbeatTimer >= 700) {
99        heartbeatStep = 0;
100      }
101      break;
102  }
103}
104
105// Play JBR-001's friendly greeting
106void playHello() {
107  buzzer.tone(523, 120);   // C5
108  delay(150);
109
110  buzzer.tone(659, 120);   // E5
111  delay(150);
112
113  buzzer.tone(784, 180);   // G5
114  delay(210);
115
116  buzzer.tone(1047, 250);  // C6
117  delay(270);
118}
119
120// Perform JBR-001's startup movement
121void makeMovement() {
122
123  // Look left, right, then forward
124  headServo.write(70);
125  delay(400);
126
127  headServo.write(110);
128  delay(400);
129
130  headServo.write(HEAD_CENTER);
131  delay(400);
132
133  // Move both arms
134  leftArmServo.write(70);
135  rightArmServo.write(110);
136  delay(500);
137
138  leftArmServo.write(110);
139  rightArmServo.write(70);
140  delay(500);
141
142  // Return to resting position
143  leftArmServo.write(LEFT_ARM_CENTER);
144  rightArmServo.write(RIGHT_ARM_CENTER);
145  delay(500);
146}
147
148void setup() {
149  Modulino.begin();
150
151  buzzer.begin();
152  distanceSensor.begin();
153  matrix.begin();
154
155  // Show the heart while JBR-001 starts
156  matrix.renderBitmap(heartSmall, 8, 13);
157
158  // Move each servo to its resting position
159  headServo.attach(HEAD_SERVO_PIN);
160  headServo.write(HEAD_CENTER);
161  delay(400);
162
163  leftArmServo.attach(LEFT_ARM_SERVO_PIN);
164  leftArmServo.write(LEFT_ARM_CENTER);
165  delay(400);
166
167  rightArmServo.attach(RIGHT_ARM_SERVO_PIN);
168  rightArmServo.write(RIGHT_ARM_CENTER);
169  delay(400);
170
171  delay(500);
172
173  // Say hello and come to life
174  playHello();
175  makeMovement();
176}
177
178void loop() {
179
180  // Keep the heart beating
181  heartbeat();
182
183  // React when someone approaches
184  if (distanceSensor.available()) {
185    float distance = distanceSensor.get();
186
187    if (distance < DETECTION_DISTANCE && !objectDetected) {
188      objectDetected = true;
189      playHello();
190    }
191
192    // Ready for the next greeting once they move away
193    if (distance > RESET_DISTANCE) {
194      objectDetected = false;
195    }
196  }
197}