Analog servos interface using Pulse Width Modulation (PWM). Connecting a PWM servo driver board to the Jetson TK1 over I2C makes interfacing with servos easy. Looky here:
In an earlier article, RobotGeek Pan and Tilt Kit, we attached two servos to a Jetson TK1 via an Arduino. The micro controller Arduino is well suited to controlling analog servos, and is easy to interface with from the Jetson. However, one of the issues is that this approach requires two different code bases on different types of machines. Though the Arduino is straightforward to program, the cognitive overhead of running two different processor types and programming models can confuse issues. In other words, it can be a pain in the ass to add an Arduino to the mix just to talk to servos.
So why not just use the PWM GPIO pins on the Jetson? The answer has to do with hardware. PWM requires some pretty precise clock work and refresh, something a SoC like the Tegra K1 doesn’t do very naturally especially when running a non-real time OS like Ubuntu. What to do, what to do …
It turns out that Adafruit makes a breakout board around a PCA9685 chip. Using I2C (only two command pins) the breakout board can control 16 free-running PWM outputs! You can also chain multiple PCA9685 boards together to control up to 992(!) PWM outputs all together. The PCA9685 has a built in clock, so the Jetson does not have to continously send signals to the device. Adafruit adds several other niceties which makes this a great alternative to other solutions.
In addition, the breakout board can also send PWM pulses to LEDs so that you can dim them. The board has built in resistors for the LEDs so you don’t have to worry about that either.
PCA9685 Breakout Board – Adafruit 16-Channel 12-bit PWM/Servo Driver – I2C interface – PCA9685
The following parts were used in the video for the demonstration to give you a feel on how to hook things up. Your design will determine if any of these are necessary or not.
- Robot Geek Pan and Tilt Kit w/ Servos – Available from Trossen Robotics (This kit was used in the video. Your application will determine which analog servos you wish to use).
- Power Jack Adapter (In the video, A female DC Power Jack 5.5mm x 2.1mm CCTV Power Jack Adapter was used).
- Power Adapter for Servo(s) (In the video, a 6V 1A AC Adapter To DC Power Adapter 5.5/2.1mm was used). Note: The selection of the power adapter is dependent on the servos being used. You will need to select something that provides enough power at the correct voltage for your application. This is very important! For example, if this were a “real” application rather than a demo, I would have probably used a 2A adapter.
The PCA9685 is connected to the I2C Gen2 signals on the Jetson J3A1 connector as follows:
GND J3A1-14 -> PCA9685 (GND)
VCC J3A1-16 -> PCA9685 (VCC – 3.3V)
SCL J3A1-18 -> PCA9685 (SCL)
SDA J3A1-20 -> PCA9685 (SDA)
On the PCA9685 breakout board that is a signal labelled V+ which may be used to power the servos. As an alternative, the power may be supplied through the power terminal block. Servos can be power greedy, so you should drive them from a separate power source rather than from the Jetson.
In the example, two servos are connected to the PCA9685 board. On the pan/tilt mechanism, the lower servo is connected to channel 0 and the upper servo is on channel 1. Here are some pics:
Software Setup and Installation
Once the board is wired up, turn the Jetson TK1 on.
In order to be able inspect the PCA9685, you may 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 0x40, which is the default address of the PCA9685. If you have soldered the address pins on the PCA9685 (as is the case if you are using multiple boards chained together) you should see the appropriate address.
There is a PCA9685 driver available in the JHPWMDriver repository on the JetsonHacks Github account. To install:
$ git clone https://github.com/jetsonhacks/JHPWMDriver.git
$ cd JHPWMDriver
$ cd example
The example is specifically for the pan and tilt mechanisms servos shown in the video, but can be used as a guide for creating your own example code. In the source file ‘servoExample.cpp’, uncomment the lines:
// int servoMin = 120 ;
// int servoMax = 720 ;
and change the values to those appropriate for your servo. Good starting points are 150/600 for initial exploration. Because servos are analog, these vary from model to model, and possibly device to device.
Once you are satisfied:
will build the example. To run the example:
$ sudo ./servoExample
The ‘sudo’ is required to gain permission for the I2C bus from user space.
At this point, all sorts of magic happens! Well, to manage expectations, the servos move around a bit with the demo code.
Equipment and Supplies
- A soldering iron, in the video a Hakko FX888D-23BY Digital Soldering Station was used. The tip of the soldering iron used is the one included with the product.
- Solder, in the video 60/40 lead free solder was used.
Note: For the lead free solder, the iron was set at 750 degrees fahrenheit.
Note: A fan or fume extractor (such as the Hakko FA400-04 Bench Top ESD-Safe Smoke Absorber) should be used to avoid breathing soldering fumes.
- Hookup wire (In the video Hook up Wire – 22 Gauge was used).
- Breadboard (In the video, a Solderless BreadBoard, 400 tie-points, 4 power rails was used)
New to electronics? This is a pretty easy project, looky here: Electronics Tutorials for some introductory material on how to start becoming a master.
Adding a servo or 900 to the Jetson is straightforward using this approach. The nice thing is that you can keep your code base running on one machine, and not have to worry about intervening protocols or communication channels amongst multiple machines. This is useful for a myriad of projects.
Thanks for the tutorial! This would be about the same with the TX1 board, correct?
Very similar: https://jetsonhacks.com/2016/01/11/imu-and-pwm-driver-over-i2c-for-nvidia-jetson-tx1/
Thanks for reading!
Yay! Got a response from Rover with the Sabertooth motor controller, with the Jetson TX1. Now to refine his response for driving, and to get it to work with the joystick.
Cool! Let us know when you have a video or some pictures.
Thanks again, I got some generic Chinese PCA9685s. I have 32 of them rigged to 512 sg9 micro servos. If you want to see a 1/4 size prototype demo, here it is: https://youtu.be/TdlfXrj6fBI.
I really appreciate your blog. If you ever want to collaborate on something, email me.
That looks like a fun project! Sounds like quite a bit of wiring to build. Thanks for taking the time to share, and thanks for reading!
Hi! I’ve followed this exact guide and also looked at the one where you use the IMU. For some reason nothing happens when I run the example program and no errors occur from what I can see from what is printed in the terminal. I’ve confirmed that bytes are getting written by printing a message every time it succeeds to write a byte. Does anyone have an idea of what can be wrong?
Do you see an entry at the address 0x40 when you run:
$ sudo i2cdetect -y -r 1
What version of L4T are you using?
I follow you and I would like to thank you for all your work !
According this project, I tried to do it on the TX1, and I have some troubles with it, like segmentation errors.
Ok for the 0x40 I2C address of the PCA9685, but it seems it’s quite different on the TX1.
Do you know how to setup the TX1 just to drives the servos (Without the IMU and QT) ?
Thanks for your help and support.