i2cpwm_board  0.5.1
ROS Package for PCA9685 based 16 channel PWM Board with I2C Interface
i2cpwm_board Documentation

Controller for I2C interfaced 16 channel PWM boards with PCA9685 chip
Bradan Lane Studio info@.nosp@m.brad.nosp@m.anlan.nosp@m.e.co.nosp@m.m
Copyright (c) 2016, Bradan Lane Studio
Licensed under GPLv3


The file is broken into sections:

The code is currently authored in C and should be rewritten as proper C++.

This documentation refers to 'servo' and 'RC servo' but is equally applicable to any PWM or PPM controlled DC motor.

All published services and topics use a one-based count syntax. For example, the first servo is '1' and the default board is '1'. The hardware uses zero-based values. For example the first channel on the 16 channel 12-bit PWM board is '0' and the first I2C board is '0' with address 0x40. The switch from one-based to zero-based is done at the lowest level of this code. All public interactions should assume one-based values.

WARNING: The code has only been tested with a single board using the default I2C address of 0x40. Once testing has been done with additional configurations, this warning will be removed or amended.


While the PCA9685 chip and related boards are called "PWM" for pulse width modulation, there use with servos is more accurately PPM for pulse position modulation.

For standard 180 degree servos with a motion arc of ±90 degrees the pulse moves the servo arm to specifc position and holds it. For continuous motion servos, the pulse moves the servo at a specific speed.

The documentation will refer to positon, speed or position/speed. These are interchangeable as the two terms are dependent on whether the servo is a fixed rotation servo or a continuous rotation servo and independent of the board itself.

Analog RC servos are most often designed for 20ms pulses. This is achieved with a frequency of 50Hz. This software defaults to 50Hz. Use the set_pwm_frequncy() to change this frequency value. It may be necessary or convenient to change the PWM frequency if using DC motors connected to PWM controllers. It may also be convenient if using PWM to control LEDs.

A commonly available board is the Adafruit 16 channel 12-bit PWM board or the similarly named HAT. There are similar boards as well as clones. All of these boards use the PCA9685 chip. Not all boards have been tested.

The PWM boards drive LED and servos using pulse width modulation. The 12 bit interface means values are in the range of 0..4096. The pulse is defined as a start value and end value. When driving servos, the start point is typically 0 and the end point is the duration.

FYI: If using more than one PWM board or when using a board with an I2C address other than the default 0x40, the set_active_board() service must be used before using other services or topics from this package.


The tolerance of the resistors in RC servos means each servo may have a slightly different center point.

The servos_absolute() topic controls servos with absolute pulse start and stop values. This topic subscriber is not generally useful in robot operations, however it is convenient for testing and for determining configuration values. Use this topic to determine the center position for a standard servo or the stop position for a continuous servo.

Also use this topic to determine the range of each servo - either the ±90 postion for a standard servo or the max forward and reverse speed for a continuous rotation servo.

note: The centering value and range of servos is dependent on the pulse frequency. If you use set_pwm_frequency() to change the system value, you will need to determine new center and range values.

The servos_proportional() topic controls servos through their range of motion using values between -1.0 and 1.0. Use the config_servos() service to set the center values, range values, and directions of rotation for servos. This enables servo motion to be generalized to a standard proportion of ±1.0. Use of the config_servos() service is required before proportional control is available.


In addition to absolute and proportional topics for controling servos, this package provides support for the geometry 'Twist' message. The servos_drive() topic handles the calculations to convert linear and angular data to servo drive data.

Drive mode requires details for each servo. Use of the config_servos() before using drive mode.

The geometry_msgs::Twist providesf linear and angular velocity measured in m/s (meters per second) and r/s (radians per second) respectively. To perform the necessary calculations, data about the drive system is required. Use config_drive_mode() to provide the RPM of the drive wheels, their radius, and the track distance between left and right. These values determine speed and turn rates.

Specifiy the desired drive mode with the mode property to cofig_drive_mode(). This package supports three drive modes:

  1. ackerman - A single velocity drive using one or more servos with a non-drive servo controlling steering.
  2. differential - Skid steer or track steer using one or more servos for each of the left and right sides. The result is full speed forward or reverse, min/max radius turns, and the ability to perform zero-radius turns
  3. mecanum - Independent drive on all four wheel capable of holonomic drive - moving in any combination of forward, reverse, turning, and sideways. The servos are assigned positons for left-front, right-front, left-rear, and right-rear wheels. This mode supports similar drive characteristics to differential drive with the additional of lateral motion.

The servos on the PWM board are assigned to their respective drive positons using the config_drive_mode() service. The applicable servos are assigned positions as follows:

positon ackerman differential mecanum
position 1 corresponds to drive left left-front
position 2 corresponds to right right-front
position 3 corresponds to left-rear
position 4 corresponds to right-rear

The drive topic requires that use of both the config_servos() service and config_drive_mode() service before drive mode will result in expected behavior.

All non-drive servos may still be operated with the proportion or absolute topics.

Note: This controller does not implement encoders for PWM motors. There is no guarantee that the drive velocity will exactly match the Twist message input. While this may not be acceptable for a commercial or scientific application, it may not be of convern for education and amatuer competitions. Encoders could be added and feedback applied to the PWM values. Additionally, when drive control is a product of positional feedback - such as line following and navigation via camera vision - drive encoders are usually not required.

The stop_servos() service is provided as convenience to stop all servos and place then is a powered off state. This is different from setting each servo to its center value. The stop service is useful as a safety operation.


Basic testing is available from the command line. Start the I2C PWM node with roslaunch i2cpwm_board i2cpwm_node.launch (or roscore and rosrun i2cpwm_board i2cpwm_board) and then proceed with example commands contained within the documentation for each service and topic subscriber.