
Pour contrôler les 20 servomoteurs de l’hexapode, j’ai acheté deux cartes 16-Channel 12-bit PWM chez Adafruit. C’est la solution la moins couteuse tout en restant dans les performances. Et il est possible de mettre en série jusqu’à 62 cartes, soit 992 servomoteurs!
Installation du protocole I2C sous Debian
Pour contrôler les servomoteurs via la carte d’Adafruit 16 channels, il nous faut installer le protocole I2C:
$ sudo apt-get install i2c-tools
Puis charger les modules dans le noyau linux :
$ sudo modprobe i2c-dev
$ sudo modprobe i2c-bcm2708
et pour la partie programmation il nous faudra python-smbus:
$ sudo apt-get install python-smbus
Câblage de la carte Adafruit 16 channels avec les servomoteurs et le raspberry pi
Mieux vaut un bon schéma qu’un long discourt!

Adafruit utilise une breadboard dans son tutoriel, mais pour les non initiés, cela complique le montage, alors que 4 fils suffisent.
Faites attention à bien alimenter la carte Adafruit sur VCC en 3.3V et non 5V. Et alimentez directement la carte Adafruit, en son centre, avec une alimentation externe comprise en 5V-7V suivant vos servomoteurs.
Vérification de la communication i2C
Si vous avez bien tout connecté, il est possible de détecter la carte Adafruit depuis le raspberry pi avec la commande :
$ sudo i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: 70 -- -- -- -- -- -- --
La réponse indique que la carte Adafruit se trouve à l’adresse 0×40, ce qui correspond en binaire à 1000000, soit la première adresse.
Tout est prêt pour accéder à I2C et SMBus via python.
Contrôle d’un servomoteur via Python sur Raspberry Pi
J’ai repris l’exemple d’Adafruit qui se compose d’un script principal “Servo_Example.py” faisant appel à 2 scripts : Adafruit_PWM_Servo_Driver.py et Adafruit_I2C.py.
$ cd /home/pi/Desktop/
$ nano Servo_Example.py
#!/usr/bin/python
from Adafruit_PWM_Servo_Driver import PWM
import time
# ===========================================================================
# Example Code
# ===========================================================================
# Initialise the PWM device using the default address
# bmp = PWM(0×40, debug=True)
pwm = PWM(0×40, debug=True)
servoMin = 150 # Min pulse length out of 4096
servoMax = 600 # Max pulse length out of 4096
def setServoPulse(channel, pulse):
pulseLength = 1000000 # 1,000,000 us per second
pulseLength /= 60 # 60 Hz
print “%d us per period” % pulseLength
pulseLength /= 4096 # 12 bits of resolution
print “%d us per bit” % pulseLength
pulse *= 1000
pulse /= pulseLength
pwm.setPWM(channel, 0, pulse)
pwm.setPWMFreq(60) # Set frequency to 60 Hz
while (True):
# Change speed of continuous servo on channel O
pwm.setPWM(0, 0, servoMin)
time.sleep(1)
pwm.setPWM(0, 0, servoMax)
time.sleep(1)
$ chmod +x Servo_Example.py
Puis
$ nano Adafruit_PWM_Servo_Driver.py
#!/usr/bin/python
import time
import math
from Adafruit_I2C import Adafruit_I2C
# ============================================================================
# Adafruit PCA9685 16-Channel PWM Servo Driver
# ============================================================================
class PWM :
i2c = None
# Registers/etc.
__SUBADR1 = 0×02
__SUBADR2 = 0×03
__SUBADR3 = 0×04
__MODE1 = 0×00
__PRESCALE = 0xFE
__LED0_ON_L = 0×06
__LED0_ON_H = 0×07
__LED0_OFF_L = 0×08
__LED0_OFF_H = 0×09
__ALLLED_ON_L = 0xFA
__ALLLED_ON_H = 0xFB
__ALLLED_OFF_L = 0xFC
__ALLLED_OFF_H = 0xFD
def __init__(self, address=0×40, debug=False):
self.i2c = Adafruit_I2C(address)
self.address = address
self.debug = debug
if (self.debug):
print “Reseting PCA9685″
self.i2c.write8(self.__MODE1, 0×00)
def setPWMFreq(self, freq):
”Sets the PWM frequency”
prescaleval = 25000000.0 # 25MHz
prescaleval /= 4096.0 # 12-bit
prescaleval /= float(freq)
prescaleval -= 1.0
if (self.debug):
print “Setting PWM frequency to %d Hz” % freq
print “Estimated pre-scale: %d” % prescaleval
prescale = math.floor(prescaleval + 0.5)
if (self.debug):
print “Final pre-scale: %d” % prescale
oldmode = self.i2c.readU8(self.__MODE1);
newmode = (oldmode & 0x7F) | 0×10 # sleep
self.i2c.write8(self.__MODE1, newmode) # go to sleep
self.i2c.write8(self.__PRESCALE, int(math.floor(prescale)))
self.i2c.write8(self.__MODE1, oldmode)
time.sleep(0.005)
self.i2c.write8(self.__MODE1, oldmode | 0×80)
def setPWM(self, channel, on, off):
”Sets a single PWM channel”
self.i2c.write8(self.__LED0_ON_L+4*channel, on & 0xFF)
self.i2c.write8(self.__LED0_ON_H+4*channel, on >> 8)
self.i2c.write8(self.__LED0_OFF_L+4*channel, off & 0xFF)
self.i2c.write8(self.__LED0_OFF_H+4*channel, off >> 8)
$ chmod +x Adafruit_PWM_Servo_Driver.py
Puis
$ nano Adafruit_I2C.py
#!/usr/bin/python
import smbus
# ===========================================================================
# Adafruit_I2C Base Class
# ===========================================================================
class Adafruit_I2C :
def __init__(self, address, bus=smbus.SMBus(0), debug=False):
self.address = address
self.bus = bus
self.debug = debug
def reverseByteOrder(self, data):
”Reverses the byte order of an int (16-bit) or long (32-bit) value”
# Courtesy Vishal Sapre
dstr = hex(data)[2:].replace(‘L’,”)
byteCount = len(dstr[::2])
val = 0
for i, n in enumerate(range(byteCount)):
d = data & 0xFF
val |= (d << (8 * (byteCount – i – 1)))
data >>= 8
return val
def write8(self, reg, value):
”Writes an 8-bit value to the specified register/address”
try:
self.bus.write_byte_data(self.address, reg, value)
if (self.debug):
print(“I2C: Wrote 0x%02X to register 0x%02X” % (value, reg))
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
def writeList(self, reg, list):
”Writes an array of bytes using I2C format”
try:
self.bus.write_i2c_block_data(self.address, reg, list)
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
def readU8(self, reg):
”Read an unsigned byte from the I2C device”
try:
result = self.bus.read_byte_data(self.address, reg)
if (self.debug):
print “I2C: Device 0x%02X returned 0x%02X from reg 0x%02X” % (self.address, result & 0xFF, reg)
return result
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
def readS8(self, reg):
”Reads a signed byte from the I2C device”
try:
result = self.bus.read_byte_data(self.address, reg)
if (self.debug):
print “I2C: Device 0x%02X returned 0x%02X from reg 0x%02X” % (self.address, result & 0xFF, reg)
if (result > 127):
return result – 256
else:
return result
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
def readU16(self, reg):
”Reads an unsigned 16-bit value from the I2C device”
try:
hibyte = self.bus.read_byte_data(self.address, reg)
result = (hibyte << 8) + self.bus.read_byte_data(self.address, reg+1)
if (self.debug):
print “I2C: Device 0x%02X returned 0x%04X from reg 0x%02X” % (self.address, result & 0xFFFF, reg)
return result
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
def readS16(self, reg):
”Reads a signed 16-bit value from the I2C device”
try:
hibyte = self.bus.read_byte_data(self.address, reg)
if (hibyte > 127):
hibyte -= 256
result = (hibyte << 8) + self.bus.read_byte_data(self.address, reg+1)
if (self.debug):
print “I2C: Device 0x%02X returned 0x%04X from reg 0x%02X” % (self.address, result & 0xFFFF, reg)
return result
except IOError, err:
print “Error accessing 0x%02X: Check your I2C address” % self.address
return -1
$ chmod +x Adafruit_I2C.py
Il ne reste plus qu’à lancer le programme en tant qu’administrateur :
$ sudo python Servo_Example.py
Share the post "Projet Bagheera – 08 – controle des servos moteur sur Raspberry Pi"
2 comments
Yaug
2013/01/14 at 15:15 (UTC 1) Link to this comment
Salut,
Pour information, quels servo-moteur as tu acheté et comptes tu utiliser ?
Merci
honeyshell
2013/01/27 at 14:43 (UTC 1) Link to this comment
Bonjour Yaug, j’ai acheté mes servos chez hobbyking, ce sera pour le fonctionnement des pattes et de la webcam de mon projet d’hexapod.