Lessons learned while working with IMU Sensor, ROS2 and Raspberry Pi

RoboFoundry
7 min readSep 5, 2021

While building a robot based on Raspberry Pi, Ubuntu 20.04 and ROS2 Foxy Fitzroy, I ended up spending a lot more time on IMU issues than I expected to spend. Here are my lessons learned and some thoughts that may save you some headaches and may even save you some time and money.

Lesson #1 — Choose the right type of IMU

There are many different types of IMUs, and the ones are considered are listed below:

  • MPU6050– 6 DOF sensor with no magnetometer
  • MPU9250–9 DOF sensor with gyro, accelerometer and magnetometer
  • BNO055– 9 DOF sensor with gyro, accelerometer and magnetometer
  • BNO085– 9 DOF sensor with gyro, accelerometer and magnetometer
  • NXP Precision Breakout based on FXOS8700 3-Axis accelerometer/magnetometer and the FXAS21002 3-axis gyroscope
  • BMI160–6 DOF sensor with gyro and accelerometer. Check out this story for in-depth how to use BMI160 with ROS2

Most of these are in $20 or less range, I’m not including anything in more expensive range as I need to stay in the budget range for the IMU sensors as one of the parameters I need to watch for the robot construction is cost. I only tested and experimented with two of these — MPU6050 and BNO055 so my comparison and thoughts are only based on these two, hope that gives you some idea on how to avoid mistakes I made. Also a disclaimer, I’m not an expert in IMU sensors and I’m still learning but wanted to share my experience if it can be helpful.

After spending a lot time hooking up the sensor with robot and writing python code from scratch to read the IMU and creating a ROS2 node to publish the IMU data over a ROS topic, I was able to display the robot with IMU sensor data in RVIZ2 simulator. However, after spending more amount of time hunting for Madgwick and Complementary filter ROS2 nodes that worked with Foxy [again there is a lot of code out there for ROS1 but finding something that will work for Foxy is very hard], the robot was spinning continuously around the z-axis even after trying/applying Madgwick and Complimentary filters. After doing some more research, I learned that the reason for this is MPU6050 does not have a magnetometer, so the sensor fusion algorithms like Madgwick and Complementary filters can only do so much and it will have that rotation.

So the main lesson learned here is - get the sensor that will have magnetometer included.

Lesson #2 — Sensor Calibration and saving offsets

After going through all the pain with MPU6050 I went for a big splurge with Adafruit BNO055. This one costs around $20 but since I was in hurry I ended up spending $10 for shipping. To be honest, I love Adafruit but the shipping costs are very expensive unless you are buying a lot of items together, which for me this was the only item along with its STEMMA connectors I was buying so it hurt to spend 50% of the sensor cost on the shipping.

Cool thing about this sensor is that it has a lot of noise filtering and orientation calculations done on hardware onboard. First time I simulated the sensor in RVIZ2, there was a night and day difference between this one and MPU6050. The robot was very stable and followed all my movements when I moved to robot as expected without a lot of noise.

The only downside to this sensor is the gyro, magnetometer and system part of the calibration works really fast within a few seconds you fire up the sensor with power. However, the accel is a really pain to get it to 3 [fully calibrated status]. The key is to move the sensor very slowly in each axis both linear and rotation until you get the calibration status showing 3.

It is really hard to find the code that will run on Raspberry Pi for saving and loading the sensor status data for BNO055. Adafruit also sells another version of this sensor BNO085 which is supposed to be better than this but does not do a lot of computation on hardware onboard, so you will receive raw sensor data and then you will need to pass it through Madgwick or Complementary filter to get orientation added for you to plug it into ROS2. When I tried to purchase, the BNO085 was out of stock so I went with BNO055 but both are essentially really good quality budget sensors.

While I was scanning for some information on Adfruit forums someone also mentioned NXP breakboard mentioned in the list above. This one supposedly has the least amount zero rate level off compared to others they sell. Again, this was out of stock, most likely due to chip shortages going on at present so I have not used it.

In order to calibrate the BNO055 sensor, you can use the Adafruit WebGL Demo tool . They have a lot of Arduino code and sensor testing tools but since I’m working with Raspberry Pi only this circuit python library was useful for me. The steps to run the tool are:

  • Run the web server side of tool by launching ‘python3 server.py’ while you are in that subfolder [you’ll see it under Adafruit_CircuitPython_BNO055examples → bno055_webgl_demo]
  • Then you launch the client side of the tool by hitting http://yourmachineIPAddress:5000 and the visualizer will render in your Chrome browser [Chrome is recommended].
  • After that you move around the sensor until you achieve all 3s for system, gyro, accel and mag like this. The image below shows the Save and Load buttons but those are not implemented for BNO055 so there is no easy way to save the calibration offsets from this tool. Some times it is very painful to get the sensor to get to all 3s and it takes a long time. I had the sensor mounted on a robot that weighs a few pounds so moving it around after mounting on robot was not easiest. So keep that in mind as well, do not mount the sensor rigidly as I did. I would suggest those plastic rivets like they use in Lego blocks to pop it in and pop it out from the base rig so you can remove it and move it around.

I quickly realized that even though the sensor itself is very powerful and good, its calibration routines are black box and it also runs those routines every time it is powered on. There is no onboard EPROM to store the last setting permanently. So every time you restart RPi you have to re-calibrate. Which turns into a very painful and time consuming task pretty fast. You don’t want to mess around with this stuff while you are trying to solve bigger problems for getting your robot to work.

I had to research a bit to find this little wonderful utility call pi-bno055 that runs on Raspberry Pi and you can use it to save and load your calibration offsets after you complete the initial calibration. The utility is written in C so you have to get the code from github link and compile it on your RPi first time, [it is as simple as running make command]. The instructions for using the command line are very well documented in ReadMe file on github.

I actually ran into a little error when first time I tried to load the saved calibration data after sensor restart. And the reason it gave me error was because I had not set the sensor mode to “config”. The default mode for BNO055 is “ndof” but you cannot load calibration data in an operational mode, you can only load calibration data when in “config” mode. That makes perfect sense, so after I switched the mode to config, I was able to load the previously saved calibration data without any issues. I even went ahead and created a shell script to automate the process. You can save it as a file if you like and run the script below:

You can execute the script on Ubuntu like this:

. your_script_filename.sh 

OR to run silently without user input

. your_script_filename.sh silent.

Save the following shell script to filename of your choice and run.

silentmode=falseif [[ "$1" == *silent* ]]then    echo "silent"    silentmode=trueelse    echo "user interaction mode"ficd REPLACE_THIS_WITH_PATH_TO_YOUR_pi-bno055_FOLDER./getbno055 -a 0x28 -t inf -vif [ "$silentmode" = false ] ; then    read -n1 -r -p "Press any key to continue..." keyfi./getbno055 -m configif [ "$silentmode" = false ] ; then    read -n1 -r -p "Changed mode to Config, Press any key to continue..." keyfi./getbno055 -l ./bno055.calif [ "$silentmode" = false ] ; then    read -n1 -r -p "Loaded saved calibration offsets successfully. Press any key to continue..." keyfi./getbno055 -m ndofif [ "$silentmode" = false ] ; then    read -n1 -r -p "Switched back to operation mode. Press any key to continue..." keyfi./getbno055 -a 0x28 -t inf -vif [ "$silentmode" = false ] ; then    read -n1 -r -p "See latest calibration status after load above. Press any key to exit..." keyficd ~

Lesson learned is — doing the calibration of the IMU sensor is painful and it is even more tricky to save the calibration offsets and automate that process to avoid doing the grunge work over and over again.

Check out these other stories:

--

--