1
1
#!/usr/bin/env python3
2
+
2
3
import math
4
+ from typing import Optional
3
5
4
- import adafruit_mpu6050 # IMU Driver
6
+ import adafruit_mpu6050
5
7
import board
6
8
import rospy
7
- from duckietown .dtros import DTROS , NodeType , DTParam , ParamType
9
+ import yaml
10
+ from adafruit_mpu6050 import MPU6050
8
11
from sensor_msgs .msg import Imu , Temperature
9
12
from std_srvs .srv import Empty
10
13
14
+ from duckietown .dtros import DTROS , NodeType
15
+
11
16
12
17
# TODO: calibration and loading custom config
13
18
@@ -17,38 +22,49 @@ def __init__(self):
17
22
super (IMUNode , self ).__init__ (node_name = "imu_node" , node_type = NodeType .DRIVER )
18
23
19
24
# get ROS/Duckiebot parameters
20
- self ._imu_device_id = rospy .get_param ('~imu_device_id' , 0x71 )
21
- adafruit_mpu6050 ._MPU6050_DEVICE_ID = 0x71 # Overwrite Adafruit default device ID being wrong
22
25
self ._veh = rospy .get_param ('~veh' )
23
- polling_hz = rospy .get_param ("~polling_hz" )
26
+ self ._i2c_connectors = rospy .get_param ("~connectors" , {})
27
+ self ._polling_hz = rospy .get_param ("~polling_hz" )
24
28
self ._temp_offset = rospy .get_param ("~temp_offset" )
25
29
self ._gyro_offset = rospy .get_param ("~ang_vel_offset" )
26
30
self ._accel_offset = rospy .get_param ("~accel_offset" )
27
31
self .loginfo ("===============IMU Node Init Val===============" )
28
- self .loginfo (f"Op Rate: { polling_hz } " )
29
- self .loginfo (f"ADDR: { self ._imu_device_id } " )
32
+ self .loginfo (f"Op Rate: { self ._polling_hz } " )
30
33
self .loginfo ("Acceleration Offset: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % tuple (self ._accel_offset ))
31
34
self .loginfo ("Gyro Offset X:%.2f, Y: %.2f, Z: %.2f degrees/s" % tuple (self ._gyro_offset ))
32
35
self .loginfo ("Temp Offset: %.2f C" % self ._temp_offset )
33
36
self .loginfo ("===============END of IMU Init Val===============" )
34
37
# IMU Initialization
35
- try :
36
- self ._imu = adafruit_mpu6050 .MPU6050 (board .I2C ())
37
- self .loginfo ("===============Performing Initial Testing!===============" )
38
- self .loginfo ("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % self ._imu .acceleration )
39
- self .loginfo ("Gyro X:%.2f, Y: %.2f, Z: %.2f degrees/s" % self ._imu .gyro )
40
- self .loginfo ("Temperature: %.2f C" % self ._imu .temperature )
41
- self .loginfo ("===============IMU Initialization Complete===============" )
42
- except Exception as IMUInitException :
43
- self .logerr ("IMU sensor not correctly setup! Error:" )
44
- self .logerr (IMUInitException )
38
+ self ._sensor : Optional [MPU6050 ] = self ._find_sensor ()
39
+ if not self ._sensor :
40
+ conns : str = yaml .safe_dump (self ._i2c_connectors , indent = 2 , sort_keys = True )
41
+ self .logerr (f"No MPU6050 device found. These connectors were tested:\n { conns } \n " )
45
42
exit (1 )
46
-
43
+ # ---
44
+ self .loginfo ("===============Performing Initial Testing!===============" )
45
+ self .loginfo ("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % self ._sensor .acceleration )
46
+ self .loginfo ("Gyro X:%.2f, Y: %.2f, Z: %.2f degrees/s" % self ._sensor .gyro )
47
+ self .loginfo ("Temperature: %.2f C" % self ._sensor .temperature )
48
+ self .loginfo ("===============IMU Initialization Complete===============" )
47
49
# ROS Pubsub initialization
48
- self .pub = rospy .Publisher ('~imu_data ' , Imu , queue_size = 10 )
49
- self .temp_pub = rospy .Publisher ('~temp_data ' , Temperature , queue_size = 10 )
50
+ self .pub = rospy .Publisher ('~data ' , Imu , queue_size = 10 )
51
+ self .temp_pub = rospy .Publisher ('~temperature ' , Temperature , queue_size = 10 )
50
52
rospy .Service ("~initialize_imu" , Empty , self .zero_sensor )
51
- self .timer = rospy .Timer (rospy .Duration .from_sec (1.0 / polling_hz ), self .publish_data )
53
+ self .timer = rospy .Timer (rospy .Duration .from_sec (1.0 / self ._polling_hz ), self .publish_data )
54
+
55
+ def _find_sensor (self ) -> Optional [MPU6050 ]:
56
+ for connector in self ._i2c_connectors :
57
+ conn : str = "[bus:{bus}](0x{address:02X})" .format (** connector )
58
+ self .loginfo (f"Trying to open device on connector { conn } " )
59
+ # Overwrite Adafruit default device ID
60
+ adafruit_mpu6050 ._MPU6050_DEVICE_ID = connector ["address" ]
61
+ try :
62
+ sensor = MPU6050 (board .I2C ())
63
+ except Exception :
64
+ self .logwarn (f"No devices found on connector { conn } , but the bus exists" )
65
+ continue
66
+ self .loginfo (f"Device found on connector { conn } " )
67
+ return sensor
52
68
53
69
def publish_data (self , event ):
54
70
# Message Blank
@@ -58,16 +74,14 @@ def publish_data(self, event):
58
74
try :
59
75
# You take the time immediately when you are polling imu
60
76
msg .header .stamp = temp_msg .header .stamp = rospy .Time .now ()
61
- acc_data = self ._imu .acceleration
62
- gyro_data = self ._imu .gyro
63
- temp_data = self ._imu .temperature
77
+ acc_data = self ._sensor .acceleration
78
+ gyro_data = self ._sensor .gyro
79
+ temp_data = self ._sensor .temperature
64
80
# Do it together so that the timestamp is honored
65
-
66
81
# Populate Message
67
82
msg .header .frame_id = temp_msg .header .frame_id = f"{ self ._veh } /imu"
68
-
69
- # Orientation
70
- msg .orientation .x = msg .orientation .y = msg .orientation .z = msg .orientation .w = 0 # We do not have this data
83
+ # Orientation (we do not have this data)
84
+ msg .orientation .x = msg .orientation .y = msg .orientation .z = msg .orientation .w = 0
71
85
# If you have no estimate for one of the data elements
72
86
# set element 0 of the associated covariance matrix to -1
73
87
msg .orientation_covariance = [0.0 for _ in range (len (msg .orientation_covariance ))]
@@ -90,10 +104,10 @@ def publish_data(self, event):
90
104
pass
91
105
return
92
106
93
- def zero_sensor (self , req ):
94
- acc_data = self ._imu .acceleration
95
- gyro_data = self ._imu .gyro
96
- temp_data = self ._imu .temperature
107
+ def zero_sensor (self , _ ):
108
+ acc_data = self ._sensor .acceleration
109
+ gyro_data = self ._sensor .gyro
110
+ temp_data = self ._sensor .temperature
97
111
self ._gyro_offset = list (gyro_data )
98
112
self ._accel_offset = list (acc_data )
99
113
self ._temp_offset = temp_data
0 commit comments