Skip to content

Commit 3ccb00c

Browse files
authored
Merge pull request #3 from gbr1/cleanup
Cleanup
2 parents d20e2c4 + 163f331 commit 3ccb00c

25 files changed

+1167
-95
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea

Blink_fast.bin

-13.3 KB
Binary file not shown.

Blink_slow.bin

-11.8 KB
Binary file not shown.

FLASH.md

-34
This file was deleted.

LICENSE

+373
Large diffs are not rendered by default.

README.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# arduino-alvik-mpy
2+
3+
**Arduino Alvik micropython** library.
4+
5+
6+
7+
<br>
8+
<br>
9+
10+
11+
12+
## How to Install Micropython library
13+
14+
### 1. install mpremote
15+
16+
[mpremote](https://docs.micropython.org/en/latest/reference/mpremote.html) is needed to upload files on the [Arduino® Nano ESP32](https://store.arduino.cc/products/nano-esp32?gad_source=1&gclid=Cj0KCQiA2KitBhCIARIsAPPMEhLtIxV_s7KyLJO4-69RdR1UeFTdgGK_XmI8w7xdbur4gs1oJU4Jl68aAhbaEALw_wcB).
17+
18+
```shell
19+
(venv)$ pip install mpremote
20+
```
21+
22+
### 2. install library
23+
24+
Run the following line to upload all files and download the dependencies needed to run the Arduino Alvik micropython library.
25+
26+
```shell
27+
Linux
28+
$ ./install.sh -p <device port>
29+
30+
Windows
31+
> install.bat -p <device port>
32+
```
33+
34+
***Note: The -p parameter is optional***
35+
36+
37+
__NOTE: DO NOT USE LAB FOR MICROPYTHON TO UPLOAD BIN FILES__
38+
39+
<br>
40+
<br>
41+
42+
### 3. Update firmware on your Arduino® Alvik
43+
44+
Go into `utilities` folder and run:
45+
```shell
46+
Linux
47+
$ ./flash_firmware.sh -p <device port> <path-to-your-firmware>
48+
49+
Windows
50+
> flash_firmware.bat -p <device port> <path-to-your-firmware>
51+
```
52+
Answer `y` to flash firmware.
53+
54+
***Note: The -p parameter is optional***
55+
56+
<br>
57+
<br>
58+
59+
60+
## Examples
61+
62+
Use `mpremote` to copy files into your Arduino® Nano ESP32.
63+
64+
e.g.
65+
``` shell
66+
(venv)$ mpremote connect "COM1" fs cp ./examples/led_setting.py :led_setting.py
67+
```
68+
69+
You can now use Arduino Lab for Micropython to run your examples remotely from the device filesystem.
70+
71+
<br>
72+
73+
__Note: not open bin files with Arduino Lab for Micropython because they will be corrupted__

arduino_alvik.py

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
from uart import uart
2+
import _thread
3+
from time import sleep_ms
4+
5+
from ucPack import ucPack
6+
7+
from pinout_definitions import *
8+
from constants import *
9+
10+
11+
class ArduinoAlvik:
12+
13+
def __init__(self):
14+
self.packeter = ucPack(200)
15+
self._update_thread_running = False
16+
self._update_thread_id = None
17+
self.l_speed = None
18+
self.r_speed = None
19+
self.battery_perc = None
20+
self.touch_bits = None
21+
self.behaviour = None
22+
self.led_state = None
23+
self.red = None
24+
self.green = None
25+
self.blue = None
26+
self.left_line = None
27+
self.center_line = None
28+
self.right_line = None
29+
self.roll = None
30+
self.pitch = None
31+
self.yaw = None
32+
self.left_tof = None
33+
self.center_left_tof = None
34+
self.center_tof = None
35+
self.center_right_tof = None
36+
self.right_tof = None
37+
self.top_tof = None
38+
self.bottom_tof = None
39+
self.version = [None, None, None]
40+
41+
def run(self):
42+
"""
43+
Runs robot background operations (e.g. threaded update)
44+
:return:
45+
"""
46+
self._update_thread_running = True
47+
self._update_thread_id = _thread.start_new_thread(self._update, (1,))
48+
49+
def stop(self):
50+
"""
51+
Stops the background operations
52+
:return:
53+
"""
54+
self._update_thread_running = False
55+
56+
@staticmethod
57+
def reset_hw():
58+
"""
59+
Resets the STM32
60+
:return:
61+
"""
62+
63+
RESET_STM32.value(0)
64+
sleep_ms(100)
65+
RESET_STM32.value(1)
66+
sleep_ms(100)
67+
68+
def get_speeds(self) -> (float, float):
69+
return self.l_speed, self.r_speed
70+
71+
def set_speeds(self, left_speed: float, right_speed: float):
72+
"""
73+
Sets left/right motor speed
74+
:param left_speed:
75+
:param right_speed:
76+
:return:
77+
"""
78+
self.packeter.packetC2F(ord('J'), left_speed, right_speed)
79+
uart.write(self.packeter.msg[0:self.packeter.msg_size])
80+
81+
def set_pid(self, side: str, kp: float, ki: float, kd: float):
82+
"""
83+
Sets motor PID parameters. Side can be 'L' or 'R'
84+
:param side:
85+
:param kp:
86+
:param ki:
87+
:param kd:
88+
:return:
89+
"""
90+
91+
self.packeter.packetC1B3F(ord('P'), ord(side), kp, ki, kd)
92+
uart.write(self.packeter.msg[0:self.packeter.msg_size])
93+
94+
def get_orientation(self) -> (float, float, float):
95+
"""
96+
Returns the orientation of the IMU
97+
:return:
98+
"""
99+
100+
return self.roll, self.pitch, self.yaw
101+
102+
def get_line_sensors(self) -> (int, int, int):
103+
"""
104+
Returns the line sensors readout
105+
:return:
106+
"""
107+
108+
return self.left_line, self.center_line, self.right_line
109+
110+
def set_servo_positions(self, a_position: int, b_position: int):
111+
"""
112+
Sets A/B servomotor angle
113+
:param a_position: position of A servomotor
114+
:param b_position: position of B servomotor
115+
:return:
116+
"""
117+
self.packeter.packetC2B(ord('S'), a_position & 0xFF, b_position & 0xFF)
118+
uart.write(self.packeter.msg[0:self.packeter.msg_size])
119+
120+
# def send_ack(self):
121+
# self.packeter.packetC1B(ord('X'), ACK_)
122+
# uart.write(self.packeter.msg[0:self.packeter.msg_size])
123+
124+
def _set_leds(self, led_state: int):
125+
"""
126+
Sets the LEDs state
127+
:param led_state: one byte 0->builtin 1->illuminator 2->left_red 3->left_green 4->left_blue
128+
5->right_red 6->right_green 7->right_blue
129+
:return:
130+
"""
131+
self.led_state = led_state & 0xFF
132+
self.packeter.packetC1B(ord('L'), self.led_state)
133+
uart.write(self.packeter.msg[0:self.packeter.msg_size])
134+
135+
def set_builtin_led(self, value: bool):
136+
if self.led_state is None:
137+
self._set_leds(0x00)
138+
self.led_state = self.led_state | 0b00000001 if value else self.led_state & 0b11111110
139+
self._set_leds(self.led_state)
140+
141+
def set_illuminator(self, value: bool):
142+
if self.led_state is None:
143+
self._set_leds(0x00)
144+
self.led_state = self.led_state | 0b00000010 if value else self.led_state & 0b11111101
145+
self._set_leds(self.led_state)
146+
147+
def set_left_led_color(self, red: bool, green: bool, blue: bool):
148+
if self.led_state is None:
149+
self._set_leds(0x00)
150+
self.led_state = self.led_state | 0b00000100 if red else self.led_state & 0b11111011
151+
self.led_state = self.led_state | 0b00001000 if green else self.led_state & 0b11110111
152+
self.led_state = self.led_state | 0b00010000 if blue else self.led_state & 0b11101111
153+
self._set_leds(self.led_state)
154+
155+
def set_right_led_color(self, red: bool, green: bool, blue: bool):
156+
if self.led_state is None:
157+
self._set_leds(0x00)
158+
self.led_state = self.led_state | 0b00100000 if red else self.led_state & 0b11011111
159+
self.led_state = self.led_state | 0b01000000 if green else self.led_state & 0b10111111
160+
self.led_state = self.led_state | 0b10000000 if blue else self.led_state & 0b01111111
161+
self._set_leds(self.led_state)
162+
163+
def _update(self, delay_=1):
164+
"""
165+
Updates the robot status reading/parsing messages from UART.
166+
This method is blocking and meant as a thread callback
167+
Use the method stop to terminate _update and exit the thread
168+
:param delay_: while loop delay
169+
:return:
170+
"""
171+
while True:
172+
if not self._update_thread_running:
173+
break
174+
if self._read_message():
175+
self._parse_message()
176+
sleep_ms(delay_)
177+
178+
def _read_message(self) -> bool:
179+
"""
180+
Read a message from the uC
181+
:return: True if a message terminator was reached
182+
"""
183+
while uart.any():
184+
b = uart.read(1)[0]
185+
self.packeter.buffer.push(b)
186+
if b == self.packeter.end_index:
187+
self.packeter.checkPayload()
188+
return True
189+
return False
190+
191+
def _parse_message(self) -> int:
192+
"""
193+
Parse a received message
194+
:return: -1 if parse error 0 if ok
195+
"""
196+
code = self.packeter.payload[0]
197+
if code == ord('j'):
198+
# joint speed
199+
_, self.l_speed, self.r_speed = self.packeter.unpacketC2F()
200+
elif code == ord('l'):
201+
# line sensor
202+
_, self.left_line, self.center_line, self.right_line = self.packeter.unpacketC3I()
203+
elif code == ord('c'):
204+
# color sensor
205+
_, self.red, self.green, self.blue = self.packeter.unpacketC3I()
206+
elif code == ord('i'):
207+
# imu
208+
_, ax, ay, az, gx, gy, gz = self.packeter.unpacketC6F()
209+
elif code == ord('p'):
210+
# battery percentage
211+
_, self.battery_perc = self.packeter.unpacketC1F()
212+
elif code == ord('d'):
213+
# distance sensor
214+
_, self.left_tof, self.center_tof, self.right_tof = self.packeter.unpacketC3I()
215+
elif code == ord('t'):
216+
# touch input
217+
_, self.touch_bits = self.packeter.unpacketC1B()
218+
elif code == ord('b'):
219+
# behaviour
220+
_, self.behaviour = self.packeter.unpacketC1B()
221+
elif code == ord('f'):
222+
# tof matrix
223+
(_, self.left_tof, self.center_left_tof, self.center_tof,
224+
self.center_right_tof, self.right_tof, self.bottom_tof, self.top_tof) = self.packeter.unpacketC7I()
225+
elif code == ord('q'):
226+
# imu position
227+
_, self.roll, self.pitch, self.yaw = self.packeter.unpacketC3F()
228+
elif code == 0x7E:
229+
# firmware version
230+
_, *self.version = self.packeter.unpacketC3B()
231+
else:
232+
return -1
233+
234+
return 0
235+
236+
def _get_touch(self) -> int:
237+
return self.touch_bits
238+
239+
def get_touch_any(self) -> bool:
240+
return bool(self.touch_bits & 0b00000001)
241+
242+
def get_touch_ok(self) -> bool:
243+
return bool(self.touch_bits & 0b00000010)
244+
245+
def get_touch_cancel(self) -> bool:
246+
return bool(self.touch_bits & 0b00000100)
247+
248+
def get_touch_center(self) -> bool:
249+
return bool(self.touch_bits & 0b00001000)
250+
251+
def get_touch_up(self) -> bool:
252+
return bool(self.touch_bits & 0b00010000)
253+
254+
def get_touch_left(self) -> bool:
255+
return bool(self.touch_bits & 0b00100000)
256+
257+
def get_touch_down(self) -> bool:
258+
return bool(self.touch_bits & 0b01000000)
259+
260+
def get_touch_right(self) -> bool:
261+
return bool(self.touch_bits & 0b10000000)
262+
263+
def get_color(self) -> (int, int, int):
264+
"""
265+
Returns the RGB color readout
266+
:return:
267+
"""
268+
269+
return self.red, self.green, self.blue
270+
# return (int((self.red/COLOR_FULL_SCALE)*255),
271+
# int((self.green/COLOR_FULL_SCALE)*255),
272+
# int((self.blue/COLOR_FULL_SCALE)*255))
273+
274+
def get_distance(self) -> (int, int, int, int, int, int):
275+
return self.left_tof, self.center_left_tof, self.center_tof, self.center_right_tof, self.right_tof
276+
277+
def get_version(self) -> str:
278+
return f'{self.version[0]}.{self.version[1]}.{self.version[2]}'
279+
280+
def print_status(self):
281+
for a in vars(self):
282+
if str(a).startswith('_'):
283+
continue
284+
print(f'{str(a).upper()} = {getattr(self, str(a))}')

0 commit comments

Comments
 (0)