robocar-pca9685/pkg/actuator/pca9685.go

121 lines
3.2 KiB
Go
Raw Normal View History

2019-12-27 17:23:08 +00:00
package actuator
import (
"fmt"
"github.com/cyrilix/robocar-pca9685/pkg/util"
2021-10-12 17:28:56 +00:00
"go.uber.org/zap"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/physic"
"periph.io/x/devices/v3/pca9685"
"periph.io/x/host/v3"
2019-12-27 17:23:08 +00:00
)
const (
MinPercent = -1.
MaxPercent = 1.
2019-12-27 17:23:08 +00:00
)
type PWM int
func NewDevice(freq physic.Frequency) *pca9685.Dev {
zap.S().Info("NewDevice pca9685 controller")
2019-12-27 17:23:08 +00:00
_, err := host.Init()
if err != nil {
zap.S().Fatalf("unable to NewDevice host: %v", err)
2019-12-27 17:23:08 +00:00
}
2021-10-12 17:28:56 +00:00
zap.S().Info("open i2c bus")
2019-12-27 17:23:08 +00:00
bus, err := i2creg.Open("")
if err != nil {
zap.S().Fatalf("unable to NewDevice i2c bus: %v", err)
2019-12-27 17:23:08 +00:00
}
zap.S().Infof("i2c bus opened: %v", bus)
2019-12-27 17:23:08 +00:00
device, err := pca9685.NewI2C(bus, pca9685.I2CAddr)
2019-12-27 17:23:08 +00:00
if err != nil {
zap.S().Fatalf("unable to NewDevice pca9685 bus: %v", err)
2019-12-27 17:23:08 +00:00
}
2022-06-15 17:53:02 +00:00
zap.S().Infof("set pwm frequency to %v", freq)
err = device.SetPwmFreq(freq)
2019-12-27 17:23:08 +00:00
if err != nil {
2021-10-12 17:28:56 +00:00
zap.S().Panicf("unable to set pwm frequency: %v", err)
2019-12-27 17:23:08 +00:00
}
zap.S().Info("NewDevice done")
return device
}
2022-06-15 17:53:02 +00:00
func (c *Pca9685Controller) convertToDuty(percent float32) (gpio.Duty, error) {
// map absolute angle to angle that vehicle can implement.
2022-06-15 17:53:02 +00:00
pw := int(c.neutralPWM)
if percent > 0 {
2022-06-15 17:53:02 +00:00
pw = util.MapRange(float64(percent), 0, MaxPercent, float64(c.neutralPWM), float64(c.maxPWM))
} else if percent < 0 {
2022-06-15 17:53:02 +00:00
pw = util.MapRange(float64(percent), MinPercent, 0, float64(c.minPWM), float64(c.neutralPWM))
}
2022-06-15 17:53:02 +00:00
c.logr.Debugf("convert value %v to pw: %v", percent, pw)
2022-06-15 17:53:02 +00:00
per := c.freq.Period().Microseconds()
draw := float64(pw) / float64(per)
return gpio.Duty(int32(draw * float64(gpio.DutyMax))), nil
/*
d, err := gpio.ParseDuty(strconv.Itoa(int(dd)))
// d, err := gpio.ParseDuty(fmt.Sprintf("%.f%%", draw*100))
if err != nil {
return 0, fmt.Errorf("unable to parse duty, probably bad compute: %w", err)
}
return d, nil
*/
}
type Pca9685Controller struct {
2022-06-15 17:53:02 +00:00
logr *zap.SugaredLogger
pin gpio.PinIO
minPWM, maxPWM, neutralPWM PWM
freq physic.Frequency
}
func (c *Pca9685Controller) Close() error {
return c.pin.Halt()
}
func (c *Pca9685Controller) SetDuty(d gpio.Duty) error {
c.logr.Debugf("set duty %v -> %d (12bits value: %d)", d.String(), d, d>>12)
err := c.pin.PWM(d, c.freq)
if err != nil {
return fmt.Errorf("unable to set pwm value: %v", err)
}
return nil
}
// SetPercentValue Set percent value
func (c *Pca9685Controller) SetPercentValue(p float32) error {
2022-06-15 17:53:02 +00:00
d, err := c.convertToDuty(p)
if err != nil {
return fmt.Errorf("unable to compute Duty value for steering: %w", err)
}
err = c.SetDuty(d)
if err != nil {
return fmt.Errorf("unable to apply duty value '%v' for pin '%v': '%w' ", d, c.pin.Name(), err)
}
return nil
}
2022-06-15 17:53:02 +00:00
func NewPca9685Controller(device *pca9685.Dev, channel int, minPWM, maxPWM, neutralPWM PWM, freq physic.Frequency, logr *zap.SugaredLogger) (*Pca9685Controller, error) {
p, err := device.CreatePin(channel)
if err != nil {
return nil, fmt.Errorf("unable to create pin for channel %v: %w", channel, err)
}
s := Pca9685Controller{
pin: p,
minPWM: minPWM,
maxPWM: maxPWM,
neutralPWM: neutralPWM,
freq: freq,
2022-06-15 17:53:02 +00:00
logr: logr,
}
return &s, nil
2019-12-27 17:23:08 +00:00
}