In the beginning I had no external PWM module and my Raspberry Pi3 has only 2 native PWM output. So I have used PigPio module as a software solution. It was a good temporary solution even though the PWM had an interference with my room's lights.
So I've ordered a PCA9685 16 Channel PWM Servo motor Driver. The Raspberry Pi can communicate with this cheap module via I2C protocol. So now I have 16 channels. :D
The new module needs new wiring and new code. I followed this post: Adafruit 16 Channel Servo Driver with Raspberry Pi. It was fine and easy. So I moved on to write the new code with extra features like clapping and bowing. (Do not forget to install the Adafruit_PCA9685 as it was written in that adafruit post.) So here my new code:
import time, sys
import Adafruit_PCA9685
class Servo:
min = 100
max = 480
pwm = Adafruit_PCA9685.PCA9685()
pwm = Adafruit_PCA9685.PCA9685(address=0x70, busnum=1)
pwm.set_pwm_freq(50)
def __init__(self, channel):
self.channel = channel
pass
def setLimits(min, max):
self.min = min
self.max = min
pass
def set_pwm(self, on, off):
self.pwm.set_pwm(self.channel, on, off)
pass
def setDegree(self, degree):
oneDegree = (self.max - self.min) / 180
self.set_pwm(0, self.min + int(oneDegree * degree))
pass
def move(self, degreeFrom, degreeTo, speed = 0.01):
if degreeFrom < degreeTo:
step = 1
else:
step = -1
for degree in range(degreeFrom, degreeTo, step):
self.setDegree(degree)
time.sleep(speed)
pass
class Arm(Servo):
def __init__(self, channel, limits):
self.channel = channel
self.limits = limits
pass
def wave(self):
self.move(self.limits[1],self.limits[3], 0.002)
self.move(self.limits[3],self.limits[1], 0.004)
pass
def reset(self):
self.setDegree(self.limits[1])
pass
class Arms():
def __init__(self):
self.rightLimits = [20, 50, 155, 160] # -, normal, clap, full
self.leftLimits = [140, 110, 35, 10]
self.Left = Arm(3,self.leftLimits)
self.Right = Arm(1,self.rightLimits)
pass
def clap(self, speed = 0):
leftDistance = self.leftLimits[1] - self.leftLimits[2]
rightDistance = self.rightLimits[2] - self.rightLimits[1]
if leftDistance > rightDistance:
distance = leftDistance
else:
distance = rightDistance
for count in range(0, distance):
self.Right.setDegree(self.rightLimits[1] + count)
self.Left.setDegree(self.leftLimits[1] - count)
time.sleep(speed)
for count in range(distance, 0, -1):
self.Right.setDegree(self.rightLimits[1] + count)
self.Left.setDegree(self.leftLimits[1] - count)
time.sleep(speed)
pass
def claps(self, quantity):
for c in range(0,quantity):
self.clap()
pass
class Head():
def __init__(self):
self.Horizontal = Servo(2)
self.Vertical = Servo(0)
self.horizontalBase = 90
self.verticalBase = 160
pass
def shake(self):
limits = [40,self.horizontalBase,140]
speed = 0.002
self.Horizontal.move(limits[0],limits[2],speed)
self.Horizontal.move(limits[2],limits[0],speed)
self.Horizontal.move(limits[0],limits[1],speed)
pass
def nod(self):
limits = [self.verticalBase,130]
self.Vertical.move(limits[0],limits[1], 0.01)
self.Vertical.move(limits[1],limits[0], 0.01)
pass
def bow(self):
limits = [self.verticalBase,100]
self.Vertical.move(limits[0],limits[1],0.05)
self.Vertical.move(limits[1],limits[0],0.01)
pass
def reset(self):
self.Horizontal.setDegree(self.horizontalBase)
self.Vertical.setDegree(self.verticalBase)
pass
Arms = Arms()
Head = Head()
if len(sys.argv) > 1:
command = sys.argv[1]
if command == "no":
Head.shake()
elif command == "reset":
Head.reset()
Arms.Left.reset()
Arms.Right.reset()
elif command == "yes":
Head.nod()
Head.nod()
elif command == "bow":
Head.bow()
elif command == "right":
Arms.Left.wave()
elif command == "left":
Arms.Right.wave()
elif command == "clap":
Arms.claps(3)
else:
print "Invalid command"
else:
print "Arguments needed"
You can give commands to Balambér through arguments of the command. So he is happy again. :D
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.