1+ from pybricks .geometry import Axis
2+ from pybricks .iodevices import PUPDevice
3+ from pybricks .pupdevices import *
4+ from pybricks .parameters import Port , Button , Color
5+ from pybricks .tools import wait , StopWatch
6+ from uerrno import ENODEV , ETIMEDOUT
7+
8+ # 1: Determine the type of hub
9+ # -------------------------------------------------------------------
10+ # For Hubs with IMU: how is it mounted?
11+ # https://docs.pybricks.com/en/latest/geometry.html#fig-imuexamples
12+ def HubInit (mounted_top = Axis .Z , mounted_front = Axis .X ):
13+ # Returns (str hub_object, dict hub_info)
14+ hub = None
15+ hub_info = dict ()
16+ try :
17+ from pybricks .hubs import MoveHub
18+ hub = MoveHub ()
19+ hub_info .update (hub_type = "MoveHub" )
20+ except ImportError :
21+ pass
22+ try :
23+ from pybricks .hubs import CityHub
24+ hub = CityHub ()
25+ hub_info .update (hub_type = "CityHub" )
26+ except ImportError :
27+ pass
28+ try :
29+ from pybricks .hubs import TechnicHub
30+ hub = TechnicHub (top_side = mounted_top , front_side = mounted_front )
31+ hub_info .update (hub_type = "TechnicHub" )
32+ except ImportError :
33+ pass
34+ try : # InventorHub is the same as PrimeHub, so treat the same.
35+ from pybricks .hubs import PrimeHub
36+ hub = PrimeHub (top_side = mounted_top , front_side = mounted_front )
37+ hub_info .update (hub_type = "PrimeHub" )
38+ except ImportError :
39+ pass
40+ try :
41+ from pybricks .hubs import EssentialHub
42+ hub = EssentialHub (top_side = mounted_top , front_side = mounted_front )
43+ hub_info .update (hub_type = "EssentialHub" )
44+ except ImportError :
45+ pass
46+
47+ if hub is None :
48+ raise Exception ("No valid Hub found" )
49+
50+ print ("Hub:\n Name:\t " , hub .system .name (),":" ,hub_info ['hub_type' ])
51+ print (" Reset reason: " , hub .system .reset_reason ())
52+ print (" voltage: " , hub .battery .voltage (), "mV" )
53+ print (" current: " , hub .battery .current (), "mA" )
54+
55+ # Check for IMU and Matrix dislay:
56+ try : # to init IMU
57+ from pybricks .parameters import Side
58+ hub_info .update (init_position = hub .imu .up ())
59+ print (" facing: " , hub_info ['init_position' ])
60+ hub_info .update (has_imu = True )
61+ except AttributeError :
62+ hub_info .update (has_imu = False )
63+ pass
64+ try : # to init Matrix
65+ from pybricks .parameters import Icon
66+ hub .display .icon (Icon .UP / 2 )
67+ hub .display .orientation (up_side )
68+ print (" with display matrix." )
69+ hub_info .update (has_matrix = True )
70+ except ImportError or AttributeError :
71+ hub_info .update (has_matrix = False )
72+ pass
73+
74+ return (hub , hub_info )
75+
76+ # 2: Diagnose connected devices
77+ # -------------------------------------------------------------------
78+ # Dictionary of device identifiers along with their name.
79+ # Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids
80+ # for retired/internal
81+ device_names = {
82+ 1 : "Wedo 2.0 Medium Motor" , #DCMotor, analog ID
83+ 2 : "PUP Train Motor" , #DCMotor, analog ID
84+ 8 : "PUP Light" , #Light, analog ID
85+ 34 : "Wedo 2.0 Tilt Sensor" ,
86+ 35 : "Wedo 2.0 Infrared Sensor" , # aka WeDo 2.0 Motion Sensor
87+ 37 : "BOOST Color Distance Sensor" ,
88+ 38 : "BOOST Interactive Motor" ,
89+ 46 : "Technic Large Motor" ,
90+ 47 : "Technic Extra Large Motor" ,
91+ 48 : "SPIKE Medium Angular Motor" ,
92+ 49 : "SPIKE Large Angular Motor" ,
93+ 61 : "SPIKE Color Sensor" ,
94+ 62 : "SPIKE Ultrasonic Sensor" ,
95+ 63 : "SPIKE Force Sensor" ,
96+ 64 : "SPIKE 3x3 Color Light Matrix" ,
97+ 65 : "SPIKE Small Angular Motor" ,
98+ 75 : "Technic Medium Angular Motor" ,
99+ 76 : "Technic Large Angular Motor" ,
100+ }
101+
102+ def ConnectToDevice (port ):
103+ # Returns a device dict()
104+ device = {'type' :None , 'id' :None , 'name' :None , 'object' :None }
105+
106+ try : # to get the device, if it is attached.
107+ pupdev = PUPDevice (port )
108+ except OSError as ex :
109+ if ex .args [0 ] == ENODEV :
110+ # No device found on this port.
111+ return device
112+ else :
113+ raise
114+ # Get the device id
115+ temp_info = pupdev .info ()
116+ device ['id' ] = temp_info ["id" ]
117+ try : # to look up the name.
118+ device ['name' ] = device_names [device ['id' ]]
119+ except KeyError :
120+ device ['name' ] = "Unknown"
121+ #print(port, ":", "Unknown device with ID", xid)
122+ if len (temp_info ) > 1 :
123+ print (temp_info )
124+
125+ # Initiate object and type
126+ xid = device ['id' ]
127+ if xid in (1 ,2 ):
128+ try :
129+ device ['object' ] = DCMotor (port )
130+ device ['type' ] = "DCMotor"
131+ except OSError as err :
132+ print ("DCMotor could not be initiated: " , err )
133+ device ['type' ] = "Custom"
134+ pass
135+ elif xid in (46 ,47 ,48 ,49 ,75 ,76 ):
136+ try :
137+ device ['object' ] = Motor (port , positive_direction = Direction .CLOCKWISE , gears = None )
138+ device ['type' ] = "Motor"
139+ except :
140+ print ("Motor could not be initiated: " , err )
141+ device ['type' ] = "Custom"
142+ pass
143+ elif xid is 8 :
144+ try :
145+ device ['object' ] = Light (port )
146+ device ['object' ].on (brightness = 50 )
147+ device ['type' ] = "Light"
148+ except :
149+ print ("Light could not be initiated: " , err )
150+ device ['type' ] = "Custom"
151+ pass
152+ elif xid is None : #ToDo
153+ try :
154+ device ['object' ] = ColorLightMatrix (port )
155+ device ['type' ] = "Matrix3x3"
156+ except :
157+ print ("Matrix could not be initiated: " , err )
158+ device ['type' ] = "Custom"
159+ pass
160+ elif xid in (34 ,35 ,37 ,61 ,62 ,63 ):
161+ device ['type' ] = "Sensor"
162+ if xid is 34 :
163+ try :
164+ device ['object' ] = TiltSensor (port )
165+ device ['type' ] += "/Tilt"
166+ except :
167+ print ("TiltSensor could not be initiated: " , err )
168+ device ['type' ] += "/Custom"
169+ pass
170+ elif xid is 35 :
171+ try :
172+ device ['object' ] = InfraredSensor (port )
173+ device ['type' ] += "/IR/Distance"
174+ except :
175+ print ("InfraredSensor could not be initiated: " , err )
176+ device ['type' ] += "/Custom"
177+ pass
178+ elif xid is 37 :
179+ try :
180+ device ['object' ] = ColorDistanceSensor (port )
181+ device ['type' ] += "/Distance/Color/Light"
182+ except :
183+ print ("ColorDistanceSensor could not be initiated: " , err )
184+ device ['type' ] += "/Custom"
185+ pass
186+ elif xid is 61 :
187+ try :
188+ device ['object' ] = ColorSensor (port )
189+ device ['type' ] += "/Color/Light"
190+ except :
191+ print ("ColorSensor could not be initiated: " , err )
192+ device ['type' ] += "/Custom"
193+ pass
194+ elif xid is 62 :
195+ try :
196+ device ['object' ] = UltrasonicSensor (port )
197+ device ['type' ] += "/Distance/Light"
198+ except :
199+ print ("UltrasonicSensor could not be initiated: " , err )
200+ device ['type' ] += "/Custom"
201+ pass
202+ elif xid is 63 :
203+ try :
204+ device ['object' ] = ForceSensor (port )
205+ device ['type' ] += "/Force/Distance/Press"
206+ except :
207+ print ("ForceSensor could not be initiated: " , err )
208+ device ['type' ] += "/Custom"
209+ pass
210+ else :
211+ pass
212+
213+ return device
214+
215+ # end of ConnectToDevice(port)
216+ # -------------------------------------------------------------------
217+
218+ # Make a list of known ports.
219+ ports = [Port .A , Port .B ]
220+ try : # to add more ports, on hubs that support it.
221+ ports .append (Port .C )
222+ ports .append (Port .D )
223+ except AttributeError :
224+ pass
225+ try : # to add more ports, on hubs that support it.
226+ ports .append (Port .E )
227+ ports .append (Port .F )
228+ except AttributeError :
229+ pass
230+
231+ # 3: Remote buttons check and remote init
232+ # -------------------------------------------------------------------
233+ remote = None
234+ ch1_val = 0 # +/-100%, scale if needed
235+ ch2_val = 0 # +100%, scale if needed
236+
237+ def ConnectRemote ():
238+ global remote
239+ try :
240+ remote = Remote (name = None ,timeout = 10000 )
241+ print ("Remote: " + remote .name ())
242+ #remote.name("Remote of <user>")
243+ except OSError as ex :
244+ if ex .errno == ETIMEDOUT :
245+ print ("No Remote found." )
246+
247+ def ServiceRemote ():
248+ global remote
249+
250+ if remote is None :
251+ return (ch1_val ,ch2_val )
252+ try :
253+ pressed = remote .buttons .pressed ()
254+ except OSError as ex :
255+ if not ex .errno == ENODEV :
256+ raise
257+ print ("Lost remote" )
258+ remote = None # empty handle
259+ return (ch1_val ,ch2_val )
260+ if len (pressed ) is 0 :
261+ return (ch1_val ,ch2_val )
262+ #print(pressed)
263+
264+ ch1_val_new = ch1_val
265+ ch2_val_new = ch2_val
266+
267+ # Remote channel 1:
268+ if Button .LEFT_PLUS in pressed :
269+ ch1_val_new += 10
270+ if ch1_val_new > 100 :
271+ ch1_val_new = 100
272+ if Button .LEFT_MINUS in pressed :
273+ ch1_val_new -= 10
274+ if ch1_val_new < - 100 :
275+ ch1_val_new = - 100
276+ if Button .LEFT in pressed :
277+ ch1_val_new = 0
278+ # Remote channel 2:
279+ if Button .RIGHT_PLUS in pressed :
280+ ch2_val_new += 10
281+ if ch2_val_new > 100 :
282+ ch2_val_new = 100
283+ if Button .RIGHT_MINUS in pressed :
284+ ch2_val_new -= 10
285+ if ch2_val_new < 0 :
286+ ch2_val_new = 0
287+ if Button .RIGHT in pressed :
288+ ch2_val_new = 0
289+
290+ return (ch1_val_new ,ch2_val_new )
291+
292+
293+ # 4: Main / Monitor changes
294+ # -------------------------------------------------------------------
295+ DIAGNOSTICS_PERIOD = 5000 # 5s
296+ sys_tick = StopWatch ()
297+ (hub ,hub_info ) = HubInit ()
298+ print (hub_info )
299+ pressed = ()
300+
301+ # Readings
302+ tilt = None
303+ distance = None
304+ color = None
305+ force = None
306+
307+ # Search through all available ports.
308+ devices = []
309+ for port in ports :
310+ dev = ConnectToDevice (port )
311+ if dev ['type' ] is None :
312+ print (port , ": ---" )
313+ else :
314+ print (port ,dev ['id' ],":" ,dev ['name' ],":" ,dev ['type' ])
315+ devices .append (dev )
316+
317+ ConnectRemote ()
318+
319+ while True :
320+ wait (100 )
321+ try :
322+ pressed = hub .buttons .pressed ()
323+ except AttributeError :
324+ pass
325+ try :
326+ pressed = hub .button .pressed ()
327+ except AttributeError :
328+ pass
329+
330+ if sys_tick .time () % DIAGNOSTICS_PERIOD :
331+ print ("Hub voltage: " , hub .battery .voltage (), "mV" )
332+ print ("Hub current: " , hub .battery .current (), "mA" )
333+ for device in devices :
334+ if "Tilt" in device ['type' ]:
335+ tilt = device ['object' ].tilt ()
336+ if "Distance" in device ['type' ]:
337+ distance = device ['object' ].distance ()
338+ if "Color" in device ['type' ]:
339+ color = device ['object' ].color ()
340+ if "Force" in device ['type' ]:
341+ force = device ['object' ].force ()
342+ print ("T:" ,tilt ,"D:" ,distance ,"C:" ,color ,"F:" ,force )
343+
344+ # do not set values blindly to not interfere with other code:
345+ (ch1_val_new ,ch2_val_new ) = ServiceRemote ()
346+ if ch1_val_new is not ch1_val :
347+ ch1_val = ch1_val_new
348+ print ("Channel 1 changed:" ,ch1_val )
349+ if ch2_val_new is not ch2_val :
350+ ch2_val = ch2_val_new
351+ print ("Channel 2 changed:" ,ch2_val )
0 commit comments