Wemos D1 - Minigame Console
In this project we will use a Wemos D1 Mini to create a tiny Minigame-console.
Components and supplies
Inertial Measurement Unit (IMU) (6 deg of freedom)
Wemos D1 Mini
OLED 0.66 Shield
Battery Shield
Project description
Code
Wemos Minigame
arduino
Here is the code that you can upload to the Wemos D1 mini. You need to install the libraries "Adafruit_GFX" and "Adafruit_SSD1306". I programmed four minigames and also added a function for charging (so that the screen is not on while charging). You can switch between the games by tilting the console far left/right. The brightness is also slightly adjustable by tilting the device forwards/backwards.
1#include<Wire.h> 2#include <Adafruit_GFX.h> 3#include <Adafruit_SSD1306.h> 4 5#define OLED_RESET -1 6Adafruit_SSD1306 display(OLED_RESET); 7 8const int MPU_addr=0x68; // I2C address of the MPU-6050 9int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; 10 11 12void write_setup(int coordx, int coordy, int T_size){ 13 display.setTextSize(T_size); 14 display.setCursor(coordx, coordy); 15} 16 17 18void setup(){ 19 Wire.begin(); 20 Wire.beginTransmission(MPU_addr); 21 Wire.write(0x6B); // PWR_MGMT_1 register 22 Wire.write(0); // set to zero (wakes up the MPU-6050) 23 Wire.endTransmission(true); 24 Serial.begin(9600); 25 26 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 27 28 display.clearDisplay(); 29 display.setTextSize(2); 30 display.setTextColor(WHITE); 31 display.println("Hello"); 32 33 display.display(); 34 delay(1000); 35} 36 37 38int jump(int t){ 39 return int(0.7*t*t - 11*t + 42); 40} 41 42void read_gyro(int16_t* AcX, int16_t* AcY, int16_t* AcZ){ 43 Wire.beginTransmission(MPU_addr); 44 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 45 Wire.endTransmission(false); 46 Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers 47 *AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 48 *AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 49 *AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 50} 51 52 53void title(char Str[]){ 54 display.clearDisplay(); 55 write_setup(0, 1, 2); 56 display.println(Str); 57 58 display.display(); 59 delay(1000); 60 display.clearDisplay(); 61} 62 63 64void jump(){ 65 while(true){ 66 title("Jump"); 67 display.fillRect(0,46,64,2,1); 68 69 float adder = 1.9; 70 bool b = true; 71 int y = 42; 72 int x = 15; 73 int t = 0; 74 bool jumb = false; 75 76 77 for(int j = 0; true; ++j){ 78 int b1x = 63; 79 int b1y = random(28, 41); 80 int b1_height = 46 - b1y; 81 int b1_width = random(int(adder)*2, int(adder)*6); 82 adder += 0.1; 83 84 for(int i = 63 + b1_width + random(0, int(adder)*15); i > -b1_width; i -= int(adder)){ 85 read_gyro(&AcX, &AcY, &AcZ); 86 87 display.fillScreen(0); 88 display.fillRect(i,b1y,b1_width,b1_height,1); 89 display.fillRect(0,46,64,2,1); 90 91 if(AcZ < -22800){jumb = true;} 92 if(jumb && t<15){ 93 ++t; 94 y = jump(t); 95 } 96 else{ 97 jumb = false; 98 t = 0; 99 y = 42; 100 } 101 102 display.drawCircle(x,y,3,1); 103 write_setup(45,10,1); 104 display.print(j); 105 106 display.display(); 107 delay(1); 108 109 if(i > 12 - b1_width && i < 19 && y + 4 > b1y){ 110 write_setup(1,11,1); 111 display.print("Crash!"); 112 display.display(); 113 delay(1500); 114 jump(); 115 } 116 117 if(AcX > 12000){gravity();} 118 else if(AcX < -8000){shoot();} 119 if(AcY > 12000){display.dim(true);} 120 else if(AcY < -12000){display.dim(false);} 121 } 122 123 } 124 } 125 126} 127 128 129void gravity(){ 130 title("Catch"); 131 int x = 31; 132 int y = 20; 133 int Ay = 0; 134 int Ax = 0; 135 int t0 = millis(); 136 int t_rem = 10000; 137 int count = 0; 138 bool done = false; 139 140 141 while(!done){ 142 int bx = random(8, 64); 143 int by = random(8, 48); 144 145 while(abs(x-bx) > 5 || abs(y-by) > 5){ 146 Ax = 0; 147 Ay = 0; 148 for(int i = 0; i < 5; i++){ 149 read_gyro(&AcX, &AcY, &AcZ); 150 Ax += AcX; 151 Ay += AcY; 152 delay(3); 153 } 154 155 Ax /= 5; 156 Ay /= 5; 157 x = -3*int((Ax - 550)/400) + 30; 158 y = -3*int((Ay + 265)/400) + 20; 159 display.clearDisplay(); 160 if(x > 63){x = 63;} 161 else if(x < 0){x = 0;} 162 if(y > 47){y = 47;} 163 else if(y < 0){y = 0;} 164 165 write_setup(0,1,1); 166 if((t_rem-(millis()-t0))/1000 > 12000){done = true; break;} 167 display.print((t_rem-(millis()-t0))/1000); 168 display.fillCircle(x, y, 3, 1); 169 display.drawCircle(bx, by, 3, 1); 170 display.display(); 171 delay(1); 172 173 if(AcX < -12000){jump();} 174 if(AcY > 12000){display.dim(true);} 175 else if(AcY < -12000){display.dim(false);} 176 } 177 if(!done){count += 1;} 178 } 179 display.clearDisplay(); 180 write_setup(2,15,1); 181 display.print("Score: "); 182 display.print(count); 183 display.display(); 184 delay(2000); 185 gravity(); 186 187} 188 189 190void shoot(){ 191 title("Shoot"); 192 int x = 0; 193 int py = 42; 194 int px = 0; 195 bool shot = true; 196 int f1x = random(0, 64); 197 int f1y = -random(2, 50); 198 int f2x = random(0,64); 199 int f2y = -random(2, 15); 200 int score = 0; 201 int Ax = 0; 202 203 while(true){ 204 205 while(true){ 206 for(int i = 0; i < 3; i++){ 207 read_gyro(&AcX, &AcY, &AcZ); 208 Ax += AcX; 209 delay(3); 210 } 211 212 Ax /= 3; 213 display.clearDisplay(); 214 x = -3*int((Ax - 550)/400) + 30; 215 Ax = 0; 216 if(x > 59){x = 59;} 217 else if(x < -5){x = -5;} 218 display.fillRect(x, 45, 11, 3, 1); 219 if(shot){px = x+5; shot = false;} 220 display.fillRect(x+4, 42, 3, 3, 1); 221 display.drawRect(px, py, 1, 3, 1); 222 display.fillCircle(f1x, f1y, 2, 1); 223 display.fillCircle(f2x, f2y, 2, 1); 224 display.display(); 225 delay(1); 226 227 if(py < -1){ 228 shot = true; 229 py = 40; 230 } 231 232 if(abs(px-f1x) < 4 && py < f1y){ 233 shot = true; 234 py = 42; 235 f1x = random(0, 64); 236 f1y = -random(5*(int(score/20)+1), 30*(int(score/12)+1)); 237 score += 1; 238 } 239 240 else if(abs(px-f2x) < 4 && py < f2y){ 241 shot = true; 242 py = 42; 243 f2x = random(0, 64); 244 f2y = -random(4*(int(score/15)+1), 40*(int(score/12)+1)); 245 score += 1; 246 } 247 248 py -= 4*(int(score/15)+1); 249 f1y += 1 + int(score/30); 250 f2y += 1 + int(score/15); 251 252 if(f1y > 46 || f2y > 46){ 253 delay(100); 254 write_setup(3, 10, 1); 255 display.print("Hit!"); 256 display.display(); 257 delay(1000); 258 display.clearDisplay(); 259 write_setup(3, 10, 1); 260 display.print("Score: "); 261 display.print(score); 262 display.display(); 263 delay(2000); 264 shoot(); 265 } 266 267 if(AcX < -12000){track();} 268 else if(AcX > 12000){jump();} 269 if(AcY > 12000){display.dim(true);} 270 else if(AcY < -12000){display.dim(false);} 271 } 272 } 273} 274 275 276void track(){ 277 title("Track"); 278 int x; 279 int Ax = 0; 280 int coord[54]; 281 int p = 15; 282 unsigned int dist = 0; 283 for(int i = 0; i < 54; i+=2){ 284 coord[i] = random(0,65); 285 coord[i+1] = random(0,49); 286 } 287 int line1[2] = {30, 48}; 288 int line2[2] = {37, 0}; 289 int line3[2] = {28, -48}; 290 291 while(true){ 292 for(int i = 0; i < 3; i++){ 293 read_gyro(&AcX, &AcY, &AcZ); 294 Ax += AcX; 295 delay(3); 296 } 297 298 Ax /= 3; 299 display.clearDisplay(); 300 x = -3*int((Ax - 550)/400) + 30; 301 Ax = 0; 302 if(x > 59){x = 59;} 303 else if(x < -5){x = -5;} 304 305 for(int i = -3; i < 4; i++){ 306 display.drawLine(line1[0]+i, line1[1], line2[0]+i, line2[1], 1); 307 display.drawLine(line2[0]+i, line2[1], line3[0]+i, line3[1], 1); 308 } 309 310 311 for(int i = 0; i < 54; i+=2){ 312 display.drawPixel(coord[i], coord[i+1], 1); 313 } 314 display.fillCircle(x, 42, 3, 0); 315 display.drawCircle(x, 42, 4, 1); 316 display.display(); 317 delay(1); 318 319 float h = p*(line2[0]-line1[0])/64; 320 if(abs(x - (line1[0] + h)) > 8 + abs(4*h/p) && p < 48){ 321 if(AcX < -12000){charging();} 322 else if(AcX > 12000){shoot();} 323 if(AcY > 12000){display.dim(true);} 324 else if(AcY < -12000){display.dim(false);} 325 display.fillCircle(x, 42, 4, 0); 326 display.drawCircle(x, 42, 3, 1); 327 display.display(); 328 delay(150); 329 display.fillCircle(x, 42, 3, 0); 330 display.drawCircle(x, 42, 2, 1); 331 display.display(); 332 delay(150); 333 display.fillCircle(x, 42, 2, 0); 334 display.drawCircle(x, 42, 1, 1); 335 display.display(); 336 delay(200); 337 display.clearDisplay(); 338 write_setup(1,5,1); 339 display.println("Distance: "); 340 display.print(dist); 341 display.display(); 342 delay(2000); 343 track(); 344 } 345 346 347 p += 2 + dist/500; 348 line1[1] += 2 + dist/500; 349 line2[1] += 2 + dist/500; 350 line3[1] += 2 + dist/500; 351 dist += 1; 352 353 if(line2[1] > 48){ 354 line1[0] = line2[0]; line1[1] = line2[1]; 355 line2[0] = line3[0]; line2[1] = line3[1]; 356 line3[0] = random(3, 61); line3[1] = -48; 357 p = 15; 358 } 359 360 361 if(AcX < -12000){charging();} 362 else if(AcX > 12000){shoot();} 363 if(AcY > 12000){display.dim(true);} 364 else if(AcY < -12000){display.dim(false);} 365 } 366} 367 368 369void charging(){ 370 display.clearDisplay(); 371 write_setup(0,1,1); 372 display.println("Charge"); 373 display.display(); 374 delay(2000); 375 display.clearDisplay(); 376 display.display(); 377 378 while(true){ 379 read_gyro(&AcX, &AcY, &AcZ); 380 if(AcX > 12000){track();} 381 delay(10); 382 } 383} 384 385 386void loop(){ 387 gravity(); 388} 389
Wemos Minigame
arduino
Here is the code that you can upload to the Wemos D1 mini. You need to install the libraries "Adafruit_GFX" and "Adafruit_SSD1306". I programmed four minigames and also added a function for charging (so that the screen is not on while charging). You can switch between the games by tilting the console far left/right. The brightness is also slightly adjustable by tilting the device forwards/backwards.
1#include<Wire.h> 2#include <Adafruit_GFX.h> 3#include <Adafruit_SSD1306.h> 4 5#define OLED_RESET -1 6Adafruit_SSD1306 display(OLED_RESET); 7 8const int MPU_addr=0x68; // I2C address of the MPU-6050 9int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; 10 11 12void write_setup(int coordx, int coordy, int T_size){ 13 display.setTextSize(T_size); 14 display.setCursor(coordx, coordy); 15} 16 17 18void setup(){ 19 Wire.begin(); 20 Wire.beginTransmission(MPU_addr); 21 Wire.write(0x6B); // PWR_MGMT_1 register 22 Wire.write(0); // set to zero (wakes up the MPU-6050) 23 Wire.endTransmission(true); 24 Serial.begin(9600); 25 26 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); 27 28 display.clearDisplay(); 29 display.setTextSize(2); 30 display.setTextColor(WHITE); 31 display.println("Hello"); 32 33 display.display(); 34 delay(1000); 35} 36 37 38int jump(int t){ 39 return int(0.7*t*t - 11*t + 42); 40} 41 42void read_gyro(int16_t* AcX, int16_t* AcY, int16_t* AcZ){ 43 Wire.beginTransmission(MPU_addr); 44 Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) 45 Wire.endTransmission(false); 46 Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers 47 *AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) 48 *AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) 49 *AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) 50} 51 52 53void title(char Str[]){ 54 display.clearDisplay(); 55 write_setup(0, 1, 2); 56 display.println(Str); 57 58 display.display(); 59 delay(1000); 60 display.clearDisplay(); 61} 62 63 64void jump(){ 65 while(true){ 66 title("Jump"); 67 display.fillRect(0,46,64,2,1); 68 69 float adder = 1.9; 70 bool b = true; 71 int y = 42; 72 int x = 15; 73 int t = 0; 74 bool jumb = false; 75 76 77 for(int j = 0; true; ++j){ 78 int b1x = 63; 79 int b1y = random(28, 41); 80 int b1_height = 46 - b1y; 81 int b1_width = random(int(adder)*2, int(adder)*6); 82 adder += 0.1; 83 84 for(int i = 63 + b1_width + random(0, int(adder)*15); i > -b1_width; i -= int(adder)){ 85 read_gyro(&AcX, &AcY, &AcZ); 86 87 display.fillScreen(0); 88 display.fillRect(i,b1y,b1_width,b1_height,1); 89 display.fillRect(0,46,64,2,1); 90 91 if(AcZ < -22800){jumb = true;} 92 if(jumb && t<15){ 93 ++t; 94 y = jump(t); 95 } 96 else{ 97 jumb = false; 98 t = 0; 99 y = 42; 100 } 101 102 display.drawCircle(x,y,3,1); 103 write_setup(45,10,1); 104 display.print(j); 105 106 display.display(); 107 delay(1); 108 109 if(i > 12 - b1_width && i < 19 && y + 4 > b1y){ 110 write_setup(1,11,1); 111 display.print("Crash!"); 112 display.display(); 113 delay(1500); 114 jump(); 115 } 116 117 if(AcX > 12000){gravity();} 118 else if(AcX < -8000){shoot();} 119 if(AcY > 12000){display.dim(true);} 120 else if(AcY < -12000){display.dim(false);} 121 } 122 123 } 124 } 125 126} 127 128 129void gravity(){ 130 title("Catch"); 131 int x = 31; 132 int y = 20; 133 int Ay = 0; 134 int Ax = 0; 135 int t0 = millis(); 136 int t_rem = 10000; 137 int count = 0; 138 bool done = false; 139 140 141 while(!done){ 142 int bx = random(8, 64); 143 int by = random(8, 48); 144 145 while(abs(x-bx) > 5 || abs(y-by) > 5){ 146 Ax = 0; 147 Ay = 0; 148 for(int i = 0; i < 5; i++){ 149 read_gyro(&AcX, &AcY, &AcZ); 150 Ax += AcX; 151 Ay += AcY; 152 delay(3); 153 } 154 155 Ax /= 5; 156 Ay /= 5; 157 x = -3*int((Ax - 550)/400) + 30; 158 y = -3*int((Ay + 265)/400) + 20; 159 display.clearDisplay(); 160 if(x > 63){x = 63;} 161 else if(x < 0){x = 0;} 162 if(y > 47){y = 47;} 163 else if(y < 0){y = 0;} 164 165 write_setup(0,1,1); 166 if((t_rem-(millis()-t0))/1000 > 12000){done = true; break;} 167 display.print((t_rem-(millis()-t0))/1000); 168 display.fillCircle(x, y, 3, 1); 169 display.drawCircle(bx, by, 3, 1); 170 display.display(); 171 delay(1); 172 173 if(AcX < -12000){jump();} 174 if(AcY > 12000){display.dim(true);} 175 else if(AcY < -12000){display.dim(false);} 176 } 177 if(!done){count += 1;} 178 } 179 display.clearDisplay(); 180 write_setup(2,15,1); 181 display.print("Score: "); 182 display.print(count); 183 display.display(); 184 delay(2000); 185 gravity(); 186 187} 188 189 190void shoot(){ 191 title("Shoot"); 192 int x = 0; 193 int py = 42; 194 int px = 0; 195 bool shot = true; 196 int f1x = random(0, 64); 197 int f1y = -random(2, 50); 198 int f2x = random(0,64); 199 int f2y = -random(2, 15); 200 int score = 0; 201 int Ax = 0; 202 203 while(true){ 204 205 while(true){ 206 for(int i = 0; i < 3; i++){ 207 read_gyro(&AcX, &AcY, &AcZ); 208 Ax += AcX; 209 delay(3); 210 } 211 212 Ax /= 3; 213 display.clearDisplay(); 214 x = -3*int((Ax - 550)/400) + 30; 215 Ax = 0; 216 if(x > 59){x = 59;} 217 else if(x < -5){x = -5;} 218 display.fillRect(x, 45, 11, 3, 1); 219 if(shot){px = x+5; shot = false;} 220 display.fillRect(x+4, 42, 3, 3, 1); 221 display.drawRect(px, py, 1, 3, 1); 222 display.fillCircle(f1x, f1y, 2, 1); 223 display.fillCircle(f2x, f2y, 2, 1); 224 display.display(); 225 delay(1); 226 227 if(py < -1){ 228 shot = true; 229 py = 40; 230 } 231 232 if(abs(px-f1x) < 4 && py < f1y){ 233 shot = true; 234 py = 42; 235 f1x = random(0, 64); 236 f1y = -random(5*(int(score/20)+1), 30*(int(score/12)+1)); 237 score += 1; 238 } 239 240 else if(abs(px-f2x) < 4 && py < f2y){ 241 shot = true; 242 py = 42; 243 f2x = random(0, 64); 244 f2y = -random(4*(int(score/15)+1), 40*(int(score/12)+1)); 245 score += 1; 246 } 247 248 py -= 4*(int(score/15)+1); 249 f1y += 1 + int(score/30); 250 f2y += 1 + int(score/15); 251 252 if(f1y > 46 || f2y > 46){ 253 delay(100); 254 write_setup(3, 10, 1); 255 display.print("Hit!"); 256 display.display(); 257 delay(1000); 258 display.clearDisplay(); 259 write_setup(3, 10, 1); 260 display.print("Score: "); 261 display.print(score); 262 display.display(); 263 delay(2000); 264 shoot(); 265 } 266 267 if(AcX < -12000){track();} 268 else if(AcX > 12000){jump();} 269 if(AcY > 12000){display.dim(true);} 270 else if(AcY < -12000){display.dim(false);} 271 } 272 } 273} 274 275 276void track(){ 277 title("Track"); 278 int x; 279 int Ax = 0; 280 int coord[54]; 281 int p = 15; 282 unsigned int dist = 0; 283 for(int i = 0; i < 54; i+=2){ 284 coord[i] = random(0,65); 285 coord[i+1] = random(0,49); 286 } 287 int line1[2] = {30, 48}; 288 int line2[2] = {37, 0}; 289 int line3[2] = {28, -48}; 290 291 while(true){ 292 for(int i = 0; i < 3; i++){ 293 read_gyro(&AcX, &AcY, &AcZ); 294 Ax += AcX; 295 delay(3); 296 } 297 298 Ax /= 3; 299 display.clearDisplay(); 300 x = -3*int((Ax - 550)/400) + 30; 301 Ax = 0; 302 if(x > 59){x = 59;} 303 else if(x < -5){x = -5;} 304 305 for(int i = -3; i < 4; i++){ 306 display.drawLine(line1[0]+i, line1[1], line2[0]+i, line2[1], 1); 307 display.drawLine(line2[0]+i, line2[1], line3[0]+i, line3[1], 1); 308 } 309 310 311 for(int i = 0; i < 54; i+=2){ 312 display.drawPixel(coord[i], coord[i+1], 1); 313 } 314 display.fillCircle(x, 42, 3, 0); 315 display.drawCircle(x, 42, 4, 1); 316 display.display(); 317 delay(1); 318 319 float h = p*(line2[0]-line1[0])/64; 320 if(abs(x - (line1[0] + h)) > 8 + abs(4*h/p) && p < 48){ 321 if(AcX < -12000){charging();} 322 else if(AcX > 12000){shoot();} 323 if(AcY > 12000){display.dim(true);} 324 else if(AcY < -12000){display.dim(false);} 325 display.fillCircle(x, 42, 4, 0); 326 display.drawCircle(x, 42, 3, 1); 327 display.display(); 328 delay(150); 329 display.fillCircle(x, 42, 3, 0); 330 display.drawCircle(x, 42, 2, 1); 331 display.display(); 332 delay(150); 333 display.fillCircle(x, 42, 2, 0); 334 display.drawCircle(x, 42, 1, 1); 335 display.display(); 336 delay(200); 337 display.clearDisplay(); 338 write_setup(1,5,1); 339 display.println("Distance: "); 340 display.print(dist); 341 display.display(); 342 delay(2000); 343 track(); 344 } 345 346 347 p += 2 + dist/500; 348 line1[1] += 2 + dist/500; 349 line2[1] += 2 + dist/500; 350 line3[1] += 2 + dist/500; 351 dist += 1; 352 353 if(line2[1] > 48){ 354 line1[0] = line2[0]; line1[1] = line2[1]; 355 line2[0] = line3[0]; line2[1] = line3[1]; 356 line3[0] = random(3, 61); line3[1] = -48; 357 p = 15; 358 } 359 360 361 if(AcX < -12000){charging();} 362 else if(AcX > 12000){shoot();} 363 if(AcY > 12000){display.dim(true);} 364 else if(AcY < -12000){display.dim(false);} 365 } 366} 367 368 369void charging(){ 370 display.clearDisplay(); 371 write_setup(0,1,1); 372 display.println("Charge"); 373 display.display(); 374 delay(2000); 375 display.clearDisplay(); 376 display.display(); 377 378 while(true){ 379 read_gyro(&AcX, &AcY, &AcZ); 380 if(AcX > 12000){track();} 381 delay(10); 382 } 383} 384 385 386void loop(){ 387 gravity(); 388} 389
Downloadable files
Schematics
The only thing to solder is the gyroscope. You have to make the connections as shown in the picture. You may also want to add a switch between the battery and the battery-module, because if you solder the battery to the module there would be no way to turn the device off. After you soldered the gyro to the battery-module the three modules (Wemos D1 mini, Battery Shield, OLED Display) can be stacked together with some header pins.
Schematics

Comments
Only logged in users can leave comments