R2D2 Arm Connected to RPI3

RPI3
You can use the RPI3 to use the servos. But the servo power will need to separte from the RPI3. The RPI3’s 5V is not enough to use servos long term. For initial testing they will work. But what you will find is the servos will glitch if connected to the RPI3’s header. The RPI3 causes the glitches. So eventually you need to find an alternative way to run the servos. There are two options I had on hand: a Maestro Mirco and PCA9685.
I included some basic code to just make the servo work. I also added the actual code I used to control the arms through the RPI3.
Read here on the Flask UI setup.
Function for Angle to Duty Cycle
The difficult part with controlling the servo with a RPI3 is the value you use to move the servo. The value is given as a duty cycle. I looked around how to convert an angle to duty cycle. I finally found one that worked with my servos. I am using Tower Pro MG995. This function should work for must people, but you can change it if needed.
@staticmethod
def calc_duty_cycle_from_angle(angle):
"""
Calculate the duty cycle based off the angle given. Then
move the servo based off this angle.
:param angle:
:return: Duty cycle for servo based off angle.
"""
#return ((angle / 180.0) + 1.0) * 5.0
return angle / 18.0 + 3.0
Schematic
Connect the servos to the RPI3 directly.
Servo Color Code
Brown = GND
Red = Power
Orange = Signal
Pinout
Orange -> Pin 7 (RPI3 GPIO 4)
Red -> Pin 2 (RPI3 5V)
Brown -> Pin 6 (RPI3 GND)

Video
RPI3 Running the Servos
Code
https://github.com/ricoai/R2D2/blob/master/controls/rpi3_servo_control.py
import RPi.GPIO as GPIO
import time
import sys
class Rpi3ServoControl:
"""
Use the RPI3 to control the servos.
"""
def __init__(self, servo_pin, init_angle=0.0):
self.servo_pin = servo_pin
self.gpio_pin = None
self.last_angle = 0.0
self.setup_pin() # Setup GPIO pin
self.set_angle(init_angle)
def setup_pin(self):
"""
Setup the GPIO pin. Use the GPIO pin given in the constructor.
:return:
"""
GPIO.setmode(GPIO.BCM) # Setup GPIO pin to BCM
GPIO.setup(self.servo_pin, GPIO.OUT) # Set GPIO pin to output
self.gpio_pin = GPIO.PWM(self.servo_pin, 50) # GPIO PWM with 50Hz
self.gpio_pin.start(2.5) # Initialization
def shutdown(self):
"""
Shutdown the object. This will properly shutdown everything.
:return:
"""
self.gpio_pin.stop()
GPIO.cleanup()
def center(self):
"""
Center the servo.
:return:
"""
self.set_angle(0.0) # CENTER (7.5)
def set_angle(self, angle):
"""
Set the servo to the given angle.
:param angle: Angle to move the servo
:return:
"""
if angle > 180:
angle = 180
if angle < 0:
angle = 0
# Cacluate the duty cycle to move to that angle
dc = Rpi3ServoControl.calc_duty_cycle_from_angle(angle)
print("Pin: " + str(self.servo_pin) + " Angle: " + str(angle) + " DC: " + str(dc))
# Move the servo
self.gpio_pin.ChangeDutyCycle(dc)
time.sleep(0.1)
# Record the last angle
self.last_angle = angle
@staticmethod
def calc_duty_cycle_from_angle(angle):
"""
Calculate the duty cycle based off the angle given. Then
move the servo based off this angle.
:param angle:
:return: Duty cycle for servo based off angle.
"""
#return ((angle / 180.0) + 1.0) * 5.0
return angle / 18.0 + 3.0
if __name__ == '__main__':
if len(sys.argv) > 1:
print("Using Servo Pin " + sys.argv[1])
rpi3_servo = Rpi3ServoControl(int(sys.argv[1]))
else:
print("Using Servo Pin 4")
rpi3_servo = Rpi3ServoControl(4)
if len(sys.argv) > 2:
angle_list = sys.argv[2:]
print("Angles to try: " + str(sys.argv[2:]))
for idx in range(len(angle_list)):
rpi3_servo.set_angle(float(angle_list[idx]))
time.sleep(0.5)
rpi3_servo.shutdown()
Basic Code
In this example, I connected the servo signal pin to RPI3 GPIO pin 4. This will then open and close the servo.
import RPi.GPIO as GPIO
import time
servoPIN = 4
GPIO.setmode(GPIO.BCM)
GPIO.setup(servoPIN, GPIO.OUT)
p = GPIO.PWM(servoPIN, 50) # GPIO 17 for PWM with 50Hz
p.start(2.5) # Initialization
try:
while True:
p.ChangeDutyCycle(5)
time.sleep(0.5)
p.ChangeDutyCycle(7.5) # CENTER
time.sleep(0.5)
p.ChangeDutyCycle(10)
time.sleep(0.5)
p.ChangeDutyCycle(12.5) # 180 degrees
time.sleep(0.5)
p.ChangeDutyCycle(10)
time.sleep(0.5)
p.ChangeDutyCycle(7.5) # CENTER
time.sleep(0.5)
p.ChangeDutyCycle(5)
time.sleep(0.5)
p.ChangeDutyCycle(2.5) # 0 degrees
time.sleep(0.5)
except KeyboardInterrupt:
p.stop()
GPIO.cleanup()
Parts List
The R2D2 arm holder can be found at http://astromech.com/