@@ -104,14 +104,14 @@ def convert(b1, b2):
104104class SpaceMouse (Device ):
105105 """
106106 A minimalistic driver class for SpaceMouse with HID library.
107-
108- Note: Use hid.enumerate() to view all USB human interface devices (HID).
109- Make sure SpaceMouse is detected before running the script.
110- You can look up its vendor/product id from this method.
107+ Auto-detects 3Dconnexion devices if default vendor/product IDs fail.
111108
112109 Args:
113110 env (RobotEnv): The environment which contains the robot(s) to control
114111 using this device.
112+ vendor_id (int): SpaceMouse vendor ID (will auto-detect if default fails)
113+ product_id (int): SpaceMouse product ID (will auto-detect if default fails)
114+ device_path (bytes): Specific device path (e.g., b'1-2:1.0') for reliable identification
115115 pos_sensitivity (float): Magnitude of input position command scaling
116116 rot_sensitivity (float): Magnitude of scale input rotation commands scaling
117117 """
@@ -121,29 +121,39 @@ def __init__(
121121 env ,
122122 vendor_id = macros .SPACEMOUSE_VENDOR_ID ,
123123 product_id = macros .SPACEMOUSE_PRODUCT_ID ,
124+ device_path = None ,
124125 pos_sensitivity = 1.0 ,
125126 rot_sensitivity = 1.0 ,
126127 ):
127128 super ().__init__ (env )
128129
129- print ("Opening SpaceMouse device" )
130+ ROBOSUITE_DEFAULT_LOGGER . info ("Opening SpaceMouse device" )
130131 self .vendor_id = vendor_id
131132 self .product_id = product_id
132133 self .device = hid .device ()
133- try :
134- self .device .open (self .vendor_id , self .product_id ) # SpaceMouse
135- except OSError as e :
136- ROBOSUITE_DEFAULT_LOGGER .warning (
137- "Failed to open SpaceMouse device"
138- "Consider killing other processes that may be using the device such as 3DconnexionHelper (killall 3DconnexionHelper)"
139- )
140- raise
134+
135+ if device_path :
136+ try :
137+ self .device .open_path (device_path )
138+ ROBOSUITE_DEFAULT_LOGGER .info (f"Connected using path: { device_path } " )
139+ except OSError :
140+ ROBOSUITE_DEFAULT_LOGGER .warning (f"Failed to open device at path: { device_path } " )
141+ self ._auto_detect_device ()
142+ else :
143+ try :
144+ self .device .open (vendor_id , product_id )
145+ ROBOSUITE_DEFAULT_LOGGER .info (f"Connected using default IDs: { vendor_id :04x} :{ product_id :04x} " )
146+ except OSError :
147+ ROBOSUITE_DEFAULT_LOGGER .warning (
148+ f"Failed to open device with provided IDs: { vendor_id :04x} :{ product_id :04x} "
149+ )
150+ self ._auto_detect_device ()
141151
142152 self .pos_sensitivity = pos_sensitivity
143153 self .rot_sensitivity = rot_sensitivity
144154
145- print ("Manufacturer: %s" % self .device .get_manufacturer_string ())
146- print ("Product: %s" % self .device .get_product_string ())
155+ ROBOSUITE_DEFAULT_LOGGER . info ("Manufacturer: %s" % self .device .get_manufacturer_string ())
156+ ROBOSUITE_DEFAULT_LOGGER . info ("Product: %s" % self .device .get_product_string ())
147157
148158 # 6-DOF variables
149159 self .x , self .y , self .z = 0 , 0 , 0
@@ -169,6 +179,18 @@ def __init__(
169179 # start listening
170180 self .listener .start ()
171181
182+ def _auto_detect_device (self ):
183+ """Auto-detect and connect to first 3Dconnexion device."""
184+ devices = [d for d in hid .enumerate () if d .get ("manufacturer_string" ) == "3Dconnexion" ]
185+ if not devices :
186+ raise OSError ("No 3Dconnexion devices found" )
187+
188+ selected = devices [0 ]
189+ self .device .open_path (selected ["path" ])
190+ self .vendor_id = selected ["vendor_id" ]
191+ self .product_id = selected ["product_id" ]
192+ ROBOSUITE_DEFAULT_LOGGER .info (f"Auto-detected: { selected ['product_string' ]} with path { selected ['path' ]} " )
193+
172194 @staticmethod
173195 def _display_controls ():
174196 """
@@ -191,6 +213,8 @@ def print_command(char, info):
191213 print_command ("s" , "switch active arm (if multi-armed robot)" )
192214 print_command ("=" , "switch active robot (if multi-robot environment)" )
193215 print ("" )
216+ print ("NOTE: Auto-detects 3Dconnexion devices. Use device_path for specific device." )
217+ print ("" )
194218
195219 def _reset_internal_state (self ):
196220 """
@@ -375,5 +399,5 @@ def _postprocess_device_outputs(self, dpos, drotation):
375399
376400 space_mouse = SpaceMouse ()
377401 for i in range (100 ):
378- print ( space_mouse .control , space_mouse .control_gripper )
402+ ROBOSUITE_DEFAULT_LOGGER . info ( f"Control: { space_mouse .control } , Gripper: { space_mouse .control_gripper } " )
379403 time .sleep (0.02 )
0 commit comments