Skip to content

Commit

Permalink
megapi: use serialport adaptor and move driver to drivers/serial
Browse files Browse the repository at this point in the history
  • Loading branch information
gen2thomas committed Feb 12, 2024
1 parent e2b710b commit 2e4ee49
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 209 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ the `gobot/drivers/serial` package:
- [UART](https://en.wikipedia.org/wiki/Serial_port) <=> [Drivers](https://github.com/hybridgroup/gobot/tree/master/drivers/serial)
- Sphero: Sphero
- Neurosky: MindWave
- MegaPi: MotorDriver

Support for devices that use Serial Peripheral Interface (SPI) have
a shared set of drivers provided using the `gobot/drivers/spi` package:
Expand Down
31 changes: 31 additions & 0 deletions drivers/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,37 @@ import(
...
```
### MegaPi adaptor split off
The MegaPi adaptor now us the generic serial adaptor. The driver part was moved. With this, the imports needs to be
adjusted.
```go
// old
import(
...
"gobot.io/x/gobot/v2/platforms/megapi"
...
)

...
megaPiAdaptor := megapi.NewAdaptor("/dev/ttyS0")
motor := megapi.NewMotorDriver(megaPiAdaptor, 1)
...

// new
import(
...
"gobot.io/x/gobot/v2/drivers/serial/megapi"
"gobot.io/x/gobot/v2/platforms/serialport"
...
)
...
adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi"))
motor := megapi.NewMotorDriver(adaptor, 1)
...
```
## Switch from version 2.2.0 (gpio drivers affected)
### gpio.ButtonDriver, gpio.PIRMotionDriver: substitute parameter "v time.duration"
Expand Down
1 change: 1 addition & 0 deletions drivers/serial/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Gobot has a extensible system for connecting to hardware devices. The following

- Sphero: Sphero
- Neurosky: MindWave
- MegaPi: MotorDriver
130 changes: 130 additions & 0 deletions drivers/serial/megapi/motor_driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package megapi

import (
"bytes"
"encoding/binary"
"log"
"sync"
"time"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/drivers/serial"
)

var _ gobot.Driver = (*MotorDriver)(nil)

type megapiMotorSerialAdaptor interface {
gobot.Adaptor
serial.SerialWriter
}

// MotorDriver represents a motor
type MotorDriver struct {
*serial.Driver
port byte
halted bool
writeBytesChannel chan []byte
finalizeChannel chan struct{}
syncRoot *sync.Mutex
}

// NewMotorDriver creates a new MotorDriver at the given port
func NewMotorDriver(a megapiMotorSerialAdaptor, port byte, opts ...serial.OptionApplier) *MotorDriver {
d := &MotorDriver{
port: port,
halted: true,
syncRoot: &sync.Mutex{},
writeBytesChannel: make(chan []byte),
finalizeChannel: make(chan struct{}),
}
d.Driver = serial.NewDriver(a, "MegaPiMotor", d.initialize, d.shutdown, opts...)

return d
}

// Speed sets the motors speed to the specified value
func (d *MotorDriver) Speed(speed int16) error {
d.syncRoot.Lock()
defer d.syncRoot.Unlock()

if d.halted {
return nil
}
return d.speedHelper(speed)
}

// initialize implements the Driver interface
func (d *MotorDriver) initialize() error {
d.syncRoot.Lock()
defer d.syncRoot.Unlock()

// sleeping is required to give the board a chance to reset after connection is done
time.Sleep(2 * time.Second)

// kick off thread to send bytes to the board
go func() {
for {
select {
case bytes := <-d.writeBytesChannel:
if _, err := d.adaptor().SerialWrite(bytes); err != nil {
panic(err)
}
time.Sleep(10 * time.Millisecond)
case <-d.finalizeChannel:
d.finalizeChannel <- struct{}{}
return
default:
time.Sleep(10 * time.Millisecond)
}
}
}()

d.halted = false
return d.speedHelper(0)
}

// Halt terminates the Driver interface
func (d *MotorDriver) shutdown() error {
d.syncRoot.Lock()
defer d.syncRoot.Unlock()

d.finalizeChannel <- struct{}{}
<-d.finalizeChannel

d.halted = true
return d.speedHelper(0)
}

// there is some sort of bug on the hardware such that you cannot
// send the exact same speed to 2 different motors consecutively
// hence we ensure we always alternate speeds
func (d *MotorDriver) speedHelper(speed int16) error {
if err := d.sendSpeed(speed - 1); err != nil {
return err
}
return d.sendSpeed(speed)
}

// sendSpeed sets the motors speed to the specified value
func (d *MotorDriver) sendSpeed(speed int16) error {
bufOut := new(bytes.Buffer)

// byte sequence: 0xff, 0x55, id, action, device, port
bufOut.Write([]byte{0xff, 0x55, 0x6, 0x0, 0x2, 0xa, d.port})
if err := binary.Write(bufOut, binary.LittleEndian, speed); err != nil {
return err
}
bufOut.Write([]byte{0xa})
d.writeBytesChannel <- bufOut.Bytes()

return nil
}

func (d *MotorDriver) adaptor() megapiMotorSerialAdaptor {
if a, ok := d.Connection().(megapiMotorSerialAdaptor); ok {
return a
}

log.Printf("%s has no MegaPi serial connector\n", d.Name())
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (
"time"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/platforms/megapi"
"gobot.io/x/gobot/v2/drivers/serial/megapi"
"gobot.io/x/gobot/v2/platforms/serialport"
)

func main() {
// use "/dev/ttyUSB0" if connecting with USB cable
// use "/dev/ttyAMA0" on devices older than Raspberry Pi 3 Model B
megaPiAdaptor := megapi.NewAdaptor("/dev/ttyS0")
motor := megapi.NewMotorDriver(megaPiAdaptor, 1)
adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi"))
motor := megapi.NewMotorDriver(adaptor, 1)

work := func() {
speed := int16(0)
Expand All @@ -36,7 +37,7 @@ func main() {
}

robot := gobot.NewRobot("megaPiBot",
[]gobot.Connection{megaPiAdaptor},
[]gobot.Connection{adaptor},
[]gobot.Device{motor},
work,
)
Expand Down
17 changes: 10 additions & 7 deletions platforms/megapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@ Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/r
package main

import (
"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/platforms/megapi"
"fmt"
"time"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/drivers/serial/megapi"
"gobot.io/x/gobot/v2/platforms/serialport"
)

func main() {
// use "/dev/ttyUSB0" if connecting with USB cable
// use "/dev/ttyAMA0" on devices older than Raspberry Pi 3 Model B
megaPiAdaptor := megapi.NewAdaptor("/dev/ttyS0")
motor := megapi.NewMotorDriver(megaPiAdaptor, 1)
adaptor := serialport.NewAdaptor("/dev/ttyS0", serialport.WithName("MegaPi"))
motor := megapi.NewMotorDriver(adaptor, 1)

work := func() {
speed := int16(0)
Expand All @@ -40,13 +43,13 @@ func main() {
}

robot := gobot.NewRobot("megaPiBot",
[]gobot.Connection{megaPiAdaptor},
[]gobot.Connection{adaptor},
[]gobot.Device{motor},
work,
)

if err := robot.Start(); err != nil {
panic(err)
}
panic(err)
}
}
```
88 changes: 0 additions & 88 deletions platforms/megapi/megapi_adaptor.go

This file was deleted.

Loading

0 comments on commit 2e4ee49

Please sign in to comment.