Developing on NVIDIA® Jetson™ for AI on the Edge

IMU and PWM Driver over I2C for NVIDIA Jetson TX1

Another couple of devices that will be needed for upcoming projects on the Jetson TX1 Development Kit are an IMU and a PWM driver for servo control. These devices can be interfaced over I2C. Looky here:


We have covered using the Bosch IMU BNO055 under ROS and the PWM/Servo Driver is based on a PCA9685 Breakout Board in earlier articles. This is just a short recap to discuss the differences between the earlier articles and this demonstration.


The parts used in the demonstration:


Both of these devices can interface with the Jetson TX1 using I2C. We have covered using I2C with the Jetson in an earlier article. In this demonstration, we use the same I2C pins as in the previous article, the Jetson TX1 J21 pins 27 (SDA) and 28 (SCL). These are I2C_GP1_DAT and I2C_GP1_CLK respectively, on I2C bus 1. Both the PCA9685 and BNO055 are wired from these signals, and both use the 3.3V supply from J21 Pin 1, and GND from J21 Pin 6.

Note: Here is the Jetson TX1 J21 header pinout for reference. The GPIO numbers have not been verified by a third party, so use those at your own risk, but the signals should be correct.

The wiring is straightforward. The 3.3V goes to VCC on both the BNO055 and PCA9685, as does GND. SDA from the Jetson goes to both breakout boards, as does SCL. In the demonstration both of the devices were placed on separate prototyping boards, and a USB cable was connected to connect the two. A USB A breakout board and micro USB B female breakout board were used to carry the I2C signal from one breadboard to the next. On the USB breakout boards, 3.3V is wired to VCC, GND is wired to GND, SDA is wired to D+, SCL is wired to D-. On the micro USB B breakout, the remaining signal (ID) is not used. The cable used is the Jetson programming cable.

Note that this is for demonstration purposes only, for an actual application some calculations should be done to find an appropriate wiring solution.


The demonstration software is available in the JetsonHacks Github RTIMULib repository. RTIMULib is originally from from richards-tech LLC. Here is an article which gives a deeper talk about IMU stuff on that website.
To install the demonstration:

git clone

then open a file browser and navigate to ‘./RTIMULib/Linux/JetsonTX1DemoGL’. Then open the file ‘’ with Qt Creator and compile the demo. Here’s an article we did a while ago on how to install Qt Creator.

After the file is finished building, go to where the executable file resides (this is dependent on how Qt Creator is configured) and execute the demo using ‘sudo’. For example:

$ sudo ./JetsonTX1DemoGL

At that point the demonstration should begin with the IMU orientation being displayed in a GUI, and the servos being positioned by the orientation of the IMU. Remember that this demonstration uses only two servos and is therefore a 2 Degree of Freedom (2 DOF) rig. That means that only two of the three axes will change the servo settings. In the demonstration the yaw (Z axis) and the roll change the servos.


Camera gimbals are typically controlled using input from an IMU, at which this demonstration begins to hint. Typically there is a known orientation where the user would like to point the camera. The IMU is mounted on the camera gimbal itself and reports back to a micro controller a pose. The micro controller then calculates the desired pose from the IMU pose, and positions the servos motors accordingly. Note that other types of motors can be used, such as the now more common gimbal motors, but the idea behind both are the same.

This type of servo setup can also be used for face tracking, though no IMU is needed in that case. A camera is mounted on the pan and tilt head. The camera takes a video feed and sends it to the Jetson which can then use a program such as OpenCV to detect faces in the image. Using this information, the Jetson can then position the servos so that the camera centers itself on the face that has been detected.


22 Responses

  1. Hey kangalow!

    I’ve been trying to run this and also RTIMULibDemoGL to test my BNO055. The BNO055 is connected on I2C bus 0 (pins 3 and 5 for SDA and SCL, respectively). I’m able to detect the device at address 0x28. However, when I try to run RTIMULibDemoGL, I get the error “Failed to open I2C bus 0”. Have you encountered this error before and do you have ideas for how to address it?


    1. As stated in the article, you have to run:
      $ sudo ./JetsonTX1DemoGL
      For permissions. As you learned, you can also set the permissions for the device itself.

  2. This is great help! Now I need to distill just the part for the IMU to work with ROS. The info needed is in this code somewhere!

  3. Howdy folks,

    I am using the PCA9685 from a ROS node and I am running in the same issue where my ROS node doesn’t have permission to open /dev/i2c-* .

    While “sudo chmod a+rw /dev/i2c-*” works as a temporary get-around, eventually I would like something that just works without having to first change the permissions of the device file.

    Taking in mind that the executable is called from a ROS launch file and while I can use a “sudo launch prefix”, I don’t want the launch to be interrupted for entering a password, nor do I want to setup a passwordless sudo either.

    How does one normally go about solving “embedded permission issues” like these?

    Thanks in advance


  4. I finally got around to creating a udev rule as suggested by kangalow to set the I2C device permissions. Here are the details:

    First create a new rule file (my editor of choice is emacs, pick yours)
    $ sudo emacs /etc/udev/rules.d/50-myi2c.rules

    Then put in the following line:
    ACTION==”add”, KERNEL==”i2c-[0-1]*”, MODE=”0666″

    I had to reboot my JTX1 before it took effect.



  5. Hello,

    IMU is giving me more troubles than I want 🙂 first of all I2C rules in udev/rules.d folder don’t help. I created the document and added both the line suggested in one of the previous tutorials, and the line that Galto suggested, but neither is working. Only thing that works is manually typing “sudo chmod a+rw /dev/i2c-*”. But that’s not the main problem.

    Main problem is that rtimulib-ros doesn’t find IMU. I use Pololu AltIMU-10 v4, which is supported by RTIMULib, and RTIMULib library is installed, as well as rtimulib-ros, but when I launch the node, it gives error “No IMU found”. In RTIMULib.ini configuration file BusIsI2C=true, and I2CBus=1, while wiring is the same as proposed here.

    Any idea what I could do to diagnose the problem? Tried i2cdetect -y -r 1, but there is a bunch of stuff, and it doesn’t change regardless if wires are connected or not.

    1. Ok, ignore my No IMU problem, I am just retarded 😀 Connection was loose and that’s why it didn’t see IMU. Now just udev rules to sort out…

  6. Did you ever sort out the udev rules ?
    I tried the $ sudo emacs /etc/udev/rules.d/50-myi2c.rules

    Then put in the following line:
    ACTION==”add”, KERNEL==”i2c-[0-1]*”, MODE=”0666″
    suggested by Galto but no luck. It only works with:“sudo chmod a+rw /dev/i2c-*”
    But I really want the launch file to run without having to do this.

  7. Hi! I use J21 connect the BMP280 in TX2,however TX2 can’t detect the BMP280.Do you know the reason?

  8. I use TX2 to connect BMP280 in J21.But use (i2cdetect -y -r 1) can’t find BMP280.I need help.Thank you very much.

    1. Note that the TX2 and the TX1 may use a different i2c bus. In other words, check with i2c if the device is on a different bus, e.g.
      $ sudo i2cdetect -y -r 0

  9. Hello,
    I have installed the Adafruit IMU directly to the I2C. I connected SCL to pin 28 and SDA to pin 27. Ground goes to pin 9 and power to pin 1. But when I run the program, I get the error “I2C read error from 41, 8 – Failed to read BNO055 data”, and when I run i2c detect on bus 0, which I think is the IMU, I get this:
    0 1 2 3 4 5 6 7 8 9 a b c d e f
    00: — 04 — — — — 09 — — 0c — 0e —
    10: — — 12 — 14 — — — — 19 — — — 1d — —
    20: — 21 — — — 25 — — 28 — — 2b — — 2e —
    30: — 31 — — — 35 — — — — 3a — — 3d — —
    40: UU UU UU UU — 45 — — — — — — — — — —
    50: 50 — — — — — — — — — 5a — — 5d — —
    60: 60 — — 63 — 65 — — — — — — — 6d — —
    70: — — — 73 UU — — UU

    Do you have any idea what the issue could be?

    1. I changed to the I2C Bus 0 in the program. Which value should I see when I run i2cdetect for the IMU. I am using the same 9dof Adafruit IMU. Do I need to change anything in the source code? Thank you

      1. I don’t understand what you are asking. The BNO055 reports as address 0x28 which is shown on the above i2cdetect dump. The PCA9685 reports as 0x41. On the TX2, Bus 0 0x40-0x43 is used internally for INA23X power monitors. Therefore you will have issues reading/writing to the PCA9685. That is what the error (I2C read error from 41) you mentioned indicates. Typically you would use I2C Bus 1 if you wanted to use the PCA9685. You will need to change the source code to reflect your installation.

        1. Thank you for your help, but I think it was a faulty IMU, I soldered the SparkFun Razor MPU9250, and it works now.

Leave a Reply

Your email address will not be published. Required fields are marked *


Some links here are affiliate links. If you purchase through these links I will receive a small commission at no additional cost to you. As an Amazon Associate, I earn from qualifying purchases.

Books, Ideas & Other Curiosities