refactor(pwm steering): asymetric center
This commit is contained in:
@ -16,9 +16,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MinPwmAngle = 999.0
|
||||
MaxPwmAngle = 1985.0
|
||||
|
||||
MinPwmThrottle = 972.0
|
||||
MaxPwmThrottle = 1954.0
|
||||
)
|
||||
@ -38,9 +35,31 @@ type Part struct {
|
||||
ctrlRecord bool
|
||||
driveMode events.DriveMode
|
||||
cancel chan interface{}
|
||||
|
||||
pwmSteeringConfig PWMSteeringConfig
|
||||
}
|
||||
|
||||
func NewPart(client mqtt.Client, name string, baud int, throttleTopic, steeringTopic, driveModeTopic, switchRecordTopic string, pubFrequency float64) *Part {
|
||||
type PWMSteeringConfig struct {
|
||||
Left int
|
||||
Right int
|
||||
Center int
|
||||
}
|
||||
|
||||
func NewPWMSteeringConfig(min, max int) PWMSteeringConfig {
|
||||
return PWMSteeringConfig{
|
||||
Left: min,
|
||||
Right: max,
|
||||
Center: min + (max-min)/2,
|
||||
}
|
||||
}
|
||||
func NewAsymetricPWMSteeringConfig(min, max, middle int) PWMSteeringConfig {
|
||||
c := NewPWMSteeringConfig(min, max)
|
||||
c.Center = middle
|
||||
return c
|
||||
}
|
||||
|
||||
func NewPart(client mqtt.Client, name string, baud int, throttleTopic, steeringTopic, driveModeTopic,
|
||||
switchRecordTopic string, pubFrequency float64, steeringConfig PWMSteeringConfig) *Part {
|
||||
c := &serial.Config{Name: name, Baud: baud}
|
||||
s, err := serial.OpenPort(c)
|
||||
if err != nil {
|
||||
@ -56,6 +75,8 @@ func NewPart(client mqtt.Client, name string, baud int, throttleTopic, steeringT
|
||||
pubFrequency: pubFrequency,
|
||||
driveMode: events.DriveMode_INVALID,
|
||||
cancel: make(chan interface{}),
|
||||
|
||||
pwmSteeringConfig: steeringConfig,
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,12 +130,23 @@ func (a *Part) processChannel1(v string) {
|
||||
if err != nil {
|
||||
zap.S().Errorf("invalid value for channel1, should be an int: %v", err)
|
||||
}
|
||||
if value < MinPwmAngle {
|
||||
value = MinPwmAngle
|
||||
} else if value > MaxPwmAngle {
|
||||
value = MaxPwmAngle
|
||||
a.steering = convertPwmSteeringToPercent(value, a.pwmSteeringConfig.Left, a.pwmSteeringConfig.Right, a.pwmSteeringConfig.Center)
|
||||
}
|
||||
|
||||
func convertPwmSteeringToPercent(value int, minPwm int, maxPwm int, middlePwm int) float32 {
|
||||
if value < minPwm {
|
||||
value = minPwm
|
||||
} else if value > maxPwm {
|
||||
value = maxPwm
|
||||
}
|
||||
a.steering = ((float32(value)-MinPwmAngle)/(MaxPwmAngle-MinPwmAngle))*2.0 - 1.0
|
||||
if value == middlePwm {
|
||||
return 0.
|
||||
}
|
||||
if value < middlePwm {
|
||||
return (float32(value) - float32(middlePwm)) / float32(middlePwm-minPwm)
|
||||
}
|
||||
// middle < value < max
|
||||
return (float32(value) - float32(middlePwm)) / float32(maxPwm-middlePwm)
|
||||
}
|
||||
|
||||
func (a *Part) processChannel2(v string) {
|
||||
|
@ -6,12 +6,22 @@ import (
|
||||
"github.com/cyrilix/robocar-protobuf/go/events"
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"math"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MinPwmAngle = 999.0
|
||||
MaxPwmAngle = 1985.0
|
||||
)
|
||||
|
||||
var (
|
||||
MiddlePwmAngle = int((MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle)
|
||||
)
|
||||
|
||||
func TestArduinoPart_Update(t *testing.T) {
|
||||
oldPublish := publish
|
||||
defer func() { publish = oldPublish }()
|
||||
@ -48,7 +58,7 @@ func TestArduinoPart_Update(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
a := Part{client: nil, serial: conn, pubFrequency: 100}
|
||||
a := Part{client: nil, serial: conn, pubFrequency: 100, pwmSteeringConfig: NewAsymetricPWMSteeringConfig(MinPwmAngle, MaxPwmAngle, MiddlePwmAngle)}
|
||||
go func() {
|
||||
err := a.Start()
|
||||
if err != nil {
|
||||
@ -103,14 +113,14 @@ func TestArduinoPart_Update(t *testing.T) {
|
||||
fmt.Sprintf("12395,%d,%d,%d,%d,%d,%d,50,%d\n", 99, channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., -1., events.DriveMode_USER, false},
|
||||
{"Sterring: left",
|
||||
fmt.Sprintf("12400,%d,%d,%d,%d,%d,%d,50,%d\n", 998, channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., -0.93, events.DriveMode_USER, false},
|
||||
fmt.Sprintf("12400,%d,%d,%d,%d,%d,%d,50,%d\n", int(MinPwmAngle+40), channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., -0.92, events.DriveMode_USER, false},
|
||||
{"Sterring: middle",
|
||||
fmt.Sprintf("12405,%d,%d,%d,%d,%d,%d,50,%d\n", 1450, channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., -0.04, events.DriveMode_USER, false},
|
||||
-1., -0.09, events.DriveMode_USER, false},
|
||||
{"Sterring: right",
|
||||
fmt.Sprintf("12410,%d,%d,%d,%d,%d,%d,50,%d\n", 1958, channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., 0.96, events.DriveMode_USER, false},
|
||||
-1., 0.95, events.DriveMode_USER, false},
|
||||
{"Sterring: over right",
|
||||
fmt.Sprintf("12415,%d,%d,%d,%d,%d,%d,50,%d\n", 2998, channel2, channel3, channel4, channel5, channel6, distanceCm),
|
||||
-1., 1., events.DriveMode_USER, false},
|
||||
@ -285,3 +295,145 @@ func unmarshalMsg(t *testing.T, payload []byte, msg proto.Message) {
|
||||
t.Errorf("unable to unmarshal protobuf content to %T: %v", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_convertPwmSteeringToPercent(t *testing.T) {
|
||||
type args struct {
|
||||
value int
|
||||
middle int
|
||||
min int
|
||||
max int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want float32
|
||||
}{
|
||||
{
|
||||
name: "middle",
|
||||
args: args{
|
||||
value: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 0.,
|
||||
},
|
||||
{
|
||||
name: "left",
|
||||
args: args{
|
||||
value: MinPwmAngle,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: -1.,
|
||||
},
|
||||
{
|
||||
name: "mid-left",
|
||||
args: args{
|
||||
value: int(math.Round((MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle - (MaxPwmAngle-MinPwmAngle)/4)),
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: -0.4989858,
|
||||
},
|
||||
{
|
||||
name: "over left",
|
||||
args: args{
|
||||
value: MinPwmAngle - 100,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: -1.,
|
||||
},
|
||||
{
|
||||
name: "right",
|
||||
args: args{
|
||||
value: MaxPwmAngle,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 1.,
|
||||
},
|
||||
{
|
||||
name: "mid-right",
|
||||
args: args{
|
||||
value: int(math.Round((MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + (MaxPwmAngle-MinPwmAngle)/4)),
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 0.5010142,
|
||||
},
|
||||
{
|
||||
name: "over right",
|
||||
args: args{
|
||||
value: MaxPwmAngle + 100,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 1.,
|
||||
},
|
||||
{
|
||||
name: "asymetric middle",
|
||||
args: args{
|
||||
value: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 0.,
|
||||
},
|
||||
{
|
||||
name: "asymetric mid-left",
|
||||
args: args{
|
||||
value: int(math.Round(((MaxPwmAngle-MinPwmAngle)/2+MinPwmAngle+100-MinPwmAngle)/2) + MinPwmAngle),
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: -0.49915683,
|
||||
},
|
||||
{
|
||||
name: "asymetric left",
|
||||
args: args{
|
||||
value: MinPwmAngle,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: -1.,
|
||||
},
|
||||
{
|
||||
name: "asymetric mid-right",
|
||||
args: args{
|
||||
value: int(math.Round((MaxPwmAngle - (MaxPwmAngle-((MaxPwmAngle-MinPwmAngle)/2+MinPwmAngle+100))/2))),
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 0.50127226,
|
||||
},
|
||||
{
|
||||
name: "asymetric right",
|
||||
args: args{
|
||||
value: MaxPwmAngle,
|
||||
middle: (MaxPwmAngle-MinPwmAngle)/2 + MinPwmAngle + 100,
|
||||
min: MinPwmAngle,
|
||||
max: MaxPwmAngle,
|
||||
},
|
||||
want: 1.,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := convertPwmSteeringToPercent(tt.args.value, tt.args.min, tt.args.max, tt.args.middle); got != tt.want {
|
||||
t.Errorf("convertPwmSteeringToPercent() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user