Skip to content

Commit 76c831c

Browse files
committed
feat: uart messaging r/w locks
fix: fixes skipping host->robot commands on occasions
1 parent 867f2ce commit 76c831c

File tree

1 file changed

+51
-9
lines changed

1 file changed

+51
-9
lines changed

arduino_alvik/arduino_alvik.py

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,31 @@
1616
from .__init__ import __required_firmware_version__
1717

1818

19+
def writes_uart(method):
20+
def wrapper(*args, **kwargs):
21+
with ArduinoAlvik._write_lock:
22+
method(*args, **kwargs)
23+
24+
return wrapper
25+
26+
27+
def reads_uart(method):
28+
def wrapper(*args, **kwargs):
29+
with ArduinoAlvik._read_lock:
30+
method(*args, **kwargs)
31+
32+
return wrapper
33+
34+
1935
class ArduinoAlvik:
2036
_update_thread_running = False
2137
_update_thread_id = None
2238
_events_thread_running = False
2339
_events_thread_id = None
2440

41+
_write_lock = _thread.allocate_lock()
42+
_read_lock = _thread.allocate_lock()
43+
2544
def __new__(cls):
2645
if not hasattr(cls, '_instance'):
2746
cls._instance = super(ArduinoAlvik, cls).__new__(cls)
@@ -119,7 +138,8 @@ def _print_battery_status(percentage: float, is_charging) -> None:
119138
word = marks_str + f" {percentage}% {charging_str} \t"
120139
print(word, end='')
121140

122-
def _lenghty_op(self, iterations=10000000) -> int:
141+
@staticmethod
142+
def _lengthy_op(self, iterations=10000000) -> int:
123143
result = 0
124144
for i in range(1, iterations):
125145
result += i * i
@@ -134,7 +154,7 @@ def _idle(self, delay_=1, check_on_thread=False, blocking=False) -> None:
134154
self.i2c.set_single_thread(True)
135155

136156
if blocking:
137-
self._lenghty_op(50000)
157+
self._lengthy_op(50000)
138158
else:
139159
sleep_ms(500)
140160
led_val = 0
@@ -157,7 +177,7 @@ def _idle(self, delay_=1, check_on_thread=False, blocking=False) -> None:
157177
self._battery_perc = abs(soc_perc)
158178
self._print_battery_status(round(soc_perc), self._battery_is_charging)
159179
if blocking:
160-
self._lenghty_op(10000)
180+
self._lengthy_op(10000)
161181
else:
162182
sleep_ms(delay_)
163183
if soc_perc > 97:
@@ -279,6 +299,7 @@ def _wait_for_fw_check(self, timeout=5) -> bool:
279299
return False
280300

281301
@staticmethod
302+
@reads_uart
282303
def _flush_uart():
283304
"""
284305
Empties the UART buffer
@@ -313,6 +334,7 @@ def _wait_for_target(self, idle_time):
313334
# print(self._last_ack)
314335
sleep_ms(100)
315336

337+
@writes_uart
316338
def is_target_reached(self) -> bool:
317339
"""
318340
Returns True if robot has sent an M or R acknowledgment.
@@ -330,6 +352,7 @@ def is_target_reached(self) -> bool:
330352
return True
331353
return False
332354

355+
@writes_uart
333356
def set_behaviour(self, behaviour: int):
334357
"""
335358
Sets the behaviour of Alvik
@@ -339,6 +362,7 @@ def set_behaviour(self, behaviour: int):
339362
self._packeter.packetC1B(ord('B'), behaviour & 0xFF)
340363
uart.write(self._packeter.msg[0:self._packeter.msg_size])
341364

365+
@writes_uart
342366
def rotate(self, angle: float, unit: str = 'deg', blocking: bool = True):
343367
"""
344368
Rotates the robot by given angle
@@ -355,6 +379,7 @@ def rotate(self, angle: float, unit: str = 'deg', blocking: bool = True):
355379
if blocking:
356380
self._wait_for_target(idle_time=(angle / MOTOR_CONTROL_DEG_S))
357381

382+
@writes_uart
358383
def move(self, distance: float, unit: str = 'cm', blocking: bool = True):
359384
"""
360385
Moves the robot by given distance
@@ -408,6 +433,7 @@ def get_wheels_speed(self, unit: str = 'rpm') -> (float | None, float | None):
408433
"""
409434
return self.left_wheel.get_speed(unit), self.right_wheel.get_speed(unit)
410435

436+
@writes_uart
411437
def set_wheels_speed(self, left_speed: float, right_speed: float, unit: str = 'rpm'):
412438
"""
413439
Sets left/right motor speed
@@ -427,6 +453,7 @@ def set_wheels_speed(self, left_speed: float, right_speed: float, unit: str = 'r
427453
self._packeter.packetC2F(ord('J'), left_speed, right_speed)
428454
uart.write(self._packeter.msg[0:self._packeter.msg_size])
429455

456+
@writes_uart
430457
def set_wheels_position(self, left_angle: float, right_angle: float, unit: str = 'deg', blocking: bool = True):
431458
"""
432459
Sets left/right motor angle
@@ -490,6 +517,7 @@ def get_line_sensors(self) -> (int | None, int | None, int | None):
490517

491518
return self._left_line, self._center_line, self._right_line
492519

520+
@writes_uart
493521
def drive(self, linear_velocity: float, angular_velocity: float, linear_unit: str = 'cm/s',
494522
angular_unit: str = 'deg/s'):
495523
"""
@@ -530,6 +558,7 @@ def get_drive_speed(self, linear_unit: str = 'cm/s', angular_unit: str = 'deg/s'
530558

531559
return convert_speed(self._linear_velocity, 'mm/s', linear_unit), angular_velocity
532560

561+
@writes_uart
533562
def reset_pose(self, x: float, y: float, theta: float, distance_unit: str = 'cm', angle_unit: str = 'deg'):
534563
"""
535564
Resets the robot pose
@@ -559,6 +588,7 @@ def get_pose(self, distance_unit: str = 'cm', angle_unit: str = 'deg') \
559588
convert_distance(self._y, 'mm', distance_unit),
560589
convert_angle(self._theta, 'deg', angle_unit))
561590

591+
@writes_uart
562592
def set_servo_positions(self, a_position: int, b_position: int):
563593
"""
564594
Sets A/B servomotor angle
@@ -586,10 +616,16 @@ def get_ack(self) -> str:
586616
"""
587617
return self._last_ack
588618

589-
# def send_ack(self):
590-
# self._packeter.packetC1B(ord('X'), ACK_)
591-
# uart.write(self._packeter.msg[0:self._packeter.msg_size])
619+
@writes_uart
620+
def send_ack(self, ack: str = 'K'):
621+
"""
622+
Sends an ack message on UART
623+
:return:
624+
"""
625+
self._packeter.packetC1B(ord('X'), ord(ack))
626+
uart.write(self._packeter.msg[0:self._packeter.msg_size])
592627

628+
@writes_uart
593629
def _set_leds(self, led_state: int):
594630
"""
595631
Sets the LEDs state
@@ -651,6 +687,7 @@ def _update(self, delay_=1):
651687
self._read_message()
652688
sleep_ms(delay_)
653689

690+
@reads_uart
654691
def _read_message(self) -> None:
655692
"""
656693
Read a message from the uC
@@ -1539,15 +1576,15 @@ def writeto_mem(self, addr, memaddr, buf, addrsize=8) -> None:
15391576
return i2c.writeto_mem(addr, memaddr, buf, addrsize=addrsize)
15401577

15411578

1542-
15431579
class _ArduinoAlvikServo:
15441580

15451581
def __init__(self, packeter: ucPack, label: str, servo_id: int, position: list[int | None]):
15461582
self._packeter = packeter
15471583
self._label = label
15481584
self._id = servo_id
15491585
self._position = position
1550-
1586+
1587+
@writes_uart
15511588
def set_position(self, position):
15521589
"""
15531590
Sets the position of the servo
@@ -1576,7 +1613,8 @@ def __init__(self, packeter: ucPack, label: int, wheel_diameter_mm: float = WHEE
15761613
self._speed = None
15771614
self._position = None
15781615
self._alvik = alvik
1579-
1616+
1617+
@writes_uart
15801618
def reset(self, initial_position: float = 0.0, unit: str = 'deg'):
15811619
"""
15821620
Resets the wheel reference position
@@ -1588,6 +1626,7 @@ def reset(self, initial_position: float = 0.0, unit: str = 'deg'):
15881626
self._packeter.packetC2B1F(ord('W'), self._label & 0xFF, ord('Z'), initial_position)
15891627
uart.write(self._packeter.msg[0:self._packeter.msg_size])
15901628

1629+
@writes_uart
15911630
def set_pid_gains(self, kp: float = MOTOR_KP_DEFAULT, ki: float = MOTOR_KI_DEFAULT, kd: float = MOTOR_KD_DEFAULT):
15921631
"""
15931632
Set PID gains for Alvik wheels
@@ -1607,6 +1646,7 @@ def stop(self):
16071646
"""
16081647
self.set_speed(0)
16091648

1649+
@writes_uart
16101650
def set_speed(self, velocity: float, unit: str = 'rpm'):
16111651
"""
16121652
Sets the motor speed
@@ -1643,6 +1683,7 @@ def get_position(self, unit: str = 'deg') -> float | None:
16431683
"""
16441684
return convert_angle(self._position, 'deg', unit)
16451685

1686+
@writes_uart
16461687
def set_position(self, position: float, unit: str = 'deg', blocking: bool = True):
16471688
"""
16481689
Sets left/right motor speed
@@ -1673,6 +1714,7 @@ def __init__(self, packeter: ucPack, label: str, led_state: list[int | None], rg
16731714
self._rgb_mask = rgb_mask
16741715
self._led_state = led_state
16751716

1717+
@writes_uart
16761718
def set_color(self, red: bool, green: bool, blue: bool):
16771719
"""
16781720
Sets the LED's r,g,b state

0 commit comments

Comments
 (0)