Skip to content

grzesiek2201/Adafruit-Servo-Driver-Library-Pi-Pico

Repository files navigation

Adafruit-Servo-Driver-Library-Pi-Pico

This is both a port of Adafruit's Arduino library for the PCA9685 (Adafruit Library) for the Raspberry Pi Pico board and an improvement on the PCA9685 Servo Controller library for Pi Pico (PCA9685 Servo Controller).

Please note it is not a Micropython library (as those have been released by Adafruit Circuitpython library), but a library meant to be used with Pi Pico C/C++ SDK.

Please find doxygen docs here Doxygen docs.

Setup

Include the headers

Copy the repository into your project. Include two files in your main cpp file:

  • #include <PCA9685_servo_driver.h>
  • #include <PCA9685_servo.h>

Change your projects CMakeLists.txt

Add a subdirectory:

add_subdirectory(Adafruit-Servo-Driver-Library-Pi-Pico)    # the argument represents a path to the library directory

Then include the library directory:

target_include_directories(${PROJECT_NAME}
    PRIVATE Adafruit-Servo-Driver-Library-Pi-Pico    # the argument represents a path to the library directory
)

Lastly, link the library:

target_link_libraries(${PROJECT_NAME}
    Adafruit-Servo-Driver-Library-Pi-Pico    # the argument represents the name of the library, as specified in the CMakeLists.txt in the library directory
)

Create necessary objects

  • Create an object of PCA9685_servo_driver type to serve as your interface with the PCA9685 board. PCA9685_servo_driver myController(i2c0);
  • Create an object(s) (depending on the number of servos that are being driven) of PCA9685_servo type to keep track of the servo's parameters and movement. std::vector<PCA9685_servo> myServo = {PCA9685_servo(&myController, 0, 100, 540)};
  • Initialize the servo:
    • set the angle range with setRange(),
    • set operation mode with setMode(),
    • set initial position with setPosition(),
    • set channel number on the board with setAddress(),
    • set duration of movement in constant time mode with setTConstantDuration().
  • In the main() loop, initialize the connection to the PCA9685 with myController.begin();.

Create control loop

Create a loop in which PCA9685_servo.loop() method will be called for each of the controlled servos. Into the loop() method pass an argument with time elapsed since last loop iteration (to keep track of when to move the servo).

while(1)
{
    TEllapsed = TNow - TPrevious;
    for(auto& servo : myServo) servo.loop(TEllapsed);
}

How to control the servo

Movement modes

There are 3 modes:

  • MODE_FAST - moves to the set position immediately, with maximum speed (part of the PCA9685_servo class as _TFastDuration),
  • MODE_TCONSTANT - the movement takes exactly _TConstantDuration microseconds, independent of the length of the movement,
  • MODE_SCONSTANT - the servo moves with a set angular velocity (set with setAngularVelocity()), which means the servo moves one degree after _SConstantPeriod microseconds.

Select a mode with setMode() method.

Set servo position

In order to move the servo, it first needs to get its position changed with setPosition() or setRelativePosition() methods. The argument passed is the position to move to in degrees. It takes effect immediately.

Set servo speed or movement time

In order to change the speed, use the setAngularVelocity() method, providing velocity in deg/s. It changes the speed in both MODE_SCONSTANT and MODE_TCONSTANT modes.

In order to change the movement time, use changeSpeedConstT().

Loop through the movement

After setting the position, it is necessary to call the loop() method repeatedly in order to execute the movement. It needs an argument that counts the time between the last call to the loop() and now in microseconds.

Other functions

Servo status

Each servo keeps track of itself, it's possible to retrieve these states through e.g.:

  • getPosition() retrieves current position in degrees,
  • isMoving() is the servo moving or not.

Callbacks

Each servo can call a function on start or end of movement through binding to function pointer. E.g.

void StopMoveHandler(uint16_t Address) { INTERNAL_LED(0); }
servo.onStopMove = StopMoveHandler;

PWM Pulse length count

In order to properly control the servo, its PWM pulse length count has to be determined. The usual range lies within (100-600), but please find the one matching your particular servo. The best way to do this is by manually changing the lower and upper range by a little bit until it matches the (-90, 90) degree range.

Examples

A simple example can be found in the examples directory alongside a sample CMakeLists.txt file.

Problems and bugs

At the moment there are not any known problems or bugs, please feel free to report them.