robocar-steering/pkg/steering/corrector.go
2022-08-22 19:51:44 +02:00

117 lines
3.2 KiB
Go

package steering
import (
"fmt"
"github.com/cyrilix/robocar-protobuf/go/events"
"go.uber.org/zap"
)
type Corrector struct {
fixValues FixesTable
}
/*
FixFromObjectPosition modify steering value according object positions
1. To compute steering correction, split in image in zones and define correction value for each zone
Steering computed
: -1 -0.66 -0.33 0 0.33 0.66 1
0% |-----|-----|-----|-----|-----|-----|
: | 0 | 0 | 0 | 0 | 0 | 0 |
20% |-----|-----|-----|-----|-----|-----|
: | 0 | 0 | 0 | 0 | 0 | 0 |
40% |-----|-----|-----|-----|-----|-----|
: | 0 | 0 | 0.25|-0.25| 0 | 0 |
60% |-----|-----|-----|-----|-----|-----|
: | 0 | 0.25| 0.5 |-0.5 |-0.25| 0 |
80% |-----|-----|-----|-----|-----|-----|
: |-0.25|-0.5 | 1 | -1 |-0.5 | 0.25|
100%|-----|-----|-----|-----|-----|-----|
2. For straight (current steering near of 0), search nearest object and if:
* left and right values < 0: use correction from right value according image splitting
* left and right values > 0: use correction from left value according image splitting
* left < 0 and right values > 0: use (right + (right - left) / 2) value
3. If current steering != 0 (turn on left or right), shift right and left values proportionnaly to current steering and
apply 2.
*/
func (c *Corrector) FixFromObjectPosition(currentSteering float64, objects []*events.Object) float64 {
// TODO, group rectangle
if len(objects) == 0 {
return currentSteering
}
// get nearest object
nearest, err := c.nearObject(objects)
if err != nil {
zap.S().Warnf("unexpected error on nearest seach object, ignore objects: %v", err)
return currentSteering
}
if currentSteering > 0.1 && currentSteering < 0.1 {
if nearest.Bottom < 0.4 {
// object is far, so no need to fix steering now
return currentSteering
}
if nearest.Left < 0 && nearest.Right < 0 {
return currentSteering + c.fixValues.ValueOf(currentSteering, nearest.Right)
}
if nearest.Left > 0 && nearest.Right > 0 {
return currentSteering + c.fixValues.ValueOf(currentSteering, nearest.Left)
}
return currentSteering + c.fixValues.ValueOf(currentSteering, nearest.Left+(nearest.Right-nearest.Left)/2.)
}
// Search if current steering is near of Right or Left
return currentSteering
}
func (c *Corrector) nearObject(objects []*events.Object) (*events.Object, error) {
if len(objects) == 0 {
return nil, fmt.Errorf("list objects must contain at least one object")
}
if len(objects) == 1 {
return objects[0], nil
}
var result *events.Object
for _, obj := range objects {
if result == nil || obj.Bottom > result.Bottom {
result = obj
continue
}
}
return result, nil
}
type FixesTable struct {
values map[string]map[int]float64
}
func (f *FixesTable) ValueOf(steering float64, distance float32) float64 {
var key string
if steering < -0.66 {
key = "<-0.66"
} else if steering < -0.33 {
key = "-0.66:-0.33"
} else if steering < 0 {
key = "-0.33:0"
} else if steering < 0.33 {
key = "0:0.33"
} else if steering < 0.66 {
key = "0.33:0.66"
} else {
key = ">= 0.66"
}
keyDistance := int(distance / 20)
return f.values[key][keyDistance]
}