4040from rclpy .qos import QoSProfile
4141from sensor_msgs .msg import Imu , MagneticField , Temperature
4242from std_msgs .msg import String
43+ from example_interfaces .srv import Trigger
4344
4445
4546class SensorService :
@@ -59,6 +60,7 @@ def __init__(self, node: Node, connector: Connector, param: NodeParameters):
5960 self .pub_mag = node .create_publisher (MagneticField , prefix + 'mag' , QoSProf )
6061 self .pub_temp = node .create_publisher (Temperature , prefix + 'temp' , QoSProf )
6162 self .pub_calib_status = node .create_publisher (String , prefix + 'calib_status' , QoSProf )
63+ self .srv = self .node .create_service (Trigger , prefix + 'calibration_request' , self .calibration_request_callback )
6264
6365 def configure (self ):
6466 """Configure the IMU sensor hardware."""
@@ -104,21 +106,26 @@ def configure(self):
104106 'P7' : bytes (b'\x24 \x05 ' )
105107 }
106108 if not (self .con .transmit (registers .BNO055_AXIS_MAP_CONFIG_ADDR , 2 ,
107- mount_positions [self .param .placement_axis_remap .value ])):
109+ mount_positions [self .param .placement_axis_remap .value ])):
108110 self .node .get_logger ().warn ('Unable to set sensor placement configuration.' )
109111
110112 # Show the current sensor offsets
111- print ('Current sensor offsets:' )
112- self .get_calib_offsets ()
113- if ( self .param .set_offsets ) :
113+ self . node . get_logger (). info ('Current sensor offsets:' )
114+ self .print_calib_data ()
115+ if self .param .set_offsets . value :
114116 configured_offsets = \
115117 self .set_calib_offsets (
116118 self .param .offset_acc ,
117119 self .param .offset_mag ,
118- self .param .offset_gyr )
119- if (configured_offsets ):
120- print ('Successfully configured sensor offsets to:' )
121- self .get_calib_offsets ()
120+ self .param .offset_gyr ,
121+ self .param .radius_mag ,
122+ self .param .radius_acc )
123+ if configured_offsets :
124+ self .node .get_logger ().info ('Successfully configured sensor offsets to:' )
125+ self .print_calib_data ()
126+ else :
127+ self .node .get_logger ().warn ('setting offsets failed' )
128+
122129
123130 # Set Device to NDOF mode
124131 # data fusion for gyroscope, acceleration sensor and magnetometer enabled
@@ -139,15 +146,14 @@ def get_sensor_data(self):
139146 # read from sensor
140147 buf = self .con .receive (registers .BNO055_ACCEL_DATA_X_LSB_ADDR , 45 )
141148 # Publish raw data
142- # TODO: convert rcl Clock time to ros time?
143- # imu_raw_msg.header.stamp = node.get_clock().now()
149+ imu_raw_msg .header .stamp = self .node .get_clock ().now ().to_msg ()
144150 imu_raw_msg .header .frame_id = self .param .frame_id .value
145151 # TODO: do headers need sequence counters now?
146152 # imu_raw_msg.header.seq = seq
147153
148154 # TODO: make this an option to publish?
149155 imu_raw_msg .orientation_covariance = [
150- self .param .variance_orientation .value [0 ], 0.0 , 0.0 ,
156+ self .param .variance_orientation .value [0 ], 0.0 , 0.0 ,
151157 0.0 , self .param .variance_orientation .value [1 ], 0.0 ,
152158 0.0 , 0.0 , self .param .variance_orientation .value [2 ]
153159 ]
@@ -179,7 +185,7 @@ def get_sensor_data(self):
179185
180186 # TODO: make this an option to publish?
181187 # Publish filtered data
182- # imu_msg.header.stamp = node.get_clock().now()
188+ imu_msg .header .stamp = self . node .get_clock ().now (). to_msg ()
183189 imu_msg .header .frame_id = self .param .frame_id .value
184190
185191 q = Quaternion ()
@@ -190,7 +196,7 @@ def get_sensor_data(self):
190196 q .z = self .unpackBytesToFloat (buf [30 ], buf [31 ])
191197 # TODO(flynneva): replace with standard normalize() function
192198 # normalize
193- norm = sqrt (q .x * q .x + q .y * q .y + q .z * q .z + q .w * q .w )
199+ norm = sqrt (q .x * q .x + q .y * q .y + q .z * q .z + q .w * q .w )
194200 imu_msg .orientation .x = q .x / norm
195201 imu_msg .orientation .y = q .y / norm
196202 imu_msg .orientation .z = q .z / norm
@@ -203,7 +209,7 @@ def get_sensor_data(self):
203209 imu_msg .linear_acceleration .y = \
204210 self .unpackBytesToFloat (buf [34 ], buf [35 ]) / self .param .acc_factor .value
205211 imu_msg .linear_acceleration .z = \
206- self .unpackBytesToFloat ( buf [36 ], buf [37 ]) / self .param .acc_factor .value
212+ self .unpackBytesToFloat (buf [36 ], buf [37 ]) / self .param .acc_factor .value
207213 imu_msg .linear_acceleration_covariance = imu_raw_msg .linear_acceleration_covariance
208214 imu_msg .angular_velocity .x = \
209215 self .unpackBytesToFloat (buf [12 ], buf [13 ]) / self .param .gyr_factor .value
@@ -215,7 +221,7 @@ def get_sensor_data(self):
215221 self .pub_imu .publish (imu_msg )
216222
217223 # Publish magnetometer data
218- # mag_msg.header.stamp = node.get_clock().now()
224+ mag_msg .header .stamp = self . node .get_clock ().now (). to_msg ()
219225 mag_msg .header .frame_id = self .param .frame_id .value
220226 # mag_msg.header.seq = seq
221227 mag_msg .magnetic_field .x = \
@@ -232,7 +238,7 @@ def get_sensor_data(self):
232238 self .pub_mag .publish (mag_msg )
233239
234240 # Publish temperature
235- # temp_msg.header.stamp = node.get_clock().now()
241+ temp_msg .header .stamp = self . node .get_clock ().now (). to_msg ()
236242 temp_msg .header .frame_id = self .param .frame_id .value
237243 # temp_msg.header.seq = seq
238244 temp_msg .temperature = float (buf [44 ])
@@ -258,8 +264,9 @@ def get_calib_status(self):
258264 # Publish via ROS topic:
259265 self .pub_calib_status .publish (calib_status_str )
260266
261- def get_calib_offsets (self ):
262- """Read all calibration offsets and print to screen."""
267+ def get_calib_data (self ):
268+ """Read all calibration data."""
269+
263270 accel_offset_read = self .con .receive (registers .ACCEL_OFFSET_X_LSB_ADDR , 6 )
264271 accel_offset_read_x = (accel_offset_read [1 ] << 8 ) | accel_offset_read [
265272 0 ] # Combine MSB and LSB registers into one decimal
@@ -268,6 +275,9 @@ def get_calib_offsets(self):
268275 accel_offset_read_z = (accel_offset_read [5 ] << 8 ) | accel_offset_read [
269276 4 ] # Combine MSB and LSB registers into one decimal
270277
278+ accel_radius_read = self .con .receive (registers .ACCEL_RADIUS_LSB_ADDR , 2 )
279+ accel_radius_read_value = (accel_radius_read [1 ] << 8 ) | accel_radius_read [0 ]
280+
271281 mag_offset_read = self .con .receive (registers .MAG_OFFSET_X_LSB_ADDR , 6 )
272282 mag_offset_read_x = (mag_offset_read [1 ] << 8 ) | mag_offset_read [
273283 0 ] # Combine MSB and LSB registers into one decimal
@@ -276,6 +286,9 @@ def get_calib_offsets(self):
276286 mag_offset_read_z = (mag_offset_read [5 ] << 8 ) | mag_offset_read [
277287 4 ] # Combine MSB and LSB registers into one decimal
278288
289+ mag_radius_read = self .con .receive (registers .MAG_RADIUS_LSB_ADDR , 2 )
290+ mag_radius_read_value = (mag_radius_read [1 ] << 8 ) | mag_radius_read [0 ]
291+
279292 gyro_offset_read = self .con .receive (registers .GYRO_OFFSET_X_LSB_ADDR , 6 )
280293 gyro_offset_read_x = (gyro_offset_read [1 ] << 8 ) | gyro_offset_read [
281294 0 ] # Combine MSB and LSB registers into one decimal
@@ -284,31 +297,54 @@ def get_calib_offsets(self):
284297 gyro_offset_read_z = (gyro_offset_read [5 ] << 8 ) | gyro_offset_read [
285298 4 ] # Combine MSB and LSB registers into one decimal
286299
300+ calib_data = {'accel_offset' : {'x' : accel_offset_read_x , 'y' : accel_offset_read_y , 'z' : accel_offset_read_z }, 'accel_radius' : accel_radius_read_value ,
301+ 'mag_offset' : {'x' : mag_offset_read_x , 'y' : mag_offset_read_y , 'z' : mag_offset_read_z }, 'mag_radius' : mag_radius_read_value ,
302+ 'gyro_offset' : {'x' : gyro_offset_read_x , 'y' : gyro_offset_read_y , 'z' : gyro_offset_read_z }}
303+
304+ return calib_data
305+
306+ def print_calib_data (self ):
307+ """Read all calibration data and print to screen."""
308+ calib_data = self .get_calib_data ()
287309 self .node .get_logger ().info (
288310 '\t Accel offsets (x y z): %d %d %d' % (
289- accel_offset_read_x ,
290- accel_offset_read_y ,
291- accel_offset_read_z ))
311+ calib_data ['accel_offset' ]['x' ],
312+ calib_data ['accel_offset' ]['y' ],
313+ calib_data ['accel_offset' ]['z' ]))
314+
315+ self .node .get_logger ().info (
316+ '\t Accel radius: %d' % (
317+ calib_data ['accel_radius' ],
318+ )
319+ )
292320
293321 self .node .get_logger ().info (
294322 '\t Mag offsets (x y z): %d %d %d' % (
295- mag_offset_read_x ,
296- mag_offset_read_y ,
297- mag_offset_read_z ))
323+ calib_data ['mag_offset' ]['x' ],
324+ calib_data ['mag_offset' ]['y' ],
325+ calib_data ['mag_offset' ]['z' ]))
326+
327+ self .node .get_logger ().info (
328+ '\t Mag radius: %d' % (
329+ calib_data ['mag_radius' ],
330+ )
331+ )
298332
299333 self .node .get_logger ().info (
300334 '\t Gyro offsets (x y z): %d %d %d' % (
301- gyro_offset_read_x ,
302- gyro_offset_read_y ,
303- gyro_offset_read_z ))
335+ calib_data [ 'gyro_offset' ][ 'x' ] ,
336+ calib_data [ 'gyro_offset' ][ 'y' ] ,
337+ calib_data [ 'gyro_offset' ][ 'z' ] ))
304338
305- def set_calib_offsets (self , acc_offset , mag_offset , gyr_offset ):
339+ def set_calib_offsets (self , acc_offset , mag_offset , gyr_offset , mag_radius , acc_radius ):
306340 """
307341 Write calibration data (define as 16 bit signed hex).
308342
309343 :param acc_offset:
310344 :param mag_offset:
311345 :param gyr_offset:
346+ :param mag_radius:
347+ :param acc_radius:
312348 """
313349 # Must switch to config mode to write out
314350 if not (self .con .transmit (registers .BNO055_OPR_MODE_ADDR , 1 , bytes ([registers .OPERATION_MODE_CONFIG ]))):
@@ -317,29 +353,47 @@ def set_calib_offsets(self, acc_offset, mag_offset, gyr_offset):
317353
318354 # Seems to only work when writing 1 register at a time
319355 try :
320- self .con .transmit (registers .ACCEL_OFFSET_X_LSB_ADDR , 1 , bytes ([acc_offset [0 ] & 0xFF ]))
321- self .con .transmit (registers .ACCEL_OFFSET_X_MSB_ADDR , 1 , bytes ([(acc_offset [0 ] >> 8 ) & 0xFF ]))
322- self .con .transmit (registers .ACCEL_OFFSET_Y_LSB_ADDR , 1 , bytes ([acc_offset [1 ] & 0xFF ]))
323- self .con .transmit (registers .ACCEL_OFFSET_Y_MSB_ADDR , 1 , bytes ([(acc_offset [1 ] >> 8 ) & 0xFF ]))
324- self .con .transmit (registers .ACCEL_OFFSET_Z_LSB_ADDR , 1 , bytes ([acc_offset [2 ] & 0xFF ]))
325- self .con .transmit (registers .ACCEL_OFFSET_Z_MSB_ADDR , 1 , bytes ([(acc_offset [2 ] >> 8 ) & 0xFF ]))
326-
327- self .con .transmit (registers .MAG_OFFSET_X_LSB_ADDR , 1 , bytes ([mag_offset [0 ] & 0xFF ]))
328- self .con .transmit (registers .MAG_OFFSET_X_MSB_ADDR , 1 , bytes ([(mag_offset [0 ] >> 8 ) & 0xFF ]))
329- self .con .transmit (registers .MAG_OFFSET_Y_LSB_ADDR , 1 , bytes ([mag_offset [1 ] & 0xFF ]))
330- self .con .transmit (registers .MAG_OFFSET_Y_MSB_ADDR , 1 , bytes ([(mag_offset [1 ] >> 8 ) & 0xFF ]))
331- self .con .transmit (registers .MAG_OFFSET_Z_LSB_ADDR , 1 , bytes ([mag_offset [2 ] & 0xFF ]))
332- self .con .transmit (registers .MAG_OFFSET_Z_MSB_ADDR , 1 , bytes ([(mag_offset [2 ] >> 8 ) & 0xFF ]))
333-
334- self .con .transmit (registers .GYRO_OFFSET_X_LSB_ADDR , 1 , bytes ([gyr_offset [0 ] & 0xFF ]))
335- self .con .transmit (registers .GYRO_OFFSET_X_MSB_ADDR , 1 , bytes ([(gyr_offset [0 ] >> 8 ) & 0xFF ]))
336- self .con .transmit (registers .GYRO_OFFSET_Y_LSB_ADDR , 1 , bytes ([gyr_offset [1 ] & 0xFF ]))
337- self .con .transmit (registers .GYRO_OFFSET_Y_MSB_ADDR , 1 , bytes ([(gyr_offset [1 ] >> 8 ) & 0xFF ]))
338- self .con .transmit (registers .GYRO_OFFSET_Z_LSB_ADDR , 1 , bytes ([gyr_offset [2 ] & 0xFF ]))
339- self .con .transmit (registers .GYRO_OFFSET_Z_MSB_ADDR , 1 , bytes ([(gyr_offset [2 ] >> 8 ) & 0xFF ]))
356+ self .con .transmit (registers .ACCEL_OFFSET_X_LSB_ADDR , 1 , bytes ([acc_offset .value [0 ] & 0xFF ]))
357+ self .con .transmit (registers .ACCEL_OFFSET_X_MSB_ADDR , 1 , bytes ([(acc_offset .value [0 ] >> 8 ) & 0xFF ]))
358+ self .con .transmit (registers .ACCEL_OFFSET_Y_LSB_ADDR , 1 , bytes ([acc_offset .value [1 ] & 0xFF ]))
359+ self .con .transmit (registers .ACCEL_OFFSET_Y_MSB_ADDR , 1 , bytes ([(acc_offset .value [1 ] >> 8 ) & 0xFF ]))
360+ self .con .transmit (registers .ACCEL_OFFSET_Z_LSB_ADDR , 1 , bytes ([acc_offset .value [2 ] & 0xFF ]))
361+ self .con .transmit (registers .ACCEL_OFFSET_Z_MSB_ADDR , 1 , bytes ([(acc_offset .value [2 ] >> 8 ) & 0xFF ]))
362+
363+ self .con .transmit (registers .ACCEL_RADIUS_LSB_ADDR , 1 , bytes ([acc_radius .value & 0xFF ]))
364+ self .con .transmit (registers .ACCEL_RADIUS_MSB_ADDR , 1 , bytes ([(acc_radius .value >> 8 ) & 0xFF ]))
365+
366+ self .con .transmit (registers .MAG_OFFSET_X_LSB_ADDR , 1 , bytes ([mag_offset .value [0 ] & 0xFF ]))
367+ self .con .transmit (registers .MAG_OFFSET_X_MSB_ADDR , 1 , bytes ([(mag_offset .value [0 ] >> 8 ) & 0xFF ]))
368+ self .con .transmit (registers .MAG_OFFSET_Y_LSB_ADDR , 1 , bytes ([mag_offset .value [1 ] & 0xFF ]))
369+ self .con .transmit (registers .MAG_OFFSET_Y_MSB_ADDR , 1 , bytes ([(mag_offset .value [1 ] >> 8 ) & 0xFF ]))
370+ self .con .transmit (registers .MAG_OFFSET_Z_LSB_ADDR , 1 , bytes ([mag_offset .value [2 ] & 0xFF ]))
371+ self .con .transmit (registers .MAG_OFFSET_Z_MSB_ADDR , 1 , bytes ([(mag_offset .value [2 ] >> 8 ) & 0xFF ]))
372+
373+ self .con .transmit (registers .MAG_RADIUS_LSB_ADDR , 1 , bytes ([mag_radius .value & 0xFF ]))
374+ self .con .transmit (registers .MAG_RADIUS_MSB_ADDR , 1 , bytes ([(mag_radius .value >> 8 ) & 0xFF ]))
375+
376+ self .con .transmit (registers .GYRO_OFFSET_X_LSB_ADDR , 1 , bytes ([gyr_offset .value [0 ] & 0xFF ]))
377+ self .con .transmit (registers .GYRO_OFFSET_X_MSB_ADDR , 1 , bytes ([(gyr_offset .value [0 ] >> 8 ) & 0xFF ]))
378+ self .con .transmit (registers .GYRO_OFFSET_Y_LSB_ADDR , 1 , bytes ([gyr_offset .value [1 ] & 0xFF ]))
379+ self .con .transmit (registers .GYRO_OFFSET_Y_MSB_ADDR , 1 , bytes ([(gyr_offset .value [1 ] >> 8 ) & 0xFF ]))
380+ self .con .transmit (registers .GYRO_OFFSET_Z_LSB_ADDR , 1 , bytes ([gyr_offset .value [2 ] & 0xFF ]))
381+ self .con .transmit (registers .GYRO_OFFSET_Z_MSB_ADDR , 1 , bytes ([(gyr_offset .value [2 ] >> 8 ) & 0xFF ]))
382+
340383 return True
341384 except Exception : # noqa: B902
342385 return False
343386
387+ def calibration_request_callback (self , request , response ):
388+ if not (self .con .transmit (registers .BNO055_OPR_MODE_ADDR , 1 , bytes ([registers .OPERATION_MODE_CONFIG ]))):
389+ self .node .get_logger ().warn ('Unable to set IMU into config mode.' )
390+ sleep (0.025 )
391+ calib_data = self .get_calib_data ()
392+ if not (self .con .transmit (registers .BNO055_OPR_MODE_ADDR , 1 , bytes ([registers .OPERATION_MODE_NDOF ]))):
393+ self .node .get_logger ().warn ('Unable to set IMU operation mode into operation mode.' )
394+ response .success = True
395+ response .message = str (calib_data )
396+ return response
397+
344398 def unpackBytesToFloat (self , start , end ):
345399 return float (struct .unpack ('h' , struct .pack ('BB' , start , end ))[0 ])
0 commit comments