@@ -29,7 +29,7 @@ def __init__(self):
2929 self ._packeter = ucPack (200 )
3030 self .left_wheel = _ArduinoAlvikWheel (self ._packeter , ord ('L' ))
3131 self .right_wheel = _ArduinoAlvikWheel (self ._packeter , ord ('R' ))
32- self ._led_state = [ None ]
32+ self ._led_state = list (( None ,))
3333 self .left_led = _ArduinoAlvikRgbLed (self ._packeter , 'left' , self ._led_state ,
3434 rgb_mask = [0b00000100 , 0b00001000 , 0b00010000 ])
3535 self .right_led = _ArduinoAlvikRgbLed (self ._packeter , 'right' , self ._led_state ,
@@ -84,12 +84,13 @@ def _progress_bar(percentage: float) -> None:
8484 :param percentage:
8585 :return:
8686 """
87- sys .stdout .write ('\r ' )
87+ sys .stdout .write (bytes ( '\r ' . encode ( 'utf-8' )) )
8888 if percentage > 97 :
8989 marks_str = ' \U0001F50B '
9090 else :
9191 marks_str = ' \U0001FAAB '
92- sys .stdout .write (marks_str + f" { percentage } % \t " )
92+ word = marks_str + f" { percentage } % \t "
93+ sys .stdout .write (bytes ((word .encode ('utf-8' ))))
9394
9495 def _idle (self , delay_ = 1 , check_on_thread = False ) -> None :
9596 """
@@ -105,20 +106,20 @@ def _idle(self, delay_=1, check_on_thread=False) -> None:
105106 while not self .is_on ():
106107 if check_on_thread and not self .__class__ ._update_thread_running :
107108 break
108- ESP32_SDA = Pin (A4 , Pin .OUT )
109- ESP32_SCL = Pin (A5 , Pin .OUT )
110- ESP32_SCL .value (1 )
111- ESP32_SDA .value (1 )
109+ _ESP32_SDA = Pin (A4 , Pin .OUT )
110+ _ESP32_SCL = Pin (A5 , Pin .OUT )
111+ _ESP32_SCL .value (1 )
112+ _ESP32_SDA .value (1 )
112113 sleep_ms (100 )
113- ESP32_SCL .value (0 )
114- ESP32_SDA .value (0 )
114+ _ESP32_SCL .value (0 )
115+ _ESP32_SDA .value (0 )
115116
116117 cmd = bytearray (1 )
117118 cmd [0 ] = 0x06
118119 i2c = I2C (0 , scl = ESP32_SCL , sda = ESP32_SDA )
119120 i2c .writeto (0x36 , cmd )
120121 soc_raw = struct .unpack ('h' , i2c .readfrom (0x36 , 2 ))[0 ]
121- soc_perc = soc_raw * 0.00390625
122+ soc_perc = soc_raw * 0.00390625
122123 self ._progress_bar (round (soc_perc ))
123124 sleep_ms (delay_ )
124125 if soc_perc > 97 :
@@ -140,30 +141,32 @@ def _idle(self, delay_=1, check_on_thread=False) -> None:
140141 LEDG .value (1 )
141142 NANO_CHK .value (0 )
142143
143- def _snake_robot (self , duration : int = 1000 ):
144+ @staticmethod
145+ def _snake_robot (duration : int = 1000 ):
144146 """
145147 Snake robot animation
146- :param percentage :
148+ :param duration :
147149 :return:
148150 """
149- i = 0
150151
151152 robot = '\U0001F916 '
152153 snake = '\U0001F40D '
153154
154155 cycles = int (duration / 200 )
155156
157+ frame = ''
156158 for i in range (0 , cycles ):
157- sys .stdout .write ('\r ' )
159+ sys .stdout .write (bytes ( '\r ' . encode ( 'utf-8' )) )
158160 pre = ' ' * i
159161 between = ' ' * (i % 2 + 1 )
160162 post = ' ' * 5
161163 frame = pre + snake + between + robot + post
162- sys .stdout .write (frame )
164+ sys .stdout .write (bytes ( frame . encode ( 'utf-8' )) )
163165 sleep_ms (200 )
164166
165- sys .stdout .write ('\r ' )
166- sys .stdout .write ('' )
167+ sys .stdout .write (bytes ('\r ' .encode ('utf-8' )))
168+ clear_frame = ' ' * len (frame )
169+ sys .stdout .write (bytes (clear_frame .encode ('utf-8' )))
167170
168171 def begin (self ) -> int :
169172 """
@@ -309,7 +312,7 @@ def _reset_hw():
309312 RESET_STM32 .value (1 )
310313 sleep_ms (100 )
311314
312- def get_wheels_speed (self , unit : str = 'rpm' ) -> (float , float ):
315+ def get_wheels_speed (self , unit : str = 'rpm' ) -> (float | None , float | None ):
313316 """
314317 Returns the speed of the wheels
315318 :param unit: the speed unit of measurement (default: 'rpm')
@@ -327,8 +330,8 @@ def set_wheels_speed(self, left_speed: float, right_speed: float, unit: str = 'r
327330 """
328331
329332 if unit == '%' :
330- left_speed = (left_speed / 100 )* MOTOR_MAX_RPM
331- right_speed = (right_speed / 100 )* MOTOR_MAX_RPM
333+ left_speed = (left_speed / 100 ) * MOTOR_MAX_RPM
334+ right_speed = (right_speed / 100 ) * MOTOR_MAX_RPM
332335 else :
333336 left_speed = convert_rotational_speed (left_speed , unit , 'rpm' )
334337 right_speed = convert_rotational_speed (right_speed , unit , 'rpm' )
@@ -345,10 +348,10 @@ def set_wheels_position(self, left_angle: float, right_angle: float, unit: str =
345348 :return:
346349 """
347350 self ._packeter .packetC2F (ord ('A' ), convert_angle (left_angle , unit , 'deg' ),
348- convert_angle (right_angle , unit , 'deg' ))
351+ convert_angle (right_angle , unit , 'deg' ))
349352 uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
350353
351- def get_wheels_position (self , unit : str = 'deg' ) -> (float , float ):
354+ def get_wheels_position (self , unit : str = 'deg' ) -> (float | None , float | None ):
352355 """
353356 Returns the angle of the wheels
354357 :param unit: the angle unit of measurement (default: 'deg')
@@ -357,36 +360,36 @@ def get_wheels_position(self, unit: str = 'deg') -> (float, float):
357360 return (convert_angle (self .left_wheel .get_position (), 'deg' , unit ),
358361 convert_angle (self .right_wheel .get_position (), 'deg' , unit ))
359362
360- def get_orientation (self ) -> (float , float , float ):
363+ def get_orientation (self ) -> (float | None , float | None , float | None ):
361364 """
362365 Returns the orientation of the IMU
363366 :return: roll, pitch, yaw
364367 """
365368
366369 return self ._roll , self ._pitch , self ._yaw
367370
368- def get_accelerations (self ) -> (float , float , float ):
371+ def get_accelerations (self ) -> (float | None , float | None , float | None ):
369372 """
370373 Returns the 3-axial acceleration of the IMU
371374 :return: ax, ay, az
372375 """
373376 return self ._ax , self ._ay , self ._az
374377
375- def get_gyros (self ) -> (float , float , float ):
378+ def get_gyros (self ) -> (float | None , float | None , float | None ):
376379 """
377380 Returns the 3-axial angular acceleration of the IMU
378381 :return: gx, gy, gz
379382 """
380383 return self ._gx , self ._gy , self ._gz
381384
382- def get_imu (self ) -> (float , float , float , float , float , float ):
385+ def get_imu (self ) -> (float | None , float | None , float | None , float | None , float | None , float | None ):
383386 """
384387 Returns all the IMUs readouts
385388 :return: ax, ay, az, gx, gy, gz
386389 """
387390 return self ._ax , self ._ay , self ._az , self ._gx , self ._gy , self ._gz
388391
389- def get_line_sensors (self ) -> (int , int , int ):
392+ def get_line_sensors (self ) -> (int | None , int | None , int | None ):
390393 """
391394 Returns the line sensors readout
392395 :return: left_line, center_line, right_line
@@ -406,7 +409,7 @@ def drive(self, linear_velocity: float, angular_velocity: float, linear_unit: st
406409 """
407410 linear_velocity = convert_speed (linear_velocity , linear_unit , 'mm/s' )
408411 if angular_unit == '%' :
409- angular_velocity = (angular_velocity / 100 )* ROBOT_MAX_DEG_S
412+ angular_velocity = (angular_velocity / 100 ) * ROBOT_MAX_DEG_S
410413 else :
411414 angular_velocity = convert_rotational_speed (angular_velocity , angular_unit , 'deg/s' )
412415 self ._packeter .packetC2F (ord ('V' ), linear_velocity , angular_velocity )
@@ -419,15 +422,16 @@ def brake(self):
419422 """
420423 self .drive (0 , 0 )
421424
422- def get_drive_speed (self , linear_unit : str = 'cm/s' , angular_unit : str = 'deg/s' ) -> (float , float ):
425+ def get_drive_speed (self , linear_unit : str = 'cm/s' , angular_unit : str = 'deg/s' ) -> (float | None , float | None ):
423426 """
424427 Returns linear and angular velocity of the robot
425428 :param linear_unit: output linear velocity unit of meas
426429 :param angular_unit: output angular velocity unit of meas
427430 :return: linear_velocity, angular_velocity
428431 """
429432 if angular_unit == '%' :
430- angular_velocity = (self ._angular_velocity / ROBOT_MAX_DEG_S )* 100
433+ angular_velocity = (self ._angular_velocity / ROBOT_MAX_DEG_S ) * 100 \
434+ if self ._angular_velocity is not None else None
431435 else :
432436 angular_velocity = convert_rotational_speed (self ._angular_velocity , 'deg/s' , angular_unit )
433437
@@ -450,7 +454,8 @@ def reset_pose(self, x: float, y: float, theta: float, distance_unit: str = 'cm'
450454 uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
451455 sleep_ms (1000 )
452456
453- def get_pose (self , distance_unit : str = 'cm' , angle_unit : str = 'deg' ) -> (float , float , float ):
457+ def get_pose (self , distance_unit : str = 'cm' , angle_unit : str = 'deg' ) \
458+ -> (float | None , float | None , float | None ):
454459 """
455460 Returns the current pose of the robot
456461 :param distance_unit: unit of x and y outputs
@@ -471,7 +476,7 @@ def set_servo_positions(self, a_position: int, b_position: int):
471476 self ._packeter .packetC2B (ord ('S' ), a_position & 0xFF , b_position & 0xFF )
472477 uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
473478
474- def get_ack (self ):
479+ def get_ack (self ) -> str :
475480 """
476481 Returns last acknowledgement
477482 :return:
@@ -609,11 +614,13 @@ def _parse_message(self) -> int:
609614
610615 return 0
611616
612- def get_battery_charge (self ) -> int :
617+ def get_battery_charge (self ) -> int | None :
613618 """
614619 Returns the battery SOC
615620 :return:
616621 """
622+ if self ._battery_perc is None :
623+ return None
617624 if self ._battery_perc > 100 :
618625 return 100
619626 return round (self ._battery_perc )
@@ -729,9 +736,9 @@ def color_calibration(self, background: str = 'white') -> None:
729736 blue_avg += blue
730737 sleep_ms (10 )
731738
732- red_avg = int (red_avg / 100 )
733- green_avg = int (green_avg / 100 )
734- blue_avg = int (blue_avg / 100 )
739+ red_avg = int (red_avg / 100 )
740+ green_avg = int (green_avg / 100 )
741+ blue_avg = int (blue_avg / 100 )
735742
736743 if background == 'white' :
737744 self ._white_cal = [red_avg , green_avg , blue_avg ]
@@ -763,7 +770,7 @@ def color_calibration(self, background: str = 'white') -> None:
763770 for line in lines :
764771 file .write (line )
765772
766- def get_color_raw (self ) -> (int , int , int ):
773+ def get_color_raw (self ) -> (int | None , int | None , int | None ):
767774 """
768775 Returns the color sensor's raw readout
769776 :return: red, green, blue
@@ -783,9 +790,9 @@ def _normalize_color(self, r: float, g: float, b: float) -> (float, float, float
783790 g = self ._limit (g , self ._black_cal [1 ], self ._white_cal [1 ])
784791 b = self ._limit (b , self ._black_cal [2 ], self ._white_cal [2 ])
785792
786- r = (r - self ._black_cal [0 ])/ (self ._white_cal [0 ] - self ._black_cal [0 ])
787- g = (g - self ._black_cal [1 ])/ (self ._white_cal [1 ] - self ._black_cal [1 ])
788- b = (b - self ._black_cal [2 ])/ (self ._white_cal [2 ] - self ._black_cal [2 ])
793+ r = (r - self ._black_cal [0 ]) / (self ._white_cal [0 ] - self ._black_cal [0 ])
794+ g = (g - self ._black_cal [1 ]) / (self ._white_cal [1 ] - self ._black_cal [1 ])
795+ b = (b - self ._black_cal [2 ]) / (self ._white_cal [2 ] - self ._black_cal [2 ])
789796
790797 return r , g , b
791798
@@ -829,7 +836,7 @@ def rgb2hsv(r: float, g: float, b: float) -> (float, float, float):
829836
830837 return h , s , v
831838
832- def get_color (self , color_format : str = 'rgb' ) -> (float , float , float ):
839+ def get_color (self , color_format : str = 'rgb' ) -> (float | None , float | None , float | None ):
833840 """
834841 Returns the normalized color readout of the color sensor
835842 :param color_format: rgb or hsv only
@@ -888,7 +895,7 @@ def hsv2label(h, s, v) -> str:
888895 label = 'BLUE'
889896 elif 260 <= h < 280 :
890897 label = 'VIOLET'
891- else : # h<20 or h>=280 is more problematic
898+ else : # h<20 or h>=280 is more problematic
892899 if v < 0.5 and s < 0.45 :
893900 label = 'BROWN'
894901 else :
@@ -900,31 +907,28 @@ def hsv2label(h, s, v) -> str:
900907 label = 'BLACK'
901908 return label
902909
903- def get_distance (self , unit : str = 'cm' ) -> (float , float , float , float , float ):
910+ def get_distance (self , unit : str = 'cm' ) -> (float | None , float | None , float | None , float | None , float | None ):
904911 """
905912 Returns the distance readout of the TOF sensor
906913 :param unit: distance output unit
907914 :return: left_tof, center_left_tof, center_tof, center_right_tof, right_tof
908915 """
909916
910- if None in [self ._left_tof , self ._center_left_tof , self ._center_tof , self ._center_right_tof , self ._right_tof ]:
911- return None , None , None , None , None
912-
913917 return (convert_distance (self ._left_tof , 'mm' , unit ),
914918 convert_distance (self ._center_left_tof , 'mm' , unit ),
915919 convert_distance (self ._center_tof , 'mm' , unit ),
916920 convert_distance (self ._center_right_tof , 'mm' , unit ),
917921 convert_distance (self ._right_tof , 'mm' , unit ))
918922
919- def get_distance_top (self , unit : str = 'cm' ) -> float :
923+ def get_distance_top (self , unit : str = 'cm' ) -> float | None :
920924 """
921925 Returns the obstacle top distance readout
922926 :param unit:
923927 :return:
924928 """
925929 return convert_distance (self ._top_tof , 'mm' , unit )
926930
927- def get_distance_bottom (self , unit : str = 'cm' ) -> float :
931+ def get_distance_bottom (self , unit : str = 'cm' ) -> float | None :
928932 """
929933 Returns the obstacle bottom distance readout
930934 :param unit:
@@ -998,26 +1002,26 @@ def set_speed(self, velocity: float, unit: str = 'rpm'):
9981002 """
9991003
10001004 if unit == '%' :
1001- velocity = (velocity / 100 )* MOTOR_MAX_RPM
1005+ velocity = (velocity / 100 ) * MOTOR_MAX_RPM
10021006 else :
10031007 velocity = convert_rotational_speed (velocity , unit , 'rpm' )
10041008
10051009 self ._packeter .packetC2B1F (ord ('W' ), self ._label & 0xFF , ord ('V' ), velocity )
10061010 uart .write (self ._packeter .msg [0 :self ._packeter .msg_size ])
10071011
1008- def get_speed (self , unit : str = 'rpm' ) -> float :
1012+ def get_speed (self , unit : str = 'rpm' ) -> float | None :
10091013 """
10101014 Returns the current RPM speed of the wheel
10111015 :param unit: the unit of the output speed
10121016 :return:
10131017 """
10141018 if unit == '%' :
1015- speed = (self ._speed / MOTOR_MAX_RPM )* 100
1019+ speed = (self ._speed / MOTOR_MAX_RPM ) * 100 if self . _speed is not None else None
10161020 else :
10171021 speed = convert_rotational_speed (self ._speed , 'rpm' , unit )
10181022 return speed
10191023
1020- def get_position (self , unit : str = 'deg' ) -> float :
1024+ def get_position (self , unit : str = 'deg' ) -> float | None :
10211025 """
10221026 Returns the wheel position (angle with respect to the reference)
10231027 :param unit: the unit of the output position
0 commit comments