Taillieu.Info

More Than a Hobby..

Use the Adafruit PCA9685 with a Raspberry PI

Use the Adafruit PCA9685 with a Raspberry PI, in Java Raspberry PI
to drive up to 16 servos

The Servo Driver we are talking about here is the Adafruit 16-Channel 12-bit PWM/Servo Driver - I2C interface - PCA9685.

The original tutorial from Adafruit is available here. The language it uses is Python. 

This board has an I2C (pronounce I "square" C) interface, that needs to be enabled on the Raspberry PI. 
I2C stands for Inter-Integrated-Circuit. 
Arduino & Adafruit provide python libraries that go along with their components. The code we present here is in big part an adaptation of this code.

Enable I2C on the Raspberry PI

We will show how to enable I2C on a Model B Raspberry PI. There is a lot of documentation on the web on how to do it on whatever version on the RasPI you have. We are not going to duplicate the web in this document... 
We will need to edit several configuration files. Use the editor you prefer (nanovigedit, ...), as root (sudo).

  1. Edit /etc/modules 
    Make sure its content eventually looks like this:
      i2c-bcm2708
      i2c-dev
              
    Save your modifications, if you have done any.
  2. Install some I2C Utilities (in python) 
     Prompt> sudo apt-get install python-smbus
     Prompt> sudo apt-get install i2c-tools
              
  3. Edit /etc/modprobe.d/raspi-blacklist.conf, comment the two lines it contents: 
    Before:
     blacklist spi-bcm2708
     blacklist i2c-bcm2708
              

    After:
     # blacklist spi-bcm2708
     # blacklist i2c-bcm2708
              
    Save your modifications, if you have done any.
  4. By now (the PCA9685 needs to be wired for that), you should be able to run the i2cdetect utility, which will will use to know the address of the servo driver:
     Prompt> sudo i2cdetect -y 1
          0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
     00:          -- -- -- -- -- -- -- -- -- -- -- -- --
     10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     70: 70 -- -- -- -- -- -- --
              
    As seen above, the I2C addresses range from 0x03 to 0x77 (binary 0000011 to 1110111). This way, several boards can be used simultaneously from the RasPI, as long as their I2C addresses are different, even if the GPIO interface pins are connected to several different boards. 
    For example, if you have connected
    • A PCA9685 (servo driver)
    • A BMP180 (Pressure, Altitude, Temperature)
    • A LSM303 (Magnetometer & Accelerometer)
    you would have
     Prompt> sudo i2cdetect -y 1
          0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
     00:          -- -- -- -- -- -- -- -- -- -- -- -- --
     10: -- -- -- -- -- -- -- -- -- 19 -- -- -- -- 1e --
     20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     70: 70 -- -- -- -- -- -- 77
              
    where, in addition to the above,
    • 0x19 would be the magnetometer address (LSM303)
    • 0x1e would be the accelerometer address (LSM303)
    • 0x77 would be the BMP180 address

Wiring

The connection setting is quite simple.

PCA9685Raspberry PI
VCC 1. 3.3 VDC Power
GND 6. 0V (Ground)
SDA 3. SDA0 (I2C)
SCL 5. SCL0 (I2C)
Raspberry PI P1 Connector map Click to enlarge Click to enlarge 
The Raspberry PI, connected to a PCA9685, with 2 servos.

This diagram shows the name of the pins you want to use on the GPIO Connector of the Raspberry PI. As we said before, we need to use the pins 1, 3, 5, and 6.

Programming

You will need to know what address to talk to to reach the PCA9685. Run the i2cdetect utility.

 Prompt> sudo i2cdetect -y 1
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 00:          -- -- -- -- -- -- -- -- -- -- -- -- --
 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
 70: 70 -- -- -- -- -- -- --
      

We will use the 0x40 address to reach the PCA9685. 
The Java code we are interested in is in the class named adafruiti2c.AdafruitPCA9685. Check it out in the repository. We are going to comment only on the main method of this class, which is a basic example. It assumes that 2 servos are connected to the PCA9685, on the 15 and 14 slots.
The PCA9685 has 16 such slots, numbered - on the board - from 0 to 15. See them on the picture at the top of this document. The slots we are talking about are the 16 columns of 3 holes drilled at the bottom of the board. Their number is printed on top of each column of 3 holes.

  ...
  public static void main(String[] args)
  {
    AdafruitPCA9685 servoBoard = new AdafruitPCA9685();   // 0x40 is the default address
    servoBoard.setPWMFreq(60); // Set frequency to 60 Hz
    int servoMin = 150;   // Min pulse length out of 4096
    int servoMax = 600;   // Max pulse length out of 4096
    
    final int CONTINUOUS_SERVO_CHANNEL = 14;
    final int STANDARD_SERVO_CHANNEL   = 15;
    
    for (int i=0; i<10; i++)
    {
      System.out.println("i=" + i);
      servoBoard.setPWM(STANDARD_SERVO_CHANNEL,   0, servoMin);
      servoBoard.setPWM(CONTINUOUS_SERVO_CHANNEL, 0, servoMin);
      waitfor(1000);
      servoBoard.setPWM(STANDARD_SERVO_CHANNEL,   0, servoMax);
      servoBoard.setPWM(CONTINUOUS_SERVO_CHANNEL, 0, servoMax);
      waitfor(1000);
    } 
    servoBoard.setPWM(CONTINUOUS_SERVO_CHANNEL, 0, 0); // Stop the continuous one
    System.out.println("Done with the demo.");
  }
  ...
      

This code loops 10 times and makes the servos go from a value of 150 to a value of 600, and vice versa. It waits for 1000 milliseconds between each message to the servos. 
Notice the two int variables, CONTINUOUS_SERVO_CHANNEL and STANDARD_SERVO_CHANNEL
For this demo, the standard servo we use is the Standard servo - TowerPro SG-5010 - 5010
As seen in its documentation, the servo rotates on 180°, 90° on each side. Position "0" (1.5ms pulse) is middle, "90" (~2ms pulse) is all the way to the right, "-90" (~1ms pulse) is all the way to the left. 
We see we use a 60 Hz frequency. This means we will have 60 cycles per second. Each cycle contains 4096 ticks. 
The value minServo is 150. 
The value maxServo is 600. 
A full cycle (of 4096 ticks) at 60 Hz will take 1 / 60 ~ 16 ms. 
150 ticks would take 150 / (60 * 4096) seconds, which is ~ 0.61 ms. 
600 ticks would take 600 / (60 * 4096) seconds, which is ~ 2.44 ms. 

More generically

  • TickTime = 1 / (freq * 4096).
  • PulseTime = TickTime * nbTicks.

It is quite easy - and convenient - to put those formulas in a spreadsheet. 
Based on those formulas, we should have:

Pulse Width
in ms
Nb Ticks
1 246
1.5 369
2 492

The values given in the Adafruit tutorial (150 & 600) happens to be a bit different of what the documentation of the servo says..., but they actually work fine, and this is the ones we use in the code:

Pulse Width
in ms
Nb Ticks
1 150
1.5 375
2 600

Running

We run the code from a script named servo:

 #!/bin/bash
 PI4J_HOME=/home/pi/pi4j/pi4j-distribution/target/distro-contents
 CP=./classes
 CP=$CP:$PI4J_HOME/lib/pi4j-core.jar
 sudo java -cp $CP adafruiti2c.AdafruitPCA9685
      
 Prompt> ./servo
      

And here is the result

 Prompt> ./servo
 Connected to bus. OK.
 Connected to device. OK.
 Setting PWM frequency to 60 Hz
 Estimated pre-scale: 100.72526
 Final pre-scale: 101.0
 i=0
 i=1
 i=2
 i=3
 i=4
 i=5
 i=6
 i=7
 i=8
 i=9
 Done with the demo
 Prompt>
              
The console output

And what next?

Drive the Raspberry PI, on its own cart... 
Fuel the Raspberry PI with a solar panel, oriented by servos to face the sun for greater efficiency.

Something to be aware of...

I followed the PWM instructions, came up with several spreadsheets for the calculations, and... it just did not work correctly. 
Both standard and continuous servos are supposed to be triggered with pulses having width ranging from 1 to 2 ms. As seen above, at 60 Hz, that makes 246 to 492 ticks. 
In reality, after many manual trials, for a frequence of 60 Hz, I used:

For the Standard Servo Between 122 & 615 ticks
For the Continuous Servo Between 340 & 410 ticks, stop at 375

Those values are suprisingly different from the theorical ones..., but they work. 
See in the code the classes named adafruiti2c.samples.DemoContinuous and adafruiti2c.samples.DemoStandard
Those are the ones I will use as bases for robotic projects.