Giuseppe Parrello

 

Embedded Servomotore SG90


Introduzione

Con questo progetto andremo a gestire un servomotore TowerPro SG90, usando la scheda di sviluppo FTDI FT232H (di cui esiste una pagina dedicata su questo sito) e la scheda di sviluppo NXP PCA9685 (di cui esiste una pagina dedicata su questo sito).

 

Collegamento

Il servomotore deve essere collegato alla scheda di sviluppo NXP PCA9685. I connettori di collegamento sono elencati qui di seguito:

Immagine Scheda FT232H Scheda PCA9685 Servomotore

FT232H - SG90

AD0 SCL ------
AD1 + AD2 SDA ------
+5V VCC ------
GND GND ------
------ Canale 0 - PWM PWM
+5V ------ VCC
------ Canale 0 - GND GND

 

Codice Python

Per gestire il servomotore, è richiesta la presenza della libreria "PCA9685_FTDI".
Il seguente esempio di codice Python fa ruotare il servomotore usando un comando "throttle" e in seguito un comando "Angle" per ruotare il motore:

# Simple demo of of the PCA9685 PWM servo/LED controller library.
import time

# Import the PCA9685 module.
import pca9685_ftdi

# Initialise the PCA9685 using the default address (0x40).
pwm = pca9685_ftdi.PCA9685_FTDI()

SERVO_FREQ = 50    # Analog servos run at ~50 Hz updates
pwm.setPWMFreq(SERVO_FREQ)  # Analog servos run at ~50 Hz updates

# our servo # counter
servonum = 0

actuation_range = 180
min_pulse       = 750
max_pulse       = 2250
_min_duty       = int((min_pulse * SERVO_FREQ) / 1000000 * 0xFFFF)
max_duty        = (max_pulse * SERVO_FREQ) / 1000000 * 0xFFFF
_duty_range     = int(max_duty - _min_duty)

def set_duty_cycle(value):
    if not 0 <= value <= 0xFFFF:
        raise ValueError("Out of range")
    if value == 0xFFFF:
        #print("set_duty_cycle", value)
        pwm.set_pwm(servonum, 0x1000, 0)
    else:
        value = (value + 1) >> 4
        #print("set_duty_cycle", value)
        pwm.set_pwm(servonum, 0, value)

def set_fraction(value):
    if value is None:
        set_duty_cycle(0)
        return
    if not 0.0 <= value <= 1.0:
        raise ValueError("Must be 0.0 to 1.0")
    duty_cycle = _min_duty + int(value * _duty_range)
    #print("duty_cycle", duty_cycle)
    set_duty_cycle(duty_cycle)

def angle(new_angle):
    if new_angle < 0 or new_angle > actuation_range:
        raise ValueError("Angle out of range")
    set_fraction(new_angle / actuation_range)

def throttle(value):
    if value > 1.0 or value < -1.0:
        raise ValueError("Throttle must be between -1.0 and 1.0")
    fraction = (value + 1) / 2
    set_fraction(fraction)

try:
    print("Throttle 1")
    throttle(1)
    time.sleep(2)
    print("Throttle -1")
    throttle(-1)
    time.sleep(2)
    print("Throttle 0\n")
    throttle(0)
    time.sleep(2)

    print("Angle 0")
    angle(0)
    time.sleep(2)
    print("Angle 90")
    angle(90)
    time.sleep(2)
    print("Angle 180")
    angle(180)
    time.sleep(2)
    print("Angle 0")
    angle(0)

except KeyboardInterrupt:
    # Capture keyboard ^C to exit the program
    print('\nYou terminated the program. The program ends!')
    angle(0)
    pwm.set_all_pwm(0, 0)
    pwm.close()