This commit is contained in:
Cyrille Nofficial 2022-08-23 13:24:31 +02:00
parent 7d27ea866f
commit 86f91d9f88
3 changed files with 213 additions and 21 deletions

View File

@ -9,11 +9,11 @@ import (
) )
type Corrector struct { type Corrector struct {
fixValues FixesTable gridMap *GridMap
} }
/* /*
FixFromObjectPosition modify steering value according object positions AdjustFromObjectPosition modify steering value according object positions
1. To compute steering correction, split in image in zones and define correction value for each zone 1. To compute steering correction, split in image in zones and define correction value for each zone
@ -40,7 +40,7 @@ FixFromObjectPosition modify steering value according object positions
3. If current steering != 0 (turn on left or right), shift right and left values proportionnaly to current steering and 3. If current steering != 0 (turn on left or right), shift right and left values proportionnaly to current steering and
apply 2. apply 2.
*/ */
func (c *Corrector) FixFromObjectPosition(currentSteering float64, objects []*events.Object) float64 { func (c *Corrector) AdjustFromObjectPosition(currentSteering float64, objects []*events.Object) float64 {
// TODO, group rectangle // TODO, group rectangle
if len(objects) == 0 { if len(objects) == 0 {
@ -60,13 +60,21 @@ func (c *Corrector) FixFromObjectPosition(currentSteering float64, objects []*ev
return currentSteering return currentSteering
} }
var delta float64
if nearest.Left < 0 && nearest.Right < 0 { if nearest.Left < 0 && nearest.Right < 0 {
return currentSteering + c.fixValues.ValueOf(currentSteering, float64(nearest.Right)) delta, err = c.gridMap.ValueOf(currentSteering, float64(nearest.Right))
} }
if nearest.Left > 0 && nearest.Right > 0 { if nearest.Left > 0 && nearest.Right > 0 {
return currentSteering + c.fixValues.ValueOf(currentSteering, float64(nearest.Left)) delta, err = c.gridMap.ValueOf(currentSteering, float64(nearest.Left))
} else {
delta, err = c.gridMap.ValueOf(currentSteering, float64(nearest.Left)+(float64(nearest.Right)-float64(nearest.Left))/2.)
} }
return currentSteering + c.fixValues.ValueOf(currentSteering, float64(nearest.Left)+(float64(nearest.Right)-float64(nearest.Left))/2.) if err != nil {
zap.S().Warnf("unable to compute delta to apply to steering, skip correction: %v", err)
delta = 0
}
return currentSteering + delta
} }
// Search if current steering is near of Right or Left // Search if current steering is near of Right or Left
@ -92,12 +100,12 @@ func (c *Corrector) nearObject(objects []*events.Object) (*events.Object, error)
return result, nil return result, nil
} }
func NewFixesTableFromJson(fileName string) (*FixesTable, error) { func NewGridMapFromJson(fileName string) (*GridMap, error) {
content, err := os.ReadFile(fileName) content, err := os.ReadFile(fileName)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to read content from %s file: %w", fileName, err) return nil, fmt.Errorf("unable to read content from %s file: %w", fileName, err)
} }
var ft FixesTable var ft GridMap
err = json.Unmarshal(content, &ft) err = json.Unmarshal(content, &ft)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to unmarshal json content from %s file: %w", fileName, err) return nil, fmt.Errorf("unable to unmarshal json content from %s file: %w", fileName, err)
@ -106,13 +114,19 @@ func NewFixesTableFromJson(fileName string) (*FixesTable, error) {
return &ft, nil return &ft, nil
} }
type FixesTable struct { type GridMap struct {
DistanceSteps []float64 `json:"distance_steps"` DistanceSteps []float64 `json:"distance_steps"`
SteeringSteps []float64 `json:"steering_steps"` SteeringSteps []float64 `json:"steering_steps"`
Data [][]float64 `json:"data"` Data [][]float64 `json:"data"`
} }
func (f *FixesTable) ValueOf(steering float64, distance float64) float64 { func (f *GridMap) ValueOf(steering float64, distance float64) (float64, error) {
if steering < f.SteeringSteps[0] || steering > f.SteeringSteps[len(f.SteeringSteps)-1] {
return 0., fmt.Errorf("invalid steering value: %v, must be between %v and %v", steering, f.SteeringSteps[0], f.SteeringSteps[len(f.SteeringSteps)-1])
}
if distance < f.DistanceSteps[0] || distance > f.DistanceSteps[len(f.DistanceSteps)-1] {
return 0., fmt.Errorf("invalid distance value: %v, must be between %v and %v", steering, f.DistanceSteps[0], f.DistanceSteps[len(f.DistanceSteps)-1])
}
// search column index // search column index
var idxCol int var idxCol int
// Start loop at 1 because first column should be skipped // Start loop at 1 because first column should be skipped
@ -132,5 +146,5 @@ func (f *FixesTable) ValueOf(steering float64, distance float64) float64 {
} }
} }
return f.Data[idxRow][idxCol] return f.Data[idxRow][idxCol], nil
} }

View File

@ -41,6 +41,20 @@ var (
} }
) )
var (
defaultGridMap = GridMap{
DistanceSteps: []float64{0., 0.2, 0.4, 0.6, 0.8, 1.},
SteeringSteps: []float64{-1., -0.66, -0.33, 0., 0.33, 0.66, 1.},
Data: [][]float64{
{0., 0., 0., 0., 0., 0.},
{0., 0., 0., 0., 0., 0.},
{0., 0., 0.25, -0.25, 0., 0.},
{0., 0.25, 0.5, -0.5, -0.25, 0.},
{0.25, 0.5, 1, -1, -0.5, -0.25},
},
}
)
func TestCorrector_FixFromObjectPosition(t *testing.T) { func TestCorrector_FixFromObjectPosition(t *testing.T) {
type args struct { type args struct {
currentSteering float64 currentSteering float64
@ -130,8 +144,8 @@ func TestCorrector_FixFromObjectPosition(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Corrector{} c := &Corrector{}
if got := c.FixFromObjectPosition(tt.args.currentSteering, tt.args.objects); got != tt.want { if got := c.AdjustFromObjectPosition(tt.args.currentSteering, tt.args.objects); got != tt.want {
t.Errorf("FixFromObjectPosition() = %v, want %v", got, tt.want) t.Errorf("AdjustFromObjectPosition() = %v, want %v", got, tt.want)
} }
}) })
} }
@ -187,14 +201,14 @@ func TestCorrector_nearObject(t *testing.T) {
} }
} }
func TestNewFixesTableFromJson(t *testing.T) { func TestNewGridMapFromJson(t *testing.T) {
type args struct { type args struct {
fileName string fileName string
} }
tests := []struct { tests := []struct {
name string name string
args args args args
want *FixesTable want *GridMap
wantErr bool wantErr bool
}{ }{
{ {
@ -202,18 +216,183 @@ func TestNewFixesTableFromJson(t *testing.T) {
args: args{ args: args{
fileName: "test_data/config.json", fileName: "test_data/config.json",
}, },
want: &defaultGridMap,
}, },
// TODO: Add test cases.
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := NewFixesTableFromJson(tt.args.fileName) got, err := NewGridMapFromJson(tt.args.fileName)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("NewFixesTableFromJson() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("NewGridMapFromJson() error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if !reflect.DeepEqual(got, tt.want) { if !reflect.DeepEqual(*got, *tt.want) {
t.Errorf("NewFixesTableFromJson() got = %v, want %v", got, tt.want) t.Errorf("NewGridMapFromJson() got = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got.SteeringSteps, tt.want.SteeringSteps) {
t.Errorf("NewGridMapFromJson(), bad steering limits: got = %v, want %v", got.SteeringSteps, tt.want.SteeringSteps)
}
if !reflect.DeepEqual(got.DistanceSteps, tt.want.DistanceSteps) {
t.Errorf("NewGridMapFromJson(), bad distance limits: got = %v, want %v", got.DistanceSteps, tt.want.DistanceSteps)
}
})
}
}
func TestGridMap_ValueOf(t *testing.T) {
type fields struct {
DistanceSteps []float64
SteeringSteps []float64
Data [][]float64
}
type args struct {
steering float64
distance float64
}
tests := []struct {
name string
fields fields
args args
want float64
wantErr bool
}{
{
name: "nominal",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: 0.,
distance: 0.,
},
want: 0,
wantErr: false,
},
{
name: "limit distance <",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: 0,
distance: 0.39999,
},
want: 0,
wantErr: false,
},
{
name: "limit distance >",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: 0,
distance: 0.400001,
},
want: -0.25,
wantErr: false,
},
{
name: "limit steering <",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: -0.660001,
distance: 0.85,
},
want: 0.25,
wantErr: false,
},
{
name: "limit steering >",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: -0.66,
distance: 0.85,
},
want: 0.5,
wantErr: false,
},
{
name: "steering < min value",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: defaultGridMap.SteeringSteps[0] - 0.1,
distance: 0.85,
},
wantErr: true,
},
{
name: "steering > max value",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: defaultGridMap.SteeringSteps[len(defaultGridMap.SteeringSteps)-1] + 0.1,
distance: 0.85,
},
wantErr: true,
},
{
name: "distance < min value",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: -0.65,
distance: defaultGridMap.DistanceSteps[0] - 0.1,
},
wantErr: true,
},
{
name: "distance > max value",
fields: fields{
DistanceSteps: defaultGridMap.DistanceSteps,
SteeringSteps: defaultGridMap.SteeringSteps,
Data: defaultGridMap.Data,
},
args: args{
steering: -0.65,
distance: defaultGridMap.DistanceSteps[len(defaultGridMap.DistanceSteps)-1] + 0.1,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := &GridMap{
DistanceSteps: tt.fields.DistanceSteps,
SteeringSteps: tt.fields.SteeringSteps,
Data: tt.fields.Data,
}
got, err := f.ValueOf(tt.args.steering, tt.args.distance)
if (err != nil) != tt.wantErr {
t.Errorf("ValueOf() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ValueOf() = %v, want %v", got, tt.want)
} }
}) })
} }

View File

@ -2,7 +2,6 @@
"steering_steps":[-1, -0.66, -0.33, 0, 0.33, 0.66, 1], "steering_steps":[-1, -0.66, -0.33, 0, 0.33, 0.66, 1],
"distance_steps": [0, 0.2, 0.4, 0.6, 0.8, 1], "distance_steps": [0, 0.2, 0.4, 0.6, 0.8, 1],
"data": [ "data": [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[0, 0, 0.25, -0.25, 0, 0], [0, 0, 0.25, -0.25, 0, 0],