Skip to content

Commit f832938

Browse files
committed
IMU node now supports two IMU models
1 parent a7fd00e commit f832938

File tree

3 files changed

+81
-34
lines changed

3 files changed

+81
-34
lines changed

launchers/sensor-imu.sh

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
source /environment.sh
4+
5+
# initialize launch file
6+
dt-launchfile-init
7+
8+
# YOUR CODE BELOW THIS LINE
9+
# ----------------------------------------------------------------------------
10+
11+
12+
# NOTE: Use the variable DT_REPO_PATH to know the absolute path to your code
13+
# NOTE: Use `dt-exec COMMAND` to run the main process (blocking process)
14+
15+
16+
# launching app
17+
dt-exec roslaunch --wait \
18+
imu_driver imu_node.launch \
19+
veh:="$VEHICLE_NAME"
20+
21+
22+
# ----------------------------------------------------------------------------
23+
# YOUR CODE ABOVE THIS LINE
24+
25+
# wait for app to end
26+
dt-launchfile-join
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
# Sensor Configuration
2-
imu_device_id: "0x71"
32
polling_hz: 30
43
sensor_name: bottom_center
4+
connectors:
5+
# MPU 6050
6+
- bus: 1
7+
address: 0x68
8+
# TODO: model 2
9+
- bus: 1
10+
address: 0x71
11+
512

613
# Calibrations
714
ang_vel_offset: [ 0, 0, 0 ]
815
accel_offset: [ 0, 0, 0 ]
9-
temp_offset: 0
16+
temp_offset: 0

packages/imu_driver/src/imu_node.py

+46-32
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
#!/usr/bin/env python3
2+
23
import math
4+
from typing import Optional
35

4-
import adafruit_mpu6050 # IMU Driver
6+
import adafruit_mpu6050
57
import board
68
import rospy
7-
from duckietown.dtros import DTROS, NodeType, DTParam, ParamType
9+
import yaml
10+
from adafruit_mpu6050 import MPU6050
811
from sensor_msgs.msg import Imu, Temperature
912
from std_srvs.srv import Empty
1013

14+
from duckietown.dtros import DTROS, NodeType
15+
1116

1217
# TODO: calibration and loading custom config
1318

@@ -17,38 +22,49 @@ def __init__(self):
1722
super(IMUNode, self).__init__(node_name="imu_node", node_type=NodeType.DRIVER)
1823

1924
# 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
2225
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")
2428
self._temp_offset = rospy.get_param("~temp_offset")
2529
self._gyro_offset = rospy.get_param("~ang_vel_offset")
2630
self._accel_offset = rospy.get_param("~accel_offset")
2731
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}")
3033
self.loginfo("Acceleration Offset: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % tuple(self._accel_offset))
3134
self.loginfo("Gyro Offset X:%.2f, Y: %.2f, Z: %.2f degrees/s" % tuple(self._gyro_offset))
3235
self.loginfo("Temp Offset: %.2f C" % self._temp_offset)
3336
self.loginfo("===============END of IMU Init Val===============")
3437
# 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")
4542
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===============")
4749
# 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)
5052
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
5268

5369
def publish_data(self, event):
5470
# Message Blank
@@ -58,16 +74,14 @@ def publish_data(self, event):
5874
try:
5975
# You take the time immediately when you are polling imu
6076
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
6480
# Do it together so that the timestamp is honored
65-
6681
# Populate Message
6782
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
7185
# If you have no estimate for one of the data elements
7286
# set element 0 of the associated covariance matrix to -1
7387
msg.orientation_covariance = [0.0 for _ in range(len(msg.orientation_covariance))]
@@ -90,10 +104,10 @@ def publish_data(self, event):
90104
pass
91105
return
92106

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
97111
self._gyro_offset = list(gyro_data)
98112
self._accel_offset = list(acc_data)
99113
self._temp_offset = temp_data

0 commit comments

Comments
 (0)