1+ from .encoded_motor import EncodedMotor
2+ from .rangefinder import Rangefinder
3+ from .imu import IMU
4+ from .reflectance import Reflectance
5+ from .puppet import Puppet , VAR_TYPE_INT , VAR_TYPE_FLOAT , PERM_READ_ONLY
6+
7+ from machine import Timer , ADC , Pin
8+ from micropython import const
9+ import time
10+
11+
12+ class Dashboard :
13+
14+ _DEFAULT_DASHBOARD_INSTANCE = None
15+
16+ # Variable type constants
17+ VAR_TYPE_FLOAT = const (2 )
18+
19+ # Permission constants
20+ PERM_READ_ONLY = const (1 )
21+ PERM_WRITE_ONLY = const (2 )
22+
23+ # Backward compatibility constants
24+ YAW = const (0 )
25+ ROLL = const (1 )
26+ PTICH = const (2 )
27+ ACCX = const (3 )
28+ ACCY = const (4 )
29+ ACCZ = const (5 )
30+ ENCL = const (6 )
31+ ENCR = const (7 )
32+ ENC3 = const (8 )
33+ ENC4 = const (9 )
34+ CURRR = const (10 )
35+ CURRL = const (11 )
36+ CURR3 = const (12 )
37+ CURR4 = const (13 )
38+ DIST = const (14 )
39+ REFL = const (15 )
40+ REFR = const (16 )
41+ VOLTAGE = const (17 )
42+
43+ # Mapping from old index to XPP variable names
44+ _VAR_NAMES = {
45+ YAW : '$imu.yaw' ,
46+ ROLL : '$imu.roll' ,
47+ PTICH : '$imu.pitch' ,
48+ ACCX : '$imu.acc_x' ,
49+ ACCY : '$imu.acc_y' ,
50+ ACCZ : '$imu.acc_z' ,
51+ ENCL : '$encoder.left' ,
52+ ENCR : '$encoder.right' ,
53+ ENC3 : '$encoder.3' ,
54+ ENC4 : '$encoder.4' ,
55+ CURRL : '$current.left' ,
56+ CURRR : '$current.right' ,
57+ CURR3 : '$current.3' ,
58+ CURR4 : '$current.4' ,
59+ DIST : '$rangefinder.distance' ,
60+ REFL : '$reflectance.left' ,
61+ REFR : '$reflectance.right' ,
62+ VOLTAGE : '$voltage' ,
63+ }
64+
65+ @classmethod
66+ def get_default_dashboard (cls ):
67+ """
68+ Get the default XRP dashboard instance. This is a singleton, so only one instance of the dashboard sensor will ever exist.
69+ """
70+ if cls ._DEFAULT_DASHBOARD_INSTANCE is None :
71+ cls ._DEFAULT_DASHBOARD_INSTANCE = cls ()
72+ return cls ._DEFAULT_DASHBOARD_INSTANCE
73+
74+ def __init__ (self ):
75+ """
76+ Manages communication with dashboard data going to a remote computer via XPP protocol.
77+ """
78+ self .left_motor = EncodedMotor .get_default_encoded_motor (index = 1 )
79+ self .right_motor = EncodedMotor .get_default_encoded_motor (index = 2 )
80+ self .motor_three = EncodedMotor .get_default_encoded_motor (index = 3 )
81+ self .motor_four = EncodedMotor .get_default_encoded_motor (index = 4 )
82+ self .imu = IMU .get_default_imu ()
83+ self .rangefinder = Rangefinder .get_default_rangefinder ()
84+ self .reflectance = Reflectance .get_default_reflectance ()
85+ self .VoltageADC = ADC (Pin ('BOARD_VIN_MEASURE' ))
86+ self .CurrLADC = ADC (Pin ('ML_CUR' ))
87+ self .CurrRADC = ADC (Pin ('MR_CUR' ))
88+ self .Curr3ADC = ADC (Pin ('M3_CUR' ))
89+ self .Curr4ADC = ADC (Pin ('M4_CUR' ))
90+
91+ # Get XPP instance
92+ self ._puppet = Puppet .get_default_puppet ()
93+
94+ # Register all sensor variables
95+ self ._register_variables ()
96+
97+ # Create timer for periodic updates
98+ self .update_timer = Timer (- 1 )
99+ self ._update_rate = 3 # Default 3 Hz
100+
101+ def _register_variables (self ):
102+ """
103+ Register all sensor variables with XPP.
104+ """
105+ # IMU variables (float)
106+ for var_name in ['$imu.yaw' , '$imu.roll' , '$imu.pitch' ,
107+ '$imu.acc_x' , '$imu.acc_y' , '$imu.acc_z' ]:
108+ self ._puppet .define_variable (var_name , VAR_TYPE_FLOAT , PERM_READ_ONLY )
109+
110+ # Encoder variables (int)
111+ for var_name in ['$encoder.left' , '$encoder.right' , '$encoder.3' , '$encoder.4' ]:
112+ self ._puppet .define_variable (var_name , VAR_TYPE_INT , PERM_READ_ONLY )
113+
114+ # Current sensor variables (int)
115+ for var_name in ['$current.left' , '$current.right' , '$current.3' , '$current.4' ]:
116+ self ._puppet .define_variable (var_name , VAR_TYPE_INT , PERM_READ_ONLY )
117+
118+ # Other sensor variables (float)
119+ for var_name in ['$rangefinder.distance' , '$reflectance.left' ,
120+ '$reflectance.right' , '$voltage' ]:
121+ self ._puppet .define_variable (var_name , VAR_TYPE_FLOAT , PERM_READ_ONLY )
122+
123+ def sendIntValue (self , index , value ):
124+ """
125+ Send an integer value (backward compatibility method).
126+ Now uses XPP protocol.
127+
128+ :param index: Variable index constant
129+ :type index: int
130+ :param value: Integer value to send
131+ :type value: int
132+ """
133+ if index not in self ._VAR_NAMES :
134+ return
135+
136+ var_name = self ._VAR_NAMES [index ]
137+ try :
138+ self ._puppet .set_variable (var_name , value )
139+ except :
140+ pass # Variable might not be registered yet
141+
142+ def sendFloatValue (self , index , value ):
143+ """
144+ Send a float value (backward compatibility method).
145+ Now uses XPP protocol.
146+
147+ :param index: Variable index constant
148+ :type index: int
149+ :param value: Float value to send
150+ :type value: float
151+ """
152+ if index not in self ._VAR_NAMES :
153+ return
154+
155+ var_name = self ._VAR_NAMES [index ]
156+ try :
157+ self ._puppet .set_variable (var_name , value )
158+ except :
159+ pass # Variable might not be registered yet
160+
161+ def _dashboard_update (self ):
162+ """
163+ Update all sensor variables with current readings.
164+ """
165+ # IMU data
166+ self ._puppet .set_variable ('$imu.yaw' , self .imu .get_yaw ())
167+ self ._puppet .set_variable ('$imu.roll' , self .imu .get_roll ())
168+ self ._puppet .set_variable ('$imu.pitch' , self .imu .get_pitch ())
169+ self ._puppet .set_variable ('$imu.acc_x' , self .imu .get_acc_x ())
170+ self ._puppet .set_variable ('$imu.acc_y' , self .imu .get_acc_y ())
171+ self ._puppet .set_variable ('$imu.acc_z' , self .imu .get_acc_z ())
172+
173+ # Encoder data
174+ self ._puppet .set_variable ('$encoder.left' , self .left_motor .get_position_counts ())
175+ self ._puppet .set_variable ('$encoder.right' , self .right_motor .get_position_counts ())
176+ self ._puppet .set_variable ('$encoder.3' , self .motor_three .get_position_counts ())
177+ self ._puppet .set_variable ('$encoder.4' , self .motor_four .get_position_counts ())
178+
179+ # Current sensor data
180+ self ._puppet .set_variable ('$current.left' , self .CurrLADC .read_u16 ())
181+ self ._puppet .set_variable ('$current.right' , self .CurrRADC .read_u16 ())
182+ self ._puppet .set_variable ('$current.3' , self .Curr3ADC .read_u16 ())
183+ self ._puppet .set_variable ('$current.4' , self .Curr4ADC .read_u16 ())
184+
185+ # Other sensors
186+ self ._puppet .set_variable ('$rangefinder.distance' , self .rangefinder .distance ())
187+ self ._puppet .set_variable ('$reflectance.left' , self .reflectance .get_left ())
188+ self ._puppet .set_variable ('$reflectance.right' , self .reflectance .get_right ())
189+
190+ # Voltage
191+ voltage = self .VoltageADC .read_u16 () / (1024 * 64 / 14 )
192+ self ._puppet .set_variable ('$voltage' , voltage )
193+
194+ def start (self , rate_hz = 3 ):
195+ """
196+ Start sending dashboard packets to the remote computer at the specified rate.
197+
198+ :param rate_hz: Update rate in Hz (default: 3)
199+ :type rate_hz: int
200+ """
201+ self ._update_rate = rate_hz
202+
203+ # Subscribe all variables at the specified rate
204+ for var_name in self ._VAR_NAMES .values ():
205+ try :
206+ self ._puppet .subscribe_variable (var_name , rate_hz )
207+ except :
208+ pass # Variable might not be registered yet
209+
210+ # Also use timer for backward compatibility
211+ period_ms = int (1000 / rate_hz )
212+ self .update_timer .init (period = period_ms , mode = Timer .PERIODIC ,
213+ callback = lambda t : self ._dashboard_update ())
214+
215+ def stop (self ):
216+ """
217+ Stop sending dashboard data packets.
218+ """
219+ # Unsubscribe from all variables
220+ for var_name in self ._VAR_NAMES .values ():
221+ try :
222+ self ._puppet .subscribe_variable (var_name , 0 )
223+ except :
224+ pass
225+
226+ # Stop timer
227+ self .update_timer .deinit ()
228+
229+ def set_value (self , name , value , rate_hz = 3 ):
230+ """
231+ Define a variable and subscribe to it at the specified rate.
232+
233+ :param name: The variable name
234+ :type name: str
235+ :param value: The value to set
236+ :type value: float
237+ :param rate_hz: The update rate in Hz (default: 3)
238+ :type rate_hz: int
239+ """
240+ self ._puppet .define_variable (name , VAR_TYPE_FLOAT , PERM_READ_ONLY )
241+ try :
242+ self ._puppet .subscribe_variable (name , rate_hz )
243+ except :
244+ pass
245+ self ._puppet .set_variable (name , value )
246+
247+ def get_value (self , name ):
248+ """
249+ Get the value of a variable.
250+
251+ :param name: The variable name
252+ :type name: str
253+ """
254+ self ._puppet .define_variable (name , VAR_TYPE_FLOAT , PERM_WRITE_ONLY )
255+ return self ._puppet .get_variable (name )
0 commit comments