-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
226 lines (179 loc) · 5.44 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import serial
import time
import atexit
import getch
""" Data is sent to the Arduino in '<D,sss>' format where:
D = direction (F: forward, B: backward, S: release, L: left, R: right)
sss = speed (000-255)
"""
SERIAL_PATH = '/dev/arduino' # USB path to connected Arduino
BAUD_RATE = 9600
DELAY = 50/1000
IS_KEYBOARD = False
IS_CONTROLLER = False
STOP_COMMAND = '<S,000>'
HANDSHAKE = '@CM' + str(int(IS_KEYBOARD or IS_CONTROLLER))
HANDSHAKE_LEN = len(HANDSHAKE)
ACK_SIGNAL = '!'
def exit_handler(ser):
""" Stops robot when stopping the program
Sends the STOP_COMMAND to the Arduino when program is manually terminated
"""
SendData(ser, STOP_COMMAND)
ser.flush()
def ReceiveData(ser):
""" Returns data from the serial buffer
Checks if there are any incoming bytes in the given serial buffer every DELAY s
then decodes and returns the data (terminates on newline)
Args:
ser: Serial object to read from
Returns:
data from the given serial buffer
"""
while True:
time.sleep(DELAY)
if ser.in_waiting > 0:
data = ser.readline().decode().rstrip()
# print("Arduino:", data)
return data
def SendData(ser, data):
""" Sends data to the serial buffer
Waits for the ACK_SIGNAL to arrive from the Arduino,
then writes the encoded data to the outgoing serial buffer
Args:
ser: Serial object to write to
data: String to send to the outgoing serial buffer
"""
while True:
ackSignal = ReceiveData(ser)
if ackSignal == ACK_SIGNAL:
# print("Sending:", data)
ser.write(data.encode())
return
# else:
# print(ackSignal) # use for debugging Arduino
def PerformHandshake(ser):
""" Sends and checks the handshake to/from the Arduino
Writes HANDSHAKE to the serial buffer every 1s until
received data from the Arduino matches HANDSHAKE
Args:
ser: Serial object to write to
"""
handshakeComplete = False
while (not handshakeComplete):
ser.write(HANDSHAKE.encode())
inData = ReceiveData(ser)
if (inData == HANDSHAKE):
handshakeComplete = True
ser.write(HANDSHAKE.encode()) # Send signal again for redundancy
print("Pi handshake complete")
return
time.sleep(0.5)
def SpeedTest(ser):
""" Tests speed control
Sends commands to:
Ramp up to max speed (255) going forward, stay at max speed for 1s, then do the same backwards
Args:
ser: Serial object to write to
"""
delay = 1
print("Moving forward")
for i in range(255):
data = '<F,' + str(i).zfill(3) + '>'
SendData(ser, data)
# time.sleep(DELAY)
time.sleep(delay)
for i in range(255,0,-1):
data = '<F,' + str(i).zfill(3) + '>'
SendData(ser, data)
# time.sleep(DELAY)
print("Moving backward")
for i in range(255):
data = '<B,' + str(i).zfill(3) + '>'
SendData(ser, data)
# time.sleep(DELAY)
time.sleep(delay)
for i in range(255,0,-1):
data = '<B,' + str(i).zfill(3) + '>'
SendData(ser, data)
# time.sleep(DELAY)
def TurnTest(ser):
""" Tests turn control
Sends commands to:
Move forward for forwardDelay seconds, then turn 90° left,
move forward again, then turn 90° right
Args:
ser: Serial object to write to
"""
turnDelay = 2.8
forwardDelay = 2
# Move forward
print("Moving forward")
data = '<F,200>'
SendData(ser, data)
time.sleep(forwardDelay)
# Turn 90° left
print("Turning left")
data = '<L,255>'
SendData(ser, data)
time.sleep(turnDelay)
# Move forward
print("Moving forward")
data = '<F,200>'
SendData(ser, data)
time.sleep(forwardDelay)
# Turn 90° right
print("Turning right")
data = '<R,255>'
SendData(ser, data)
time.sleep(turnDelay)
def keyboard_control(key, ser):
""" Handles manual control using the keyboard
Robot continues moving in specified direction until another command is given
SLow and fast speeds are constant
Controls:
w = Forwards Hold shift to use faster speed
s = Backwards x = exit
d = Turn Right any other key = Stop
a = Turn Left
Args:
key: Typed key
"""
fast_spd = '225'
slow_spd = '100'
if key == 'w' :
data = f'<F,{fast_spd}>'
elif key == 'W' :
data = f'<F,{slow_spd}>'
elif key == 's' :
data = f'<B,{fast_spd}>'
elif key == 'S' :
data = f'<B,{slow_spd}>'
elif key == 'd' :
data = f'<R,{fast_spd}>'
elif key == 'D' :
data = f'<R,{slow_spd}>'
elif key == 'a' :
data = f'<L,{fast_spd}>'
elif key == 'A' :
data = f'<L,{slow_spd}>'
elif key == 'x' :
exit()
else:
data = STOP_COMMAND
SendData(ser, data)
if __name__ == '__main__':
ser = serial.Serial(SERIAL_PATH, BAUD_RATE, timeout=1)
atexit.register(exit_handler,ser)
ser.flush()
PerformHandshake(ser)
# SendData(ser, STOP_COMMAND)
while True:
if IS_KEYBOARD:
key = getch.getch() # returns and prints typed key
keyboard_control(key, ser)
else:
SpeedTest(ser)
# TurnTest(ser)