Skip to content

Commit 966a03b

Browse files
committed
input: Add IR sensor code for ducking detection
Signed-off-by: Brian Tsoi <[email protected]>
1 parent b5077fa commit 966a03b

File tree

5 files changed

+903
-20
lines changed

5 files changed

+903
-20
lines changed

game/python/dino_jump_main.py

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import random
77
import numpy as np
88
import pygame
9+
import serial
910

1011
from sprites import import_sprite
1112

@@ -15,6 +16,8 @@
1516
#############################################################################
1617

1718

19+
ser = serial.Serial('COM10', 9600, timeout=0)
20+
1821
class Game:
1922

2023
def __init__(self):
@@ -143,23 +146,36 @@ def check_start_game(self):
143146
self.dino.is_jumping = True
144147
self.dino.update_jumping_location()
145148

149+
# def check_user_input(self):
150+
# for event in pygame.event.get():
151+
# if event.type == pygame.QUIT:
152+
# pygame.quit()
153+
# sys.exit()
154+
155+
# if event.type == pygame.KEYDOWN:
156+
# if event.key == pygame.K_SPACE:
157+
# self.dino.is_jumping = True
158+
# if event.key == pygame.K_DOWN:
159+
# self.dino.is_ducking = True
160+
161+
# if event.type == pygame.KEYUP:
162+
# # if event.key == pygame.K_SPACE:
163+
# # self.dino.is_jumping = False
164+
# if event.key == pygame.K_DOWN:
165+
# self.dino.is_ducking = False
166+
146167
def check_user_input(self):
147-
for event in pygame.event.get():
148-
if event.type == pygame.QUIT:
149-
pygame.quit()
150-
sys.exit()
151-
152-
if event.type == pygame.KEYDOWN:
153-
if event.key == pygame.K_SPACE:
154-
self.dino.is_jumping = True
155-
if event.key == pygame.K_DOWN:
156-
self.dino.is_ducking = True
157-
158-
if event.type == pygame.KEYUP:
159-
# if event.key == pygame.K_SPACE:
160-
# self.dino.is_jumping = False
161-
if event.key == pygame.K_DOWN:
162-
self.dino.is_ducking = False
168+
in_waiting = ser.in_waiting
169+
if in_waiting > 0 and not self.dino.is_jumping:
170+
s = str(ser.read(in_waiting))
171+
if 'J' in s:
172+
self.dino.is_jumping = True
173+
if 'D' in s:
174+
self.dino.is_ducking = True
175+
print(s)
176+
else:
177+
self.dino.is_ducking = False
178+
163179

164180
def update_full_game_state(self):
165181
self.background_game_state_array = np.zeros((game.HEIGHT, game.WIDTH)).astype(
@@ -390,8 +406,8 @@ def update_frame(self):
390406
#############################################################################
391407

392408
# Wait until first space bar press until the game starts
393-
while not game.start_game:
394-
game.check_start_game()
409+
# while not game.start_game:
410+
# game.check_start_game()
395411

396412
# Simulates the whole loop running
397413
while not game.game_over:
@@ -402,10 +418,9 @@ def update_frame(self):
402418
game.dino.update_dino_footing()
403419
game.all_obstacles.update_location()
404420
game.update_full_game_state()
405-
game.check_collision_and_game_over()
421+
# game.check_collision_and_game_over()
406422
game.draw_to_screen()
407423

408-
print("game over!")
409424
game.dino.update_frame()
410425
game.dino.update_dino_footing()
411426
game.update_full_game_state()

input/ir_sensor/ir_sensor.ino

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
const int SAMPLE_SIZE = 10;
2+
const int IR_PIN_0 = A0;
3+
const int IR_PIN_1 = A1;
4+
const int IR_PIN_2 = A2;
5+
const int IR_0_THRESHOLD = 500;
6+
const int IR_1_THRESHOLD = 500;
7+
const int IR_2_THRESHOLD = 500;
8+
9+
void setup() {
10+
Serial.begin(9600);
11+
}
12+
13+
void loop() {
14+
// print_val();
15+
// print_min_of_samples();
16+
detect_ducking();
17+
detect_jumping();
18+
delay(5);
19+
}
20+
21+
void print_min_of_samples() {
22+
int min0 = min_of_samples(IR_PIN_0);
23+
char buf[32] = {0};
24+
sprintf(buf, "0:%d", min0);
25+
Serial.println(buf);
26+
27+
if (min0 > IR_0_THRESHOLD) {
28+
Serial.println("H0");
29+
} else {
30+
Serial.println("L0");
31+
}
32+
33+
int min1 = min_of_samples(IR_PIN_1);
34+
sprintf(buf, "1:%d", min1);
35+
Serial.println(buf);
36+
37+
if (min1 > IR_1_THRESHOLD) {
38+
Serial.println("H1");
39+
} else {
40+
Serial.println("L1");
41+
}
42+
43+
int min2 = min_of_samples(IR_PIN_2);
44+
sprintf(buf, "2:%d", min2);
45+
Serial.println(buf);
46+
47+
if (min2 > IR_2_THRESHOLD) {
48+
Serial.println("H2");
49+
} else {
50+
Serial.println("L2");
51+
}
52+
}
53+
54+
void detect_ducking() {
55+
int min1 = min_of_samples(IR_PIN_1);
56+
int min2 = min_of_samples(IR_PIN_2);
57+
58+
if (min1 < IR_1_THRESHOLD && min2 < IR_2_THRESHOLD) {
59+
Serial.println("D");
60+
}
61+
}
62+
63+
int min_of_samples(const int pin) {
64+
uint32_t min = 0xFFFFFFFF;
65+
66+
for (int i = 0; i < SAMPLE_SIZE; i++) {
67+
int val = analogRead(pin);
68+
if (min > val) {
69+
min = val;
70+
}
71+
}
72+
73+
return min;
74+
}
75+
76+
77+
void print_val() {
78+
// analogRead takes ~100us
79+
int read_val = analogRead(IR_PIN_1);
80+
char buf[32] = {0};
81+
sprintf(buf, "1:%d", read_val);
82+
Serial.println(buf);
83+
84+
read_val = analogRead(IR_PIN_2);
85+
sprintf(buf, "2:%d", read_val);
86+
Serial.println(buf);
87+
}
88+
89+
enum State { IDLE, STANDING, JUMPING, JUMPED };
90+
State currentState = IDLE;
91+
92+
const int JUMP_COOLDOWN = 500;
93+
long jump_start_time = 0;
94+
95+
void detect_jumping(){
96+
int min = min_of_samples(IR_PIN_0);
97+
98+
long curr_time = millis();
99+
bool jump_cooldowned = curr_time - jump_start_time > JUMP_COOLDOWN;
100+
101+
// if detect something previously -> don't detect anything currently = jump -> go back to detecting
102+
// if something was detected previously
103+
switch(currentState){
104+
case IDLE: //no person here
105+
//check if person appeared
106+
if(min > IR_0_THRESHOLD){ //person appeared
107+
currentState = STANDING;
108+
} else {
109+
currentState = IDLE;
110+
}
111+
break;
112+
case STANDING: //person standing there
113+
//check if person jumped
114+
if(min < IR_0_THRESHOLD && jump_cooldowned){ //person disappeared -> jumped
115+
currentState = JUMPING;
116+
jump_start_time = curr_time;
117+
Serial.println("J");
118+
} else {
119+
currentState = STANDING;
120+
}
121+
break;
122+
case JUMPING: // person jumping
123+
if(min < IR_0_THRESHOLD){ //person still jumping
124+
currentState = JUMPING;
125+
} else {
126+
currentState = JUMPED;
127+
}
128+
break;
129+
case JUMPED: //person jumped -> only register jumping once
130+
currentState = STANDING; //back to standing
131+
break;
132+
}
133+
134+
}
135+
136+

input/ir_sensor/plot_ir.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import serial
2+
import matplotlib.pyplot as plt
3+
import matplotlib.animation as animation
4+
from collections import deque
5+
6+
SERIAL_PORT = 'COM10'
7+
BAUD_RATE = 9600
8+
DATA_POINTS = 200
9+
Y_LOWER_LIM = 0
10+
Y_UPPER_LIM = 4096
11+
12+
# DATA_POINTS = 2000
13+
# Y_LOWER_LIM = -2
14+
# Y_UPPER_LIM = 2
15+
16+
data_buffer_0 = deque(maxlen=DATA_POINTS)
17+
data_buffer_1 = deque(maxlen=DATA_POINTS)
18+
data_buffer_2 = deque(maxlen=DATA_POINTS)
19+
20+
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=0)
21+
print(f"Connected to {SERIAL_PORT} at {BAUD_RATE} baud.")
22+
23+
fig, ax = plt.subplots()
24+
ax.set_title("Real-Time Serial Data Plot")
25+
ax.set_xlabel("Data Points")
26+
ax.set_ylabel("Value")
27+
28+
line0, = ax.plot([], [], lw=2)
29+
line1, = ax.plot([], [], lw=2)
30+
line2, = ax.plot([], [], lw=2)
31+
ax.legend()
32+
33+
text0 = ax.text(0.3, 0.95, '', transform=ax.transAxes, ha='center', color='blue', fontsize=12)
34+
text1 = ax.text(0.5, 0.95, '', transform=ax.transAxes, ha='center', color='orange', fontsize=12)
35+
text2 = ax.text(0.7, 0.95, '', transform=ax.transAxes, ha='center', color='green', fontsize=12)
36+
37+
def init():
38+
# ax.set_xlim(0, DATA_POINTS * 2 - 1)
39+
ax.set_xlim(0, DATA_POINTS + 10)
40+
ax.set_ylim(Y_LOWER_LIM, Y_UPPER_LIM)
41+
line0.set_data([], [])
42+
line1.set_data([], [])
43+
line2.set_data([], [])
44+
45+
text0.set_text("")
46+
text1.set_text("")
47+
text2.set_text("")
48+
return line0, line1, line2, text0, text1, text2
49+
50+
def update(frame):
51+
global data_buffer_1, data_buffer_2
52+
53+
try:
54+
while ser.in_waiting > 0:
55+
line_data = ser.readline().decode('utf-8').strip()
56+
print(line_data, end=" ")
57+
if line_data:
58+
if "L" in line_data or "H" in line_data:
59+
if line_data[1] == "0":
60+
text0.set_text(line_data)
61+
elif line_data[1] == "1":
62+
text1.set_text(line_data)
63+
else:
64+
text2.set_text(line_data)
65+
else:
66+
channel, data = line_data.split(":")
67+
value = float(data)
68+
if int(channel) == 0:
69+
data_buffer_0.append(value)
70+
elif int(channel) == 1:
71+
data_buffer_1.append(value)
72+
elif int(channel) == 2:
73+
data_buffer_2.append(value)
74+
else:
75+
print("Unknown channel")
76+
print()
77+
78+
except serial.SerialException as e:
79+
print(f"Serial error: {e}")
80+
81+
line0.set_data(range(len(data_buffer_0)), data_buffer_0)
82+
line1.set_data(range(len(data_buffer_1)), data_buffer_1)
83+
line2.set_data(range(len(data_buffer_2)), data_buffer_2)
84+
return line0, line1, line2, text0, text1, text2
85+
86+
87+
ani = animation.FuncAnimation(fig, update, init_func=init, blit=False, interval=1)
88+
89+
try:
90+
plt.show()
91+
except KeyboardInterrupt:
92+
print("Plotting stopped.")
93+
94+
ser.close()

input/ir_sensor/process_data.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import pandas as pd
2+
import matplotlib.pyplot as plt
3+
4+
file_path = "sample_data.csv"
5+
df = pd.read_csv(file_path, header=None)
6+
7+
# Change num groups to see the effects of number of samples we do for smoothing the signal
8+
# Setting num_groups to 1 shows the original data
9+
num_groups = 1
10+
df['group'] = df.index // num_groups
11+
min_df = df.groupby('group')[0].min().reset_index(drop=True)
12+
13+
plt.figure(figsize=(10, 5))
14+
plt.plot(min_df.index, min_df, marker='o', linestyle='-')
15+
16+
plt.xlabel("Grouped Index")
17+
plt.ylabel("Min Values")
18+
plt.title("Min CSV Data Plot")
19+
plt.ylim([0, 600])
20+
plt.grid()
21+
plt.legend()
22+
plt.show()
23+

0 commit comments

Comments
 (0)