tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/servo/servo.go (about) 1 package servo 2 3 import "machine" 4 5 // PWM is the interface necessary for controlling typical servo motors. 6 type PWM interface { 7 Configure(config machine.PWMConfig) error 8 Channel(pin machine.Pin) (channel uint8, err error) 9 Top() uint32 10 Set(channel uint8, value uint32) 11 } 12 13 // Array is an array of servos controlled by a single PWM peripheral. On most 14 // chips, one PWM peripheral can control multiple servos (usually two or four). 15 type Array struct { 16 pwm PWM 17 } 18 19 // Servo is a single servo (connected to one PWM output) that's part of a servo 20 // array. 21 type Servo struct { 22 pwm PWM 23 channel uint8 24 } 25 26 const pwmPeriod = 20e6 // 20ms 27 28 // NewArray returns a new servo array based on the given PWM, for if you want to 29 // control multiple servos from a single PWM peripheral. Using a single PWM for 30 // multiple servos saves PWM peripherals for other uses and might use less power 31 // depending on the chip. 32 // 33 // If you only want to control a single servo, you could use the New shorthand 34 // instead. 35 func NewArray(pwm PWM) (Array, error) { 36 err := pwm.Configure(machine.PWMConfig{ 37 Period: pwmPeriod, 38 }) 39 if err != nil { 40 return Array{}, err 41 } 42 return Array{pwm}, nil 43 } 44 45 // Add adds a new servo to the servo array. Please check the chip documentation 46 // which pins can be controlled by the given PWM: depending on the chip this 47 // might be rigid (only a single pin) or very flexible (you can pick any pin). 48 func (array Array) Add(pin machine.Pin) (Servo, error) { 49 channel, err := array.pwm.Channel(pin) 50 if err != nil { 51 return Servo{}, err 52 } 53 return Servo{ 54 pwm: array.pwm, 55 channel: channel, 56 }, nil 57 } 58 59 // New is a shorthand for NewArray and array.Add. This is useful if you only 60 // want to control just a single servo. 61 func New(pwm PWM, pin machine.Pin) (Servo, error) { 62 array, err := NewArray(pwm) 63 if err != nil { 64 return Servo{}, err 65 } 66 return array.Add(pin) 67 } 68 69 // SetMicroseconds sets the output signal to be high for the given number of 70 // microseconds. For many servos the range is normally between 1000µs and 2000µs 71 // for 90° of rotation (with 1500µs being the 'neutral' middle position). 72 // 73 // In many cases they can actually go a bit further, with a wider range of 74 // supported pulse ranges. For example, they might allow pulse widths from 500µs 75 // to 2500µs, but be warned that going outside of the 1000µs-2000µs range might 76 // break the servo as it might destroy the gears if it doesn't support this 77 // range. Therefore, to be sure check the datasheet before you try values 78 // outside of the 1000µs-2000µs range. 79 func (s Servo) SetMicroseconds(microseconds int16) { 80 value := uint64(s.pwm.Top()) * uint64(microseconds) / (pwmPeriod / 1000) 81 s.pwm.Set(s.channel, uint32(value)) 82 }