forked from tinygo-org/drivers
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR adds support for controlling servos. For example, on the Arduino Uno it should be able to control up to 6 servos jitter-free when using all available PWM pins. I haven't added support for setting a position in degrees, mainly because this varies by servo and it's probably necessary to configure the bounds in some way. Therefore, I added just SetMicroseconds. This makes the API possible to use and leaves the possibility of adding a SetPosition in the future.
- Loading branch information
1 parent
428db3c
commit c765ef3
Showing
4 changed files
with
129 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package main | ||
|
||
import ( | ||
"machine" | ||
"time" | ||
|
||
"tinygo.org/x/drivers/servo" | ||
) | ||
|
||
// Configuration for the Arduino Uno. | ||
// Please change the PWM and pin if you want to try this example on a different | ||
// board. | ||
var ( | ||
pwm = machine.Timer1 | ||
pin = machine.D9 | ||
) | ||
|
||
func main() { | ||
s, err := servo.New(pwm, pin) | ||
if err != nil { | ||
for { | ||
println("could not configure servo") | ||
time.Sleep(time.Second) | ||
} | ||
return | ||
} | ||
|
||
println("setting to 0°") | ||
s.SetMicroseconds(1000) | ||
time.Sleep(3 * time.Second) | ||
|
||
println("setting to 45°") | ||
s.SetMicroseconds(1500) | ||
time.Sleep(3 * time.Second) | ||
|
||
println("setting to 90°") | ||
s.SetMicroseconds(2000) | ||
time.Sleep(3 * time.Second) | ||
|
||
for { | ||
time.Sleep(time.Second) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package servo | ||
|
||
import "machine" | ||
|
||
// PWM is the interface necessary for controlling typical servo motors. | ||
type PWM interface { | ||
Configure(config machine.PWMConfig) error | ||
Channel(pin machine.Pin) (channel uint8, err error) | ||
Top() uint32 | ||
Set(channel uint8, value uint32) | ||
} | ||
|
||
// Array is an array of servos controlled by a single PWM peripheral. On most | ||
// chips, one PWM peripheral can control multiple servos (usually two or four). | ||
type Array struct { | ||
pwm PWM | ||
} | ||
|
||
// Servo is a single servo (connected to one PWM output) that's part of a servo | ||
// array. | ||
type Servo struct { | ||
pwm PWM | ||
channel uint8 | ||
} | ||
|
||
const pwmPeriod = 20e6 // 20ms | ||
|
||
// NewArray returns a new servo array based on the given PWM, for if you want to | ||
// control multiple servos from a single PWM peripheral. Using a single PWM for | ||
// multiple servos saves PWM peripherals for other uses and might use less power | ||
// depending on the chip. | ||
// | ||
// If you only want to control a single servo, you could use the New shorthand | ||
// instead. | ||
func NewArray(pwm PWM) (Array, error) { | ||
err := pwm.Configure(machine.PWMConfig{ | ||
Period: pwmPeriod, | ||
}) | ||
if err != nil { | ||
return Array{}, err | ||
} | ||
return Array{pwm}, nil | ||
} | ||
|
||
// Add adds a new servo to the servo array. Please check the chip documentation | ||
// which pins can be controlled by the given PWM: depending on the chip this | ||
// might be rigid (only a single pin) or very flexible (you can pick any pin). | ||
func (array Array) Add(pin machine.Pin) (Servo, error) { | ||
channel, err := array.pwm.Channel(pin) | ||
if err != nil { | ||
return Servo{}, err | ||
} | ||
return Servo{ | ||
pwm: array.pwm, | ||
channel: channel, | ||
}, nil | ||
} | ||
|
||
// New is a shorthand for NewArray and array.Add. This is useful if you only | ||
// want to control just a single servo. | ||
func New(pwm PWM, pin machine.Pin) (Servo, error) { | ||
array, err := NewArray(pwm) | ||
if err != nil { | ||
return Servo{}, err | ||
} | ||
return array.Add(pin) | ||
} | ||
|
||
// SetMicroseconds sets the output signal to be high for the given number of | ||
// microseconds. For many servos the range is normally between 1000µs and 2000µs | ||
// for 90° of rotation (with 1500µs being the 'neutral' middle position). | ||
// | ||
// In many cases they can actually go a bit further, with a wider range of | ||
// supported pulse ranges. For example, they might allow pulse widths from 500µs | ||
// to 2500µs, but be warned that going outside of the 1000µs-2000µs range might | ||
// break the servo as it might destroy the gears if it doesn't support this | ||
// range. Therefore, to be sure check the datasheet before you try values | ||
// outside of the 1000µs-2000µs range. | ||
func (s Servo) SetMicroseconds(microseconds int16) { | ||
value := uint64(s.pwm.Top()) * uint64(microseconds) / (pwmPeriod / 1000) | ||
s.pwm.Set(s.channel, uint32(value)) | ||
} |