Robot Operating System (ROS) makes integration of sensors such as the Bosch BNO055 9 Degree of Freedom (DOF) IMU straightforward. Looky here:
Background
When building a robot, designing, planning and selecting sensors and parts for the build are crucial to success of the overall project. In building our project robot, one of the sensors that is needed is an Inertial Measurement Unit (IMU) which will be used for odometery. Odometry will be discussed in another article in the future.
There are a multitude of IMUs on the market, in a three part article about IMUs, we discussed how to install a 10-DOF IMU. That particular IMU has discreet gyroscope and accelerometer/compass chips from which the host takes the readings and applies ‘fusion’ algorithms to produce three-axis orientation output. Also, the host generally has to provide a means to calibrate the sensor. Calibration usually means moving the IMU around each axis to hit the minimum and maximum values of the sensor, and place the information into a calibration file of some sort.
Bosch has recently come out with a new IMU, the BNO055. Adafruit has placed the BNO055 on a breakout board and added their usual niceties which allows the Jetson TK1 to access the BNO055 via I2C. The descriptive blurb from the Adafruit website:
If you’ve ever ordered and wire up a 9-DOF sensor, chances are you’ve also realized the challenge of turning the sensor data from an accelerometer, gyroscope and magnetometer into actual “3D space orientation”! Orientation is a hard problem to solve. The sensor fusion algorithms (the secret sauce that blends accelerometer, magnetometer and gyroscope data into stable three-axis orientation output) can be mind-numbingly difficult to get right and implement on low cost real time systems.
Bosch is the first company to get this right by taking a MEMS accelerometer, magnetometer and gyroscope and putting them on a single die with a high speed ARM Cortex-M0 based processor to digest all the sensor data, abstract the sensor fusion and real time requirements away, and spit out data you can use in quaternions, Euler angles or vectors.
Note: The BNO055 uses an I2C technique called ‘clock stretching’. The chip holds the SCL line low while taking a reading, basically saying “not ready yet”. This provides more flexibility on the I2C master side because it does not have to do a full command-and-response. However, be aware of this when connecting the BNO055 to things like I2C address multiplexers which may require you to work around this feature. For example, some people report that initializing the BNO055 twice may be required as a work around to get the sensor to work.
I like things that do the maths on their own and don’t bother me about it. Cool!
Install Strategy
The idea here is to install the Bosch IMU under ROS on the Jetson TK1. Following the path of least resistance, we’ll use RTIMULib (from richards-tech LLC on Github) as the low level interface library and rtimulib_ros (from Romain Reignier) as the interface to ROS. It should be noted that this is a trade off of convenience versus overhead. Because the Bosch IMU spits out fused sensor data, it should be straightforward to turn this directly into a producer that ROS can digest. However RTIMULib and rtimulib_ros already do this (though with added overhead), so for now this seems like a straightforward path to integration.
We will cover the software installation, how to wire up the Bosch IMU to the Jetson, and then how to run the visual demo.
Software Installation
Note: Before installing the IMU interface to ROS, ROS must be installed of course. Here’s an article on how to do that. Also you must have a catkin workspace installed. Here’s a video that covers that process.
Installing RTIMULib
Under the normal RTIMULib installation process, Qt is installed along with the library. If you are not using Qt on the robot, that is unnecessary. In this installation, the cmake file is modified to so that Qt is not installed.
First install ccmake, which will be used later to edit the cmake file.
sudo apt-get install cmake-curses-gui
Then get RTIMULib.
git clone https://github.com/jetsonhacks/RTIMULib.git
By default, I2C devices are owned by root. To change this, create a file /etc/udev/rules.d/90-i2c.rules and add the line:
sudo gedit /etc/udev/rules.d/90-i2c.rules
KERNEL==”i2c-[0-7]”,MODE=”0666″
As an alternative, you can do this straight from a command line:
$ sudo bash -c 'echo KERNEL==\"i2c-[0-7]\",MODE=\"0666\" > /etc/udev/rules.d/90-i2c.rules'
Then prepare for compilation
$ cd RTIMULib
#Switch to the Linux directory
$ cd Linux
$ mkdir build
$ cd build
$ cmake ..
This generates the cmake file. The parameters can now be changed so that Qt is not required:
ccmake ..
Change the ‘GL’ related options to off, ‘c’ to configure and then ‘g’ to generate and exit. Then:
cmake ..
make -j4
sudo make install
sudo ldconfig
You will probably need to reboot the machine for the permission changes in the udev to take effect.
Install rtimulib_ros
Setup rtimulib next. “catkin_ws” is the example workspace name and should be replaced by your own catkin workspace name where you are doing development.
cd ~/catkin_ws/src
source devel/setup.bash
git clone https://github.com/jetsonhacks/rtimulib_ros.git
To recreate the demonstration, the ROS Topic needs to be “imu”. In the source file, it is listed as “imu/data”. The Topic name is probably related to the consumer viewing the Topic, you may need to change this appropriately later. For now, we’ll just get this working for the demo.
cd rtimulib_ros/src
$ gedit rtimulib_ros.cpp
Change the line:
// ros::Publisher imu_pub = n.advertise
ros::Publisher imu_pub = n.advertise
Then build the node:
$ cd ..
$ cd ..
$ catkin_make
For the demo, install the IMU visualizer:
$ sudo apt-get install ros-indigo-razor-imu-9dof
$ sudo apt-get install python-visual
$ sudo apt-get install python-wxtools
Installing the Bosch IMU
There are several ways to connect the Inertial Measurement Unit (IMU) to the Jetson TK1 Development Kit. Here’s a demonstration of a very simple way. The IMU is not the Bosch, but is very similar and the installation method is the same. Looky here:
Here’s a couple of pictures of the Bosch breakout board from the Adafruit website:
Solder the supplied header pins onto the IMU breakout board, then wire the IMU header pins to the Jetson J3A1 connector as follows:
GND J3A1-14 (-)
Vin J3A1-16 (+)
SCL J3A1-18 (C)
SDA J3A1-20 (D)
Here are some pictures from the Jetson Wiki for reference :
There are several ways to actually connect the headers to the Jetson J3A1 connector, in this case we use simple female to female jumper wires (0.1″ spacing, 2.54mm pitch – this is standard Arduino size) to attach to the IMU header, and then connect the jumper wire to a machine pin jumper wire, which is then connected to the Jetson.
For the demo, I used Adafruit Premium Female/Female Jumper Wires – 40×6″ and 20 CM Machine Pin Wire Kit/10 Pack. This approach may be adequate for some projects, but for more rugged projects you may want to consider actually soldering wires to the header pins approach or making a breakout board for the Jetsons’ J3A1 header. Remember that the J3A1 header is 2mm pitch (0.08″) which is slightly smaller than the more standard DIY 2.54mm pitch that something like an Arduino uses. You’ll also want to physically mount the device some where also, fortunately there are mounting holes for that purpose on the breakout board.
Running the demo
After installing the software and wiring the IMU to the Jetson, you should be ready to start robotin’.
# Open a new terminal
$ roscore
# Open a new Terminal
$ cd ~/catkin_ws
$ source devel/setup.bash
$ roslaunch rtimulib_ros rtimulib_ros.launch
# Open a new Terminal
$ cd ~/catkin_ws
$ source devel/setup.bash
$ roslaunch razor_imu_9dof razor-display.launch
At this point, you should be up and running and you should be receiving data from the IMU.
Conclusion
The Bosch BNO055 is a good choice for many applications where the host system does not want to bother with having to generate the IMU sensor fusion data. The Bosch is straightforward to use, and does not require the calibration gymnastics that most other IMUs require. Recommended.
45 Responses
With a drawer full of -other- 6 and 9 degree IMU’s, I hesitated to buy this.
I am glad I did. The MEMS gyros and accelerometers in the other IMU’s all work well. I could never get the magnetometer component of 9DOF units to determine ‘magnetic north’ well enough to use. A lot of robot odometry routines fall back to using just the rotation gyro for this reason I suspect.
This Bosch IMU does repeatably return heading values in relation to ‘north’ while mounted on my robot.
To give the automatic calibration software the best chance, I did mount it as far away from the motors as possible.
Recommended!
Diving a little deeper into the Bosch BNO055 and the ROS navigation stack…
I am still a big fan of this device. Repeatable absolute magnetic bearing readings are nothing to be sneezed at for mobile ground robot applications.
For those using the ROS navigation stack, this may be of interest.
No solution yet, just interesting data points…
From the ROS REP 103 Standard Units of Measure and Coordinate Conventions:
“By the right hand rule, the yaw component of orientation increases as the child frame rotates counter-clockwise, and for geographic poses, yaw is zero when pointing east.
This requires special mention only because it differs from a traditional compass bearing, which is zero when pointing north and increments clockwise. Hardware drivers should make the appropriate transformations before publishing standard ROS messages.”
The navigation stack of ROS expects some fairly bizarre sensor outputs vs intuitive compass behavior. When using just gyro readings for yaw values not referenced to magnetic north, this is easily overlooked.
The Bosch IMU has two data output modes, both increment yaw turning clockwise.
The BNO055 allows inverting the sign of the Z axis in register settings. We will try that first before doing conversions further downstream.
As usual, rvis will be the easiest debug tool for verification.
That’s interesting information. Coincidentally I’ve been playing with the BNO055 and found in the RTIMULib library BNO055 driver that the Euler angles had their axes remapped before being stored as a fusionPose in IMURead, and were then converted to a separate quaternion (fusionQPose). rtimulib_ros then publishes the quaternion (fusionQPose) angles to the “imu/data” topic. I’m certainly interested in hearing about what you learn.
After resorting to painters tape on the floor to create a compass rose with both NED and ENU coordinate systems, the solution was actually fairly simple.
1) I physically rotated the IMU to report zero Euler yaw with the robot facing east.
2) Subtract the reported fused Euler yaw from 360 before sending it off to ROS.
The Euler yaw to quaternion conversion is done in a ROS node on the TK1.
My robot is doing all the odometry calculations on a mbed enabled nucleo STM32 development board. The Bosch IMU is being read by the mbed board in my case.
X_odometry increases as the robot travels east.
Y_odometry increases as the robot travels north.
Euler yaw value increases as the robot turns counter-clockwise.
The ROS navigation stack seems OK with this setup.
It is strange to have the robot moving due east on a zero degree heading.
Thank you for posting this, it’s certainly good information to know! Hopefully you can post some pictures or video of the robot in action.
How about the entire odometry code? x_odom, y_odom and yaw_enu are all that ROS needs to publish the robot pose. Things do get easier with faster microcontrollers. Most of the current odometry examples seem to be geared for legacy (slow) 8-bit microcontroller limitations.
I will probably circle back around to this one day to see if fiddling with the IMU registers can accomplish the same thing. I have probably hosed the pitch and roll reporting, but yaw is really the only thing I am after from the IMU.
————————————————————————-
imu.get_Euler_Angles(&euler_angles); // From Bosch BNO055 IMU
yaw_enu = 360 – euler_angles.h;
left_pulses_odom = left_enc.getPulses();
right_pulses_odom = right_enc.getPulses();
left_delta_odom = left_pulses_odom – prev_left_pulses_odom;
right_delta_odom = right_pulses_odom – prev_right_pulses_odom;
distance_delta_odom = (0.5 * (double)(left_delta_odom + right_delta_odom)) * MetersPerCount;
distance_total_odom += distance_delta_odom;
x_delta_odom = distance_delta_odom * (double)cos(yaw_enu*0.017453292);
y_delta_odom = distance_delta_odom * (double)sin(yaw_enu*0.017453292);
x_odom += x_delta_odom;
y_odom += y_delta_odom;
prev_left_pulses_odom = left_pulses_odom;
prev_right_pulses_odom = right_pulses_odom;
Way excellent! Look forward to using this.
A followup, by using volume 1 of “ROS By Example” by R. Patrick Goebel as a step by step guide for standards checking of my scratch built ‘turtlebot cousin’, this second iteration of the build works well.
Xbox Kinects have a narrow field of view to generate ‘fake’ laser scan data. My previous build with gyro only yaw was not accurate enough for ROS move_base and amcl to work as robustly as I knew they could.
The Bosch IMU allows such tight odometry calculations, the ROS navigation stack now works like it should. Even with a less than optimum ‘laser’, the robot keeps localization within a map during ‘patrols’ very well.
Where the Jetson will shine is adding some vision applications to the mix.
Running ROS does not tax the JetsonTK1 capabilities at all.
Only one minor gripe with the Bosch IMU. I do not think there is a way to store calibration data on the device between power cycles. This means on every power-up of the IMU, I have to pick up the robot and do the ‘figure eight’ maneuver to calibrate the IMU. This is not a problem on a small robot. Larger robots may need a way to unmount the IMU to wave it around and remount in the same position.
My understanding is that once you have the IMU calibrated, you can read the calibration information from the chip, save it somewhere, and then on startup set the calibration for the IMU from the saved data. The IMU will still calibrate itself, but it should be pretty close.
The registers that hold the calibration data have names like:
ACCEL_RADIUS ….
MAG_RADIUS …
ACCEL_OFFSET…
MAG_OFFSET…
GYRO_OFFSET…
Tried this on the TX1 everything works ok up to the visualization part. That fails with a segmentation fault. Any ideas?
I haven’t look at it yet.
Its the visualization stuff. Going to rviz or rqt its good to go. Tried recompiling those three python packages and discovered one of them is what is keeping me from building ros-desktop. Wxtools. Gets a seg fault when trying to build ros as well. But the separate package compiles no problem. So finally I have everything hooked up to the tx1 I had on the tk1’s.
Not too surprising, the actual code that reads the IMU is pretty straightforward. Graphics and such rarely are. Another hurdle down on the bot!
Like your music! What is it?
Thanks,
Cactus
Hi Cactus,
Thanks for your kind words. A couple of my friends and I get together and jam every couple of months, and I throw an audio recorder on. Since I’ve been doing this for more than ten years, I have a good backlog of background music to select from. Most of the songs are several minutes long, so they tend to match the length of the videos I do for this channel. Thanks for reading and watching (and listening!)
showing this error:
Failed to open I2C port – Failed to read BNO055 data
Any ideas on this ?
Where you able to see the BNO055 on the I2C bus? There’s not enough information in your question to give you any help.
Once the board is wired up, turn the Jetson TK1 on.
In order to be able inspect the i2c bus, you will find it useful to install the i2c tools:
$ sudo apt-get install libi2c-dev i2c-tools
After installation, in a Terminal execute:
$ sudo i2cdetect -y -r 1
You should see an entry of 0x28, which is the default address of the IMU.
Hi kangalow,
I have same problem,
run -> roslaunch rtimulib_ros rtimulib_ros.launch
showing this error:
Failed to open I2C port – Failed to read BNO055 data
Failed to open I2C bus1
I check i2c entry of 0x28 is OK.
Any ideas on this ? Thanks~
My first guess would be that the udev permissions are messed up. What is the content of the file /etc/udev/rules.d/90-i2c.rules
There should be a line
KERNEL==”i2c-[0-7]”,MODE=”0666″
[Possible Fix] I had this issue using the tx1 and the BNO055 IMU. I edited the RTIMULib.ini file under catkin_ws/src/rtimulib_ros/config. For IMUType the default was set to 10. I changed it to 0 and it started working for me. I now look at the .ini file after running once and it says 10 again but its working repeatably now.
I’m using SparkFun 9DoF Razor IMU M0 (MP9250)… facing with the same issue. The i2c address is 8×60.
Any fix that I should do?
I am trying to get my IMU talking to ROS and I am running into a permissions issue. I have tried adding the rules file you describe on two different Jetson TK1s. The first is a vanilla 21.4 install, and the other is a grinch kernel. On both of them I added the rules file and rebooted, but the permissions for the i2c lines are still set to only be for root user. I used the single line command you provide, and I verified the file was created in the correct spot. Any ideas on what I could be doing wrong here?
I figured it out. When I went back and looked at the entry in the rules file I noticed that it had quote marks around the whole statement. When I took those out and rebooted it worked fine. I believe your command should look like this instead: sudo bash -c ‘echo KERNEL==\”i2c-[0-7]\”,MODE=\”0666\” > /etc/udev/rules.d/90-i2c.rules’
I apologize, I had placed the command in an HTML blockquote block which messed up the intent. I placed the command into a HTML code block which should clear things up. I’m sorry for the inconvenience.
Long time viewer first time poster. Thanks for the most excellent toturials! My question : Any caveats for doing this with a JTX1 instead of a JTK1?
Hi Galto,
Thanks for the kind words. This article may prove useful if you want to use the BNO055 on the TX1: https://jetsonhacks.com/2016/01/11/imu-and-pwm-driver-over-i2c-for-nvidia-jetson-tx1/
Thanks for reading!
Hi,
Can this package be used standalone with normal pc running ROS. I do not have a jetson to play with right now but would like to test the Bosch BNO055 IMU. I plan to use it on the turtlebot2 with a laptop PC. Any suggestions or pointers?
Thanks
Alex
Hi Alex,
Unlikely this would work, as it uses the GPIO pins on the Jetson to interface with IMU board. You may be able to interface with an Arduino and then hook the Arduino up to a PC. Thanks for reading!
Hi @kangalow,
Thanks for the reply. In case I use an arduino, can you tell how can I use it to communicate with the ROS. I know there is something call ros_serial but not sure how to use it. Can you point me to some good direction.
Thanks
Alex
Here’s an article very similar to what you would end up doing with the Arduino in your application:
https://jetsonhacks.com/2016/08/02/jetson-racecar-11-arduino-ros-node-for-car-control/
Hi Kangalow,
I have managed to use the BNO055 with the PC via USB. I used the FT232H UART converter from adafruit to connect it via the USB cable. The sensor is alive and I can run demo from the adafruit library. Does the RTIMULIB be used now with this configuration? I want to use your ros package for the IMU? Can you guide me.
Thanks
Alex
Hi Alex,
I don’t know enough about a PC application to help you, sorry.
Hi kangalow,
Never mind. I figured out how to use it with the PC. I had to write a small code and interface with the adafruit library. Its working good on ROS now. Thanks.
Alex
Hi,
Has anyone checked if their Barometer Pressure Sensor Works? My sensor is MS5611 and it is supported by the library but i have no way of checking if it working properly or not?
Any ideas?
This is an old post but maybe someone will see a new comment…
Does anyone know if it is possible to use the this package with two IMU units of the same make/model on the same machine? I am using a Pololu MinIMUv3 with the L3GD20H and LSM303D that has worked great with this package, but I have to add a second one on my robot. The module provides a way to set different slave addresses for the units, but in the RTIMU .ini file it only seems to specialize which i2c bus is used, not the address.
As always, thanks for the help. JetsonHacks has helped me go from completely clueless to being able to BS my way through quite a few situations 🙂
Thank you for the kind words. I don’t know the correct answer to this question, but it strikes me that you may be able to use another I2C bus for the second sensor and not have to change the address. You can look at the diagram:
http://elinux.org/Jetson/I2C
for where the header pins are located. As such things go, this post is a little old and this RTIMULib has been superseded:
https://github.com/RTIMULib/RTIMULib2
Good luck!
This turorial was super helpful! Thank you very much for the time put into it. I have one question about the output rate: how can I change the publishing rate so that I’m only getting 5 or 10 data points a second.l? For my application, I need to save all the data to a .bag or .txt file for 45-60 minutes and don’t want to have to work through hundreds of thousands of data points at the end.
Thanks for the tuturial. I had to make some changes as some instructions seem out of date.
The package ros-indigo-razor-imu-9dof did not seem available to my TX2 board so I used the package ros-kinetic-razor-imu-9dof.
However, this did not seem to install properly as no new package was found in catkin_ws/src. So I had to install from source using:
cd catkin_ws/src
git clone https://github.com/KristofRobot/razor_imu_9dof.git
cd ..
catkin_make
The Jetson TX2 runs a version of Ubuntu 16.04, which uses ROS Kinetic. The TK1 uses an earlier version of Ubuntu, and requires ROS Indigo.
A package that you install via apt-get is a binary, it does not get installed in the src directory. The catkin_ws/src directory is for packages that you are compiling from source files. Thanks for reading!
Hi, I tried this with my TX2 and I think it worked quite well for up and down, but when I made an orientation the razor display show the opposite direction, and it is the same when I mounted the imu on my robot, so if it turns right, the display will show that it turns left, maybe I have to do the modification on the RTIMULib program, but I don’t know what is wrong, do you have any idea about this? Thank You.
The orientation is based on how you have the BNO055 mounted. I don’t know how you mounted the device on your robot. Thanks for reading!
Thank you for replying, actually when I used the razor-display, when I turn it to the left, on the display will turn right, and the same with the roll and pitch also move to the opposite direction, and I think in your video also the imu moves opposite to the razor display, I am so confuse, or maybe is there something wrong with my understanding? hehe
You should not watch the video. Instead understand which coordinate system you are using and expecting for the device, and adjust accordingly. For example: https://youtu.be/AVAzePauK2w?t=417
I ran this on Jetson TX2, and it worked fine. However, when I tried on Jetson xavier Nx, it did not work. i2cdetect can not see this device.
What does this mean “ KERNEL==”i2c-[0-7]”,MODE=”0666″?
The Xavier NX has different I2C bus numbering. Which I2C bus did you try, and to which I2C bus did you wire the IMU?
The line you reference appears to be from a udev rule which sets the permissions of the I2C bus to make it accessible from user space.