Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

megapi: use serialport adaptor and move driver to drivers/serial #1062

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
33 changes: 32 additions & 1 deletion drivers/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ import(

### Neurosky adaptor split off

The Neurosky adaptor now us the generic serial adaptor. The driver part was moved. With this, the imports needs to be
The Neurosky adaptor now use the generic serial adaptor. The driver part was moved. With this, the imports needs to be
adjusted. In addition all events now have a suffix "Event", see below.

```go
Expand Down Expand Up @@ -148,6 +148,37 @@ import(
...
```

### MegaPi adaptor split off

The MegaPi adaptor now use 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
Loading