forked from hybridgroup/gobot
-
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.
Add SparkFun’s EasyDriver (and BigEasyDriver)
Signed-off-by: Brendan Stennett <[email protected]>
- Loading branch information
1 parent
1c82bf7
commit d072e75
Showing
3 changed files
with
420 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
package gpio | ||
|
||
import ( | ||
"errors" | ||
"strconv" | ||
"time" | ||
|
||
"gobot.io/x/gobot" | ||
) | ||
|
||
// EasyDriver object | ||
type EasyDriver struct { | ||
gobot.Commander | ||
|
||
name string | ||
connection DigitalWriter | ||
stepPin string | ||
dirPin string | ||
enPin string | ||
sleepPin string | ||
|
||
angle float32 | ||
rpm uint | ||
dir int8 | ||
moving bool | ||
stepNum int | ||
enabled bool | ||
sleeping bool | ||
} | ||
|
||
// NewEasyDriver returns a new EasyDriver from SparkFun (https://www.sparkfun.com/products/12779) | ||
// TODO: Support selecting phase input instead of hard-wiring MS1 and MS2 to board truth table | ||
// This should also work for the BigEasyDriver (untested) | ||
// A - DigitalWriter | ||
// stepPin - Pin corresponding to step input on EasyDriver | ||
// dirPin - Pin corresponding to dir input on EasyDriver. Optional | ||
// enPin - Pin corresponding to enabled input on EasyDriver. Optional | ||
// sleepPin - Pin corresponding to sleep input on EasyDriver. Optional | ||
// angle - Step angle of motor | ||
func NewEasyDriver(a DigitalWriter, angle float32, stepPin string, dirPin string, enPin string, sleepPin string) *EasyDriver { | ||
d := &EasyDriver{ | ||
Commander: gobot.NewCommander(), | ||
name: gobot.DefaultName("EasyDriver"), | ||
connection: a, | ||
stepPin: stepPin, | ||
dirPin: dirPin, | ||
enPin: enPin, | ||
sleepPin: sleepPin, | ||
|
||
angle: angle, | ||
rpm: 1, | ||
dir: 1, | ||
enabled: true, | ||
sleeping: false, | ||
} | ||
|
||
// panic if step pin isn't set | ||
if stepPin == "" { | ||
panic("Step pin is not set") | ||
} | ||
|
||
// 1/4 of max speed. Not too fast, not too slow | ||
d.rpm = d.GetMaxSpeed() / 4 | ||
|
||
d.AddCommand("Move", func(params map[string]interface{}) interface{} { | ||
degs, _ := strconv.Atoi(params["degs"].(string)) | ||
return d.Move(degs) | ||
}) | ||
d.AddCommand("Step", func(params map[string]interface{}) interface{} { | ||
return d.Step() | ||
}) | ||
d.AddCommand("Run", func(params map[string]interface{}) interface{} { | ||
return d.Run() | ||
}) | ||
d.AddCommand("Stop", func(params map[string]interface{}) interface{} { | ||
return d.Stop() | ||
}) | ||
|
||
return d | ||
} | ||
|
||
// Name of EasyDriver | ||
func (d *EasyDriver) Name() string { return d.name } | ||
|
||
// SetName sets name for EasyDriver | ||
func (d *EasyDriver) SetName(n string) { d.name = n } | ||
|
||
// Connection returns EasyDriver's connection | ||
func (d *EasyDriver) Connection() gobot.Connection { return d.connection.(gobot.Connection) } | ||
|
||
// Start implements the Driver interface | ||
func (d *EasyDriver) Start() (err error) { return } | ||
|
||
// Halt implements the Driver interface; stops running the stepper | ||
func (d *EasyDriver) Halt() (err error) { | ||
d.Stop() | ||
return | ||
} | ||
|
||
// Move the motor given number of degrees at current speed. | ||
func (d *EasyDriver) Move(degs int) (err error) { | ||
if d.moving { | ||
// don't do anything if already moving | ||
return | ||
} | ||
|
||
d.moving = true | ||
|
||
steps := int(float32(degs) / d.angle) | ||
for i := 0; i < steps; i++ { | ||
if !d.moving { | ||
// don't continue to step if driver is stopped | ||
break | ||
} | ||
|
||
d.Step() | ||
} | ||
|
||
d.moving = false | ||
|
||
return | ||
} | ||
|
||
// Step the stepper 1 step | ||
func (d *EasyDriver) Step() (err error) { | ||
stepsPerRev := d.GetMaxSpeed() | ||
|
||
// a valid steps occurs for a low to high transition | ||
d.connection.DigitalWrite(d.stepPin, 0) | ||
// 1 minute / steps per revolution / revolutions per minute | ||
// let's keep it as Microseconds so we only have to do integer math | ||
time.Sleep(time.Duration(60*1000*1000/stepsPerRev/d.rpm) * time.Microsecond) | ||
d.connection.DigitalWrite(d.stepPin, 1) | ||
|
||
// increment or decrement the number of steps by 1 | ||
d.stepNum += int(d.dir) | ||
|
||
return | ||
} | ||
|
||
// Run the stepper continuously | ||
func (d *EasyDriver) Run() (err error) { | ||
if d.moving { | ||
// don't do anything if already moving | ||
return | ||
} | ||
|
||
d.moving = true | ||
|
||
go func() { | ||
for d.moving { | ||
d.Step() | ||
} | ||
}() | ||
|
||
return | ||
} | ||
|
||
// Stop running the stepper | ||
func (d *EasyDriver) Stop() (err error) { | ||
d.moving = false | ||
return | ||
} | ||
|
||
// SetDirection sets the direction to be moving. Valid directions are "cw" or "ccw" | ||
func (d *EasyDriver) SetDirection(dir string) (err error) { | ||
// can't change direct if dirPin isn't set | ||
if d.dirPin == "" { | ||
return errors.New("dirPin is not set") | ||
} | ||
|
||
if dir == "ccw" { | ||
d.dir = -1 | ||
d.connection.DigitalWrite(d.dirPin, 1) // high is ccw | ||
} else { // default to cw, even if user specified wrong value | ||
d.dir = 1 | ||
d.connection.DigitalWrite(d.dirPin, 0) // low is cw | ||
} | ||
|
||
return | ||
} | ||
|
||
// SetSpeed sets the speed of the motor in RPMs. 1 is the lowest and GetMaxSpeed is the highest | ||
func (d *EasyDriver) SetSpeed(rpm uint) (err error) { | ||
if rpm < 1 { | ||
d.rpm = 1 | ||
} else if rpm > d.GetMaxSpeed() { | ||
d.rpm = d.GetMaxSpeed() | ||
} else { | ||
d.rpm = rpm | ||
} | ||
|
||
return | ||
} | ||
|
||
// GetMaxSpeed returns the max speed of the stepper | ||
func (d *EasyDriver) GetMaxSpeed() uint { | ||
return uint(360 / d.angle) | ||
} | ||
|
||
// GetCurrentStep returns current step number | ||
func (d *EasyDriver) GetCurrentStep() int { | ||
return d.stepNum | ||
} | ||
|
||
// IsMoving returns a bool stating whether motor is currently in motion | ||
func (d *EasyDriver) IsMoving() bool { | ||
return d.moving | ||
} | ||
|
||
// Enable enables all motor output | ||
func (d *EasyDriver) Enable() (err error) { | ||
// can't enable if enPin isn't set. This is fine normally since it will be enabled by default | ||
if d.enPin == "" { | ||
return errors.New("enPin is not set. Board is enabled by default") | ||
} | ||
|
||
d.enabled = true | ||
d.connection.DigitalWrite(d.enPin, 0) // enPin is active low | ||
|
||
return | ||
} | ||
|
||
// Disable disables all motor output | ||
func (d *EasyDriver) Disable() (err error) { | ||
// can't disable if enPin isn't set | ||
if d.enPin == "" { | ||
return errors.New("enPin is not set") | ||
} | ||
|
||
// let's stop the motor first | ||
d.Stop() | ||
|
||
d.enabled = false | ||
d.connection.DigitalWrite(d.enPin, 1) // enPin is active low | ||
|
||
return | ||
} | ||
|
||
// IsEnabled returns a bool stating whether motor is enabled | ||
func (d *EasyDriver) IsEnabled() bool { | ||
return d.enabled | ||
} | ||
|
||
// Sleep puts the driver to sleep and disables all motor output. Low power mode. | ||
func (d *EasyDriver) Sleep() (err error) { | ||
// can't sleep if sleepPin isn't set | ||
if d.sleepPin == "" { | ||
return errors.New("sleepPin is not set") | ||
} | ||
|
||
// let's stop the motor first | ||
d.Stop() | ||
|
||
d.sleeping = true | ||
d.connection.DigitalWrite(d.sleepPin, 0) // sleepPin is active low | ||
|
||
return | ||
} | ||
|
||
// Wake wakes up the driver | ||
func (d *EasyDriver) Wake() (err error) { | ||
// can't wake if sleepPin isn't set | ||
if d.sleepPin == "" { | ||
return errors.New("sleepPin is not set") | ||
} | ||
|
||
d.sleeping = false | ||
d.connection.DigitalWrite(d.sleepPin, 1) // sleepPin is active low | ||
|
||
// we need to wait 1ms after sleeping before doing a step to charge the step pump (according to data sheet) | ||
// this will ensure that happens | ||
time.Sleep(1 * time.Millisecond) | ||
|
||
return | ||
} | ||
|
||
// IsSleeping returns a bool stating whether motor is enabled | ||
func (d *EasyDriver) IsSleeping() bool { | ||
return d.sleeping | ||
} |
Oops, something went wrong.