This is a cache of https://www.96boards.org/blog/arduino-vs-pca9685/. It is a snapshot of the page at 2024-12-26T04:14:08.562+0000.
Out with Arduino, In with i2c and PCA9685 | OpenCV on RB3 Pt. 7 | Qualcomm RB3 Robotic Arm Project - 96Boards

Out with Arduino, In with i2c and PCA9685 | OpenCV on RB3 Pt. 7 | Qualcomm RB3 Robotic Arm Project

Sahaj Sarup
|

Introduction

As per my last blog, due to pending enablement of i2c driver in the official debian image we were still using Arduino over USB-UART to control the actual servos.

This meant that the servos weren’t “directly” being controlled by the RB3. Rather the RB3 was sending somewhat of a coordinates to the Arduino which in turn controlled the servos.

As Linaro Connect SAN19 was coming up, the i2c drivers got enabled and now we are able to control the servos using a PCA9685 chip which is a i2c to pwm controller.

Changes to the code

Some major but repetitive changes were required. For the purpose of talking to the PCA chip, we are using this library by Adafruit.

We also need to replicate some Arduino functions such as map and pulsewidth, both on with are y]used together to convert angle values to pwm values to control the servos.

def map_ard(x, in_min, in_max, out_min, out_max):
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def pulseWidth(angle):
    pulse_wide = map_ard(angle, 0, 180, min_pulse, max_pulse)
    analog_value = int(float(pulse_wide) / 1000000 * frequency * 4096)
    return analog_value

Differences between the Arduino and I2C code

Lets take the first while loop for example, this loop is responsible for moving the arm left or right on the X axis to line up with the object.

With Arduino:

            while ( ( ( loca[0] >= ((600/2)+10) ) or ( loca[0] <= ((600/2)-10) ) ) ):
                print("Required Object at X:" + str(loca[0]) + " Y: " + str(loca[1]))
                shape_data_str = client.get('vision_data')
                shape_data = json.loads(shape_data_str)
                loca[0] = shape_data[col][0][0]
                loca[1] = shape_data[col][0][1]
                if (loca[0] <= ((600/2)+10)):
                    print("d")
                    serialPort.write(str.encode('d'))
                elif (loca[0] >= ((600/2)+10)):
                    print("a")
                    serialPort.write(str.encode('a'))
                time.sleep(0.1)

With PCA9685

            while ( ( ( loca[0] >= ((600/2)+10) ) or ( loca[0] <= ((600/2)-10) ) ) ):
                print("Required Object at X:" + str(loca[0]) + " Y: " + str(loca[1]))
                shape_data_str = client.get('vision_data')
                shape_data = json.loads(shape_data_str)
                loca[0] = shape_data[col][0][0]
                loca[1] = shape_data[col][0][1]
                if (loca[0] <= ((600/2)+10)):
                    if (i != 0):
                        pwm.set_pwm(0, 0, pulseWidth(i))
                        i = i - 1
                elif (loca[0] >= ((600/2)+10)):
                    if (i != 165):
                        pwm.set_pwm(0, 0, pulseWidth(i))
                        i = i + 1
                time.sleep(0.1)

As you can see the serialPort.write(str.encode('a')) statement changed to pwm.set_pwm(0, 0, pulseWidth(i)). This changed the behavior of telling the arduino to move left by 1 degree into directly sending the pwm signals to the servo to move it by 1 degree.

The remaining code has been changed in a similar manner.

To take a look at the entire code, you can check out my repo for the time being as we start to close out this variant of the Robotic Arm project by the end of the week.

Repository: https://github.com/ric96/RB3-RoboticArm/tree/i2c


First life of PWM using PCA9685 on the RB3, image taken during Linaro Connect SAN19

This article is Part 9 in a 10-Part Series.

comments powered by Disqus