16
16
from .__init__ import __required_firmware_version__
17
17
18
18
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
+
19
35
class ArduinoAlvik :
20
36
_update_thread_running = False
21
37
_update_thread_id = None
22
38
_events_thread_running = False
23
39
_events_thread_id = None
24
40
41
+ _write_lock = _thread .allocate_lock ()
42
+ _read_lock = _thread .allocate_lock ()
43
+
25
44
def __new__ (cls ):
26
45
if not hasattr (cls , '_instance' ):
27
46
cls ._instance = super (ArduinoAlvik , cls ).__new__ (cls )
@@ -119,7 +138,8 @@ def _print_battery_status(percentage: float, is_charging) -> None:
119
138
word = marks_str + f" { percentage } % { charging_str } \t "
120
139
print (word , end = '' )
121
140
122
- def _lenghty_op (self , iterations = 10000000 ) -> int :
141
+ @staticmethod
142
+ def _lengthy_op (self , iterations = 10000000 ) -> int :
123
143
result = 0
124
144
for i in range (1 , iterations ):
125
145
result += i * i
@@ -134,7 +154,7 @@ def _idle(self, delay_=1, check_on_thread=False, blocking=False) -> None:
134
154
self .i2c .set_single_thread (True )
135
155
136
156
if blocking :
137
- self ._lenghty_op (50000 )
157
+ self ._lengthy_op (50000 )
138
158
else :
139
159
sleep_ms (500 )
140
160
led_val = 0
@@ -157,7 +177,7 @@ def _idle(self, delay_=1, check_on_thread=False, blocking=False) -> None:
157
177
self ._battery_perc = abs (soc_perc )
158
178
self ._print_battery_status (round (soc_perc ), self ._battery_is_charging )
159
179
if blocking :
160
- self ._lenghty_op (10000 )
180
+ self ._lengthy_op (10000 )
161
181
else :
162
182
sleep_ms (delay_ )
163
183
if soc_perc > 97 :
@@ -279,6 +299,7 @@ def _wait_for_fw_check(self, timeout=5) -> bool:
279
299
return False
280
300
281
301
@staticmethod
302
+ @reads_uart
282
303
def _flush_uart ():
283
304
"""
284
305
Empties the UART buffer
@@ -313,6 +334,7 @@ def _wait_for_target(self, idle_time):
313
334
# print(self._last_ack)
314
335
sleep_ms (100 )
315
336
337
+ @writes_uart
316
338
def is_target_reached (self ) -> bool :
317
339
"""
318
340
Returns True if robot has sent an M or R acknowledgment.
@@ -330,6 +352,7 @@ def is_target_reached(self) -> bool:
330
352
return True
331
353
return False
332
354
355
+ @writes_uart
333
356
def set_behaviour (self , behaviour : int ):
334
357
"""
335
358
Sets the behaviour of Alvik
@@ -339,6 +362,7 @@ def set_behaviour(self, behaviour: int):
339
362
self ._packeter .packetC1B (ord ('B' ), behaviour & 0xFF )
340
363
uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
341
364
365
+ @writes_uart
342
366
def rotate (self , angle : float , unit : str = 'deg' , blocking : bool = True ):
343
367
"""
344
368
Rotates the robot by given angle
@@ -355,6 +379,7 @@ def rotate(self, angle: float, unit: str = 'deg', blocking: bool = True):
355
379
if blocking :
356
380
self ._wait_for_target (idle_time = (angle / MOTOR_CONTROL_DEG_S ))
357
381
382
+ @writes_uart
358
383
def move (self , distance : float , unit : str = 'cm' , blocking : bool = True ):
359
384
"""
360
385
Moves the robot by given distance
@@ -408,6 +433,7 @@ def get_wheels_speed(self, unit: str = 'rpm') -> (float | None, float | None):
408
433
"""
409
434
return self .left_wheel .get_speed (unit ), self .right_wheel .get_speed (unit )
410
435
436
+ @writes_uart
411
437
def set_wheels_speed (self , left_speed : float , right_speed : float , unit : str = 'rpm' ):
412
438
"""
413
439
Sets left/right motor speed
@@ -427,6 +453,7 @@ def set_wheels_speed(self, left_speed: float, right_speed: float, unit: str = 'r
427
453
self ._packeter .packetC2F (ord ('J' ), left_speed , right_speed )
428
454
uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
429
455
456
+ @writes_uart
430
457
def set_wheels_position (self , left_angle : float , right_angle : float , unit : str = 'deg' , blocking : bool = True ):
431
458
"""
432
459
Sets left/right motor angle
@@ -490,6 +517,7 @@ def get_line_sensors(self) -> (int | None, int | None, int | None):
490
517
491
518
return self ._left_line , self ._center_line , self ._right_line
492
519
520
+ @writes_uart
493
521
def drive (self , linear_velocity : float , angular_velocity : float , linear_unit : str = 'cm/s' ,
494
522
angular_unit : str = 'deg/s' ):
495
523
"""
@@ -530,6 +558,7 @@ def get_drive_speed(self, linear_unit: str = 'cm/s', angular_unit: str = 'deg/s'
530
558
531
559
return convert_speed (self ._linear_velocity , 'mm/s' , linear_unit ), angular_velocity
532
560
561
+ @writes_uart
533
562
def reset_pose (self , x : float , y : float , theta : float , distance_unit : str = 'cm' , angle_unit : str = 'deg' ):
534
563
"""
535
564
Resets the robot pose
@@ -559,6 +588,7 @@ def get_pose(self, distance_unit: str = 'cm', angle_unit: str = 'deg') \
559
588
convert_distance (self ._y , 'mm' , distance_unit ),
560
589
convert_angle (self ._theta , 'deg' , angle_unit ))
561
590
591
+ @writes_uart
562
592
def set_servo_positions (self , a_position : int , b_position : int ):
563
593
"""
564
594
Sets A/B servomotor angle
@@ -586,10 +616,16 @@ def get_ack(self) -> str:
586
616
"""
587
617
return self ._last_ack
588
618
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 ])
592
627
628
+ @writes_uart
593
629
def _set_leds (self , led_state : int ):
594
630
"""
595
631
Sets the LEDs state
@@ -651,6 +687,7 @@ def _update(self, delay_=1):
651
687
self ._read_message ()
652
688
sleep_ms (delay_ )
653
689
690
+ @reads_uart
654
691
def _read_message (self ) -> None :
655
692
"""
656
693
Read a message from the uC
@@ -1539,15 +1576,15 @@ def writeto_mem(self, addr, memaddr, buf, addrsize=8) -> None:
1539
1576
return i2c .writeto_mem (addr , memaddr , buf , addrsize = addrsize )
1540
1577
1541
1578
1542
-
1543
1579
class _ArduinoAlvikServo :
1544
1580
1545
1581
def __init__ (self , packeter : ucPack , label : str , servo_id : int , position : list [int | None ]):
1546
1582
self ._packeter = packeter
1547
1583
self ._label = label
1548
1584
self ._id = servo_id
1549
1585
self ._position = position
1550
-
1586
+
1587
+ @writes_uart
1551
1588
def set_position (self , position ):
1552
1589
"""
1553
1590
Sets the position of the servo
@@ -1576,7 +1613,8 @@ def __init__(self, packeter: ucPack, label: int, wheel_diameter_mm: float = WHEE
1576
1613
self ._speed = None
1577
1614
self ._position = None
1578
1615
self ._alvik = alvik
1579
-
1616
+
1617
+ @writes_uart
1580
1618
def reset (self , initial_position : float = 0.0 , unit : str = 'deg' ):
1581
1619
"""
1582
1620
Resets the wheel reference position
@@ -1588,6 +1626,7 @@ def reset(self, initial_position: float = 0.0, unit: str = 'deg'):
1588
1626
self ._packeter .packetC2B1F (ord ('W' ), self ._label & 0xFF , ord ('Z' ), initial_position )
1589
1627
uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
1590
1628
1629
+ @writes_uart
1591
1630
def set_pid_gains (self , kp : float = MOTOR_KP_DEFAULT , ki : float = MOTOR_KI_DEFAULT , kd : float = MOTOR_KD_DEFAULT ):
1592
1631
"""
1593
1632
Set PID gains for Alvik wheels
@@ -1607,6 +1646,7 @@ def stop(self):
1607
1646
"""
1608
1647
self .set_speed (0 )
1609
1648
1649
+ @writes_uart
1610
1650
def set_speed (self , velocity : float , unit : str = 'rpm' ):
1611
1651
"""
1612
1652
Sets the motor speed
@@ -1643,6 +1683,7 @@ def get_position(self, unit: str = 'deg') -> float | None:
1643
1683
"""
1644
1684
return convert_angle (self ._position , 'deg' , unit )
1645
1685
1686
+ @writes_uart
1646
1687
def set_position (self , position : float , unit : str = 'deg' , blocking : bool = True ):
1647
1688
"""
1648
1689
Sets left/right motor speed
@@ -1673,6 +1714,7 @@ def __init__(self, packeter: ucPack, label: str, led_state: list[int | None], rg
1673
1714
self ._rgb_mask = rgb_mask
1674
1715
self ._led_state = led_state
1675
1716
1717
+ @writes_uart
1676
1718
def set_color (self , red : bool , green : bool , blue : bool ):
1677
1719
"""
1678
1720
Sets the LED's r,g,b state
0 commit comments