Platform controller for the Mobile Arcade project

Dependencies:   APA102 Motor

Committer:
abraha2d
Date:
Tue Dec 11 14:44:55 2018 +0000
Revision:
2:774edcf60939
Parent:
1:113469a23547
Child:
3:7e5233f883c7
Add game lighting, integration with Pi

Who changed what in which revision?

UserRevisionLine numberNew contents of line
abraha2d 0:d4e7f9c1287f 1 #include "mbed.h"
abraha2d 0:d4e7f9c1287f 2 #include "Motor.h"
abraha2d 1:113469a23547 3 #include "APA102.h"
abraha2d 0:d4e7f9c1287f 4
abraha2d 1:113469a23547 5 #define NUM_LEDS 72
abraha2d 1:113469a23547 6
abraha2d 1:113469a23547 7 #define TAIL_BLINKER_START 0
abraha2d 1:113469a23547 8 #define NUM_TAIL_BLINKER 3
abraha2d 1:113469a23547 9 #define TAIL_REVERSE_START 3
abraha2d 1:113469a23547 10 #define NUM_TAIL_REVERSE 2
abraha2d 1:113469a23547 11
abraha2d 1:113469a23547 12 #define GLOW_START 6
abraha2d 1:113469a23547 13 #define NUM_GLOW 21
abraha2d 1:113469a23547 14
abraha2d 1:113469a23547 15 #define HEAD_FOG_START 28
abraha2d 1:113469a23547 16 #define NUM_HEAD_FOG 1
abraha2d 1:113469a23547 17
abraha2d 1:113469a23547 18 #define HEAD_BLINKER_START 30
abraha2d 1:113469a23547 19 #define NUM_HEAD_BLINKER 2
abraha2d 1:113469a23547 20 #define HEAD_LIGHT_START 32
abraha2d 1:113469a23547 21 #define NUM_HEAD_LIGHT 3
abraha2d 1:113469a23547 22
abraha2d 1:113469a23547 23 #define GAME_START 51
abraha2d 1:113469a23547 24 #define NUM_GAME 19
abraha2d 1:113469a23547 25
abraha2d 2:774edcf60939 26 #define COLOR_GAME_MENU CRGB(1, 1, 1)
abraha2d 2:774edcf60939 27 #define COLOR_GAME_GAME CRGB(0, 1, 2)
abraha2d 2:774edcf60939 28
abraha2d 1:113469a23547 29 #define COLOR_HEADLIGHT_DIM CRGB(8, 8, 8)
abraha2d 1:113469a23547 30 #define COLOR_HEADLIGHT_ON CRGB(32, 32, 32)
abraha2d 1:113469a23547 31 #define COLOR_FOGLIGHT CRGB(64, 64, 0)
abraha2d 0:d4e7f9c1287f 32
abraha2d 1:113469a23547 33 #define COLOR_TAILLIGHT CRGB(32, 0, 0)
abraha2d 1:113469a23547 34 #define COLOR_BRAKELIGHT CRGB(128, 0, 0)
abraha2d 1:113469a23547 35 #define COLOR_REVERSE CRGB(64, 64, 64)
abraha2d 1:113469a23547 36
abraha2d 1:113469a23547 37 #define COLOR_UNDERGLOW CRGB(0, 16, 0)
abraha2d 1:113469a23547 38
abraha2d 1:113469a23547 39 #define COLOR_BLINKER CRGB(128, 32, 0)
abraha2d 1:113469a23547 40 #define BLINK_DELAY 0.5
abraha2d 1:113469a23547 41
abraha2d 1:113469a23547 42 #define BLINKER_L 1
abraha2d 1:113469a23547 43 #define BLINKER_R 2
abraha2d 1:113469a23547 44 #define FOGLIGHT 4
abraha2d 1:113469a23547 45 #define REVERSE 8
abraha2d 1:113469a23547 46 #define UNDERGLOW 16
abraha2d 1:113469a23547 47 #define HEADLIGHT 32
abraha2d 1:113469a23547 48 #define BRAKELIGHT 64
abraha2d 2:774edcf60939 49 uint8_t lights = 0;
abraha2d 1:113469a23547 50
abraha2d 1:113469a23547 51 CRGB l_leds[NUM_LEDS];
abraha2d 1:113469a23547 52 CRGB r_leds[NUM_LEDS];
abraha2d 1:113469a23547 53
abraha2d 2:774edcf60939 54 int numGame = 0;
abraha2d 2:774edcf60939 55
abraha2d 2:774edcf60939 56 CRGB gameColor = COLOR_GAME_MENU;
abraha2d 2:774edcf60939 57 int gamePwmNum = 1;
abraha2d 2:774edcf60939 58 int gamePwmDen = 4;
abraha2d 2:774edcf60939 59 int gamePwmMax = 8;
abraha2d 1:113469a23547 60
abraha2d 1:113469a23547 61 SPI l_strip(p5, p6, p7);
abraha2d 1:113469a23547 62 SPI r_strip(p11, p12, p13);
abraha2d 0:d4e7f9c1287f 63
abraha2d 0:d4e7f9c1287f 64 Motor l_motor(p21, p23, p22); // PWMA, AI1, AI2
abraha2d 0:d4e7f9c1287f 65 Motor r_motor(p26, p24, p25); // PWMB, BI1, BI2
abraha2d 0:d4e7f9c1287f 66
abraha2d 1:113469a23547 67 float l_vel = 0;
abraha2d 1:113469a23547 68 float r_vel = 0;
abraha2d 0:d4e7f9c1287f 69
abraha2d 1:113469a23547 70 Serial bt(p28, p27); // Bluefruit RX, TX
abraha2d 1:113469a23547 71 Serial pc(USBTX, USBRX);
abraha2d 1:113469a23547 72
abraha2d 2:774edcf60939 73 Thread pcThread;
abraha2d 1:113469a23547 74 Thread btThread;
abraha2d 1:113469a23547 75 Thread blinkerThread;
abraha2d 1:113469a23547 76
abraha2d 2:774edcf60939 77 void pc_thread() {
abraha2d 2:774edcf60939 78 for(;;) {
abraha2d 2:774edcf60939 79 while (!pc.readable()) wait(0.1);
abraha2d 2:774edcf60939 80 switch (pc.getc()) {
abraha2d 2:774edcf60939 81 case 's':
abraha2d 2:774edcf60939 82 // Switch to game
abraha2d 2:774edcf60939 83 while(pc.getc() != '\n'); // Flush rest of command
abraha2d 2:774edcf60939 84 while (gamePwmNum != 1) wait(0.01); // Wait for dim before switch
abraha2d 2:774edcf60939 85 gameColor = COLOR_GAME_GAME;
abraha2d 2:774edcf60939 86 break;
abraha2d 2:774edcf60939 87 case 'e':
abraha2d 2:774edcf60939 88 // Switch to menu
abraha2d 2:774edcf60939 89 while(pc.getc() != '\n'); // Flush rest of command
abraha2d 2:774edcf60939 90 while (gamePwmNum != 1) wait(0.01); // Wait for dim before switch
abraha2d 2:774edcf60939 91 gameColor = COLOR_GAME_MENU;
abraha2d 2:774edcf60939 92 break;
abraha2d 2:774edcf60939 93 case 'b':
abraha2d 2:774edcf60939 94 // Starting up
abraha2d 2:774edcf60939 95 while (numGame < NUM_GAME) {
abraha2d 2:774edcf60939 96 numGame++;
abraha2d 2:774edcf60939 97 wait(0.05);
abraha2d 2:774edcf60939 98 }
abraha2d 2:774edcf60939 99 lights = FOGLIGHT | UNDERGLOW | BRAKELIGHT;
abraha2d 2:774edcf60939 100 break;
abraha2d 2:774edcf60939 101 case 'h':
abraha2d 2:774edcf60939 102 // Shutting down
abraha2d 2:774edcf60939 103 lights = 0;
abraha2d 2:774edcf60939 104 while (numGame > 0) {
abraha2d 2:774edcf60939 105 numGame--;
abraha2d 2:774edcf60939 106 wait(0.05);
abraha2d 2:774edcf60939 107 }
abraha2d 2:774edcf60939 108 break;
abraha2d 2:774edcf60939 109 }
abraha2d 2:774edcf60939 110 }
abraha2d 2:774edcf60939 111 }
abraha2d 2:774edcf60939 112
abraha2d 1:113469a23547 113 void bt_thread() {
abraha2d 0:d4e7f9c1287f 114 char bnum = 0;
abraha2d 0:d4e7f9c1287f 115 char bhit = 0;
abraha2d 1:113469a23547 116 for(;;) {
abraha2d 1:113469a23547 117 while (!bt.readable()) wait(0.1);
abraha2d 0:d4e7f9c1287f 118 if (bt.getc() == '!' && bt.getc() == 'B') {
abraha2d 0:d4e7f9c1287f 119 bnum = bt.getc(); // button number
abraha2d 1:113469a23547 120 bhit = bt.getc(); // '1' = hit, '0' = release
abraha2d 0:d4e7f9c1287f 121 if (bt.getc() == char(~('!' + 'B' + bnum + bhit))) {
abraha2d 1:113469a23547 122 pc.printf("%i\n", bnum);
abraha2d 1:113469a23547 123 if (bnum == 53 && bhit == '1') { // UP
abraha2d 1:113469a23547 124 l_vel += 0.25f;
abraha2d 1:113469a23547 125 r_vel += 0.25f;
abraha2d 1:113469a23547 126 } else if (bnum == 54 && bhit == '1') { // DOWN
abraha2d 1:113469a23547 127 l_vel -= 0.25f;
abraha2d 1:113469a23547 128 r_vel -= 0.25f;
abraha2d 1:113469a23547 129 } else if (bnum == 55 && bhit == '1') { // LEFT
abraha2d 1:113469a23547 130 l_vel += 0.25f;
abraha2d 1:113469a23547 131 r_vel -= 0.25f;
abraha2d 1:113469a23547 132 } else if (bnum == 56 && bhit == '1') { // RIGHT
abraha2d 1:113469a23547 133 l_vel -= 0.25f;
abraha2d 1:113469a23547 134 r_vel += 0.25f;
abraha2d 1:113469a23547 135 } else if (bnum == '2' && bhit == '1') {
abraha2d 1:113469a23547 136 lights ^= FOGLIGHT;
abraha2d 1:113469a23547 137 }
abraha2d 1:113469a23547 138 l_motor.speed(l_vel);
abraha2d 1:113469a23547 139 r_motor.speed(r_vel);
abraha2d 1:113469a23547 140 if (bnum == '1' && bhit == '1') {
abraha2d 1:113469a23547 141 l_vel = 0;
abraha2d 1:113469a23547 142 r_vel = 0;
abraha2d 1:113469a23547 143 l_motor.brake(1);
abraha2d 1:113469a23547 144 r_motor.brake(1);
abraha2d 1:113469a23547 145 }
abraha2d 1:113469a23547 146 if (l_vel + r_vel > 0.01f) {
abraha2d 1:113469a23547 147 lights &= ~(BRAKELIGHT | REVERSE);
abraha2d 1:113469a23547 148 lights |= HEADLIGHT;
abraha2d 1:113469a23547 149 } else if (l_vel + r_vel < -0.01f) {
abraha2d 1:113469a23547 150 lights &= ~(BRAKELIGHT | HEADLIGHT);
abraha2d 1:113469a23547 151 lights |= REVERSE;
abraha2d 1:113469a23547 152 } else {
abraha2d 1:113469a23547 153 lights &= ~(HEADLIGHT | REVERSE);
abraha2d 1:113469a23547 154 lights |= BRAKELIGHT;
abraha2d 1:113469a23547 155 }
abraha2d 1:113469a23547 156 if (l_vel - r_vel > 0.01f) {
abraha2d 1:113469a23547 157 lights &= ~BLINKER_R;
abraha2d 1:113469a23547 158 lights |= BLINKER_L;
abraha2d 1:113469a23547 159 } else if (r_vel - l_vel > 0.01f) {
abraha2d 1:113469a23547 160 lights &= ~BLINKER_L;
abraha2d 1:113469a23547 161 lights |= BLINKER_R;
abraha2d 1:113469a23547 162 } else {
abraha2d 1:113469a23547 163 lights &= ~(BLINKER_L | BLINKER_R);
abraha2d 0:d4e7f9c1287f 164 }
abraha2d 0:d4e7f9c1287f 165 }
abraha2d 0:d4e7f9c1287f 166 }
abraha2d 0:d4e7f9c1287f 167 }
abraha2d 0:d4e7f9c1287f 168 }
abraha2d 0:d4e7f9c1287f 169
abraha2d 1:113469a23547 170 void blinker_thread() {
abraha2d 1:113469a23547 171 for (;;) {
abraha2d 1:113469a23547 172 while (!(lights & (BLINKER_L | BLINKER_R))) {
abraha2d 1:113469a23547 173 wait(0.1);
abraha2d 1:113469a23547 174 }
abraha2d 2:774edcf60939 175
abraha2d 1:113469a23547 176 if (lights & BLINKER_L) {
abraha2d 1:113469a23547 177 fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, COLOR_BLINKER);
abraha2d 1:113469a23547 178 fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, COLOR_BLINKER);
abraha2d 1:113469a23547 179 }
abraha2d 1:113469a23547 180 if (lights & BLINKER_R) {
abraha2d 1:113469a23547 181 fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, COLOR_BLINKER);
abraha2d 1:113469a23547 182 fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, COLOR_BLINKER);
abraha2d 1:113469a23547 183 }
abraha2d 1:113469a23547 184 wait(BLINK_DELAY);
abraha2d 2:774edcf60939 185
abraha2d 1:113469a23547 186 if (l_leds[HEAD_BLINKER_START] == COLOR_BLINKER) {
abraha2d 1:113469a23547 187 fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, CRGB::Black);
abraha2d 1:113469a23547 188 fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, CRGB::Black);
abraha2d 1:113469a23547 189 }
abraha2d 1:113469a23547 190 if (r_leds[HEAD_BLINKER_START] == COLOR_BLINKER) {
abraha2d 1:113469a23547 191 fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, CRGB::Black);
abraha2d 1:113469a23547 192 fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, CRGB::Black);
abraha2d 1:113469a23547 193 }
abraha2d 1:113469a23547 194 wait(BLINK_DELAY);
abraha2d 1:113469a23547 195 }
abraha2d 1:113469a23547 196 }
abraha2d 1:113469a23547 197
abraha2d 0:d4e7f9c1287f 198 // main() runs in its own thread in the OS
abraha2d 1:113469a23547 199 int main() {
abraha2d 1:113469a23547 200
abraha2d 2:774edcf60939 201 // Jack up the SPI frequency
abraha2d 1:113469a23547 202 l_strip.frequency(4000000);
abraha2d 1:113469a23547 203 r_strip.frequency(4000000);
abraha2d 1:113469a23547 204
abraha2d 1:113469a23547 205 // Clear out the strip
abraha2d 1:113469a23547 206 fill_solid(l_leds, NUM_LEDS, CRGB::Black);
abraha2d 1:113469a23547 207 fill_solid(r_leds, NUM_LEDS, CRGB::Black);
abraha2d 1:113469a23547 208 APA102_write(l_strip, l_leds, NUM_LEDS);
abraha2d 1:113469a23547 209 APA102_write(r_strip, r_leds, NUM_LEDS);
abraha2d 1:113469a23547 210
abraha2d 1:113469a23547 211 // Start threads
abraha2d 2:774edcf60939 212 pcThread.start(pc_thread);
abraha2d 0:d4e7f9c1287f 213 btThread.start(bt_thread);
abraha2d 1:113469a23547 214 blinkerThread.start(blinker_thread);
abraha2d 1:113469a23547 215
abraha2d 1:113469a23547 216 int ctr = 0;
abraha2d 1:113469a23547 217 bool up = true;
abraha2d 1:113469a23547 218
abraha2d 1:113469a23547 219 for(;;) {
abraha2d 1:113469a23547 220 if (ctr % (gamePwmDen * 7) == 0) {
abraha2d 1:113469a23547 221 gamePwmNum += up ? 1 : -1;
abraha2d 1:113469a23547 222 if (gamePwmNum == gamePwmMax) {
abraha2d 1:113469a23547 223 up = false;
abraha2d 1:113469a23547 224 } else if (gamePwmNum == 1) {
abraha2d 1:113469a23547 225 up = true;
abraha2d 1:113469a23547 226 ctr = 0;
abraha2d 1:113469a23547 227 }
abraha2d 1:113469a23547 228 }
abraha2d 1:113469a23547 229
abraha2d 2:774edcf60939 230 if (lights) {
abraha2d 1:113469a23547 231
abraha2d 2:774edcf60939 232 fill_solid(&(l_leds[HEAD_LIGHT_START]), NUM_HEAD_LIGHT, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
abraha2d 2:774edcf60939 233 fill_solid(&(r_leds[HEAD_LIGHT_START]), NUM_HEAD_LIGHT, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
abraha2d 2:774edcf60939 234
abraha2d 2:774edcf60939 235 if (!(lights & BLINKER_L)) {
abraha2d 2:774edcf60939 236 fill_solid(&(l_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
abraha2d 2:774edcf60939 237 fill_solid(&(l_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
abraha2d 2:774edcf60939 238 }
abraha2d 2:774edcf60939 239
abraha2d 2:774edcf60939 240 if (!(lights & BLINKER_R)) {
abraha2d 2:774edcf60939 241 fill_solid(&(r_leds[HEAD_BLINKER_START]), NUM_HEAD_BLINKER, lights & HEADLIGHT ? COLOR_HEADLIGHT_ON : COLOR_HEADLIGHT_DIM);
abraha2d 2:774edcf60939 242 fill_solid(&(r_leds[TAIL_BLINKER_START]), NUM_TAIL_BLINKER, lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
abraha2d 2:774edcf60939 243 }
abraha2d 2:774edcf60939 244
abraha2d 2:774edcf60939 245 fill_solid(&(l_leds[HEAD_FOG_START]), NUM_HEAD_FOG, lights & FOGLIGHT ? COLOR_FOGLIGHT : CRGB::Black);
abraha2d 2:774edcf60939 246 fill_solid(&(r_leds[HEAD_FOG_START]), NUM_HEAD_FOG, lights & FOGLIGHT ? COLOR_FOGLIGHT : CRGB::Black);
abraha2d 2:774edcf60939 247
abraha2d 2:774edcf60939 248 fill_solid(&(l_leds[GLOW_START]), NUM_GLOW, lights & UNDERGLOW ? COLOR_UNDERGLOW : CRGB::Black);
abraha2d 2:774edcf60939 249 fill_solid(&(r_leds[GLOW_START]), NUM_GLOW, lights & UNDERGLOW ? COLOR_UNDERGLOW : CRGB::Black);
abraha2d 2:774edcf60939 250
abraha2d 2:774edcf60939 251 fill_solid(&(l_leds[TAIL_REVERSE_START]), NUM_TAIL_REVERSE, lights & REVERSE ? COLOR_REVERSE :
abraha2d 2:774edcf60939 252 lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
abraha2d 2:774edcf60939 253 fill_solid(&(r_leds[TAIL_REVERSE_START]), NUM_TAIL_REVERSE, lights & REVERSE ? COLOR_REVERSE :
abraha2d 2:774edcf60939 254 lights & BRAKELIGHT ? COLOR_BRAKELIGHT : COLOR_TAILLIGHT);
abraha2d 2:774edcf60939 255
abraha2d 2:774edcf60939 256 } else {
abraha2d 2:774edcf60939 257
abraha2d 2:774edcf60939 258 fill_solid(&(l_leds[0]), NUM_LEDS, CRGB::Black);
abraha2d 2:774edcf60939 259 fill_solid(&(r_leds[0]), NUM_LEDS, CRGB::Black);
abraha2d 2:774edcf60939 260
abraha2d 1:113469a23547 261 }
abraha2d 1:113469a23547 262
abraha2d 1:113469a23547 263 double scaleFactor = ceil((double) gamePwmNum / gamePwmDen);
abraha2d 2:774edcf60939 264 if (numGame != NUM_GAME) {
abraha2d 2:774edcf60939 265 fill_solid(&(l_leds[GAME_START]), NUM_GAME, CRGB::Black);
abraha2d 2:774edcf60939 266 fill_solid(&(r_leds[GAME_START]), NUM_GAME, CRGB::Black);
abraha2d 2:774edcf60939 267 }
abraha2d 2:774edcf60939 268 fill_solid(&(l_leds[GAME_START]), numGame, (ctr % gamePwmDen) < (gamePwmNum / scaleFactor) ? gameColor * scaleFactor : CRGB::Black);
abraha2d 2:774edcf60939 269 fill_solid(&(r_leds[GAME_START]), numGame, (ctr % gamePwmDen) < (gamePwmNum / scaleFactor) ? gameColor * scaleFactor : CRGB::Black);
abraha2d 1:113469a23547 270 ctr++;
abraha2d 1:113469a23547 271
abraha2d 1:113469a23547 272 APA102_write(l_strip, l_leds, NUM_LEDS);
abraha2d 1:113469a23547 273 APA102_write(r_strip, r_leds, NUM_LEDS);
abraha2d 1:113469a23547 274
abraha2d 1:113469a23547 275 wait(0);
abraha2d 0:d4e7f9c1287f 276 }
abraha2d 0:d4e7f9c1287f 277 }