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  }