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

RSDK-7466 - Change navigation config to include bounding regions #3971

Merged
merged 18 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from 11 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
6 changes: 3 additions & 3 deletions services/motion/motion.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ type MoveOnGlobeReq struct {
MovementSensorName resource.Name
// Static obstacles that should be navigated around
Obstacles []*spatialmath.GeoGeometry
// Set of bounds which the robot must remain within while navigating
BoundingRegions []*spatialmath.GeoGeometry
// Optional motion configuration
MotionCfg *MotionConfiguration

BoundingRegions []*spatialmath.GeoGeometry
Extra map[string]interface{}
Extra map[string]interface{}
}

func (r MoveOnGlobeReq) String() string {
Expand Down
22 changes: 21 additions & 1 deletion services/navigation/builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ var (
errNegativeObstaclePollingFrequencyHz = errors.New("obstacle_polling_frequency_hz must be non-negative if set")
errNegativePlanDeviationM = errors.New("plan_deviation_m must be non-negative if set")
errNegativeReplanCostFactor = errors.New("replan_cost_factor must be non-negative if set")
errGeomWithTranslation = errors.New("geometries specified through navigation are not allowed to have a translation")
)

const (
Expand Down Expand Up @@ -99,6 +100,7 @@ type Config struct {
MetersPerSec float64 `json:"meters_per_sec,omitempty"`

Obstacles []*spatialmath.GeoGeometryConfig `json:"obstacles,omitempty"`
BoundingRegions []*spatialmath.GeoGeometryConfig `json:"bounding_regions,omitempty"`
PositionPollingFrequencyHz float64 `json:"position_polling_frequency_hz,omitempty"`
ObstaclePollingFrequencyHz float64 `json:"obstacle_polling_frequency_hz,omitempty"`
PlanDeviationM float64 `json:"plan_deviation_m,omitempty"`
Expand Down Expand Up @@ -181,7 +183,16 @@ func (conf *Config) Validate(path string) ([]string, error) {
for _, obs := range conf.Obstacles {
for _, geoms := range obs.Geometries {
if !geoms.TranslationOffset.ApproxEqual(r3.Vector{}) {
return nil, errors.New("geometries specified through the navigation are not allowed to have a translation")
return nil, errors.Wrap(errGeomWithTranslation, "obstacle")
}
}
}

// Ensure bounding regions have no translation
for _, region := range conf.BoundingRegions {
for _, geoms := range region.Geometries {
if !geoms.TranslationOffset.ApproxEqual(r3.Vector{}) {
return nil, errors.Wrap(errGeomWithTranslation, "bounding region")
}
}
}
Expand Down Expand Up @@ -225,6 +236,7 @@ type builtIn struct {
// exploreMotionService will be removed once the motion explore model is integrated into motion builtin
exploreMotionService motion.Service
obstacles []*spatialmath.GeoGeometry
boundingRegions []*spatialmath.GeoGeometry

motionCfg *motion.MotionConfiguration
replanCostFactor float64
Expand Down Expand Up @@ -368,6 +380,12 @@ func (svc *builtIn) Reconfigure(ctx context.Context, deps resource.Dependencies,
return err
}

// Parse bounding regions from the configuration
newBoundingRegions, err := spatialmath.GeoGeometriesFromConfigs(svcConfig.BoundingRegions)
if err != nil {
return err
}
nicksanford marked this conversation as resolved.
Show resolved Hide resolved

// Create explore motion service
// Note: this service will disappear after the explore motion model is integrated into builtIn
exploreMotionConf := resource.Config{ConvertedAttributes: &explore.Config{}}
Expand All @@ -381,6 +399,7 @@ func (svc *builtIn) Reconfigure(ctx context.Context, deps resource.Dependencies,
svc.mapType = mapType
svc.motionService = motionSvc
svc.obstacles = newObstacles
svc.boundingRegions = newBoundingRegions
svc.replanCostFactor = replanCostFactor
svc.visionServicesByName = visionServicesByName
svc.motionCfg = &motion.MotionConfiguration{
Expand Down Expand Up @@ -524,6 +543,7 @@ func (svc *builtIn) moveToWaypoint(ctx context.Context, wp navigation.Waypoint,
MovementSensorName: svc.movementSensor.Name(),
Obstacles: svc.obstacles,
MotionCfg: svc.motionCfg,
BoundingRegions: svc.boundingRegions,
Extra: extra,
}
cancelCtx, cancelFn := context.WithCancel(ctx)
Expand Down
26 changes: 24 additions & 2 deletions services/navigation/builtin/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"math"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -574,6 +575,28 @@ func TestNavSetup(t *testing.T) {
paths, err := ns.Paths(ctx, nil)
test.That(t, err, test.ShouldBeNil)
test.That(t, paths, test.ShouldBeEmpty)

test.That(t, len(ns.(*builtIn).boundingRegions), test.ShouldEqual, 1)
test.That(t, len(ns.(*builtIn).obstacles), test.ShouldEqual, 1)
}

func TestNavSetUpFromFaultyConfig(t *testing.T) {
nicksanford marked this conversation as resolved.
Show resolved Hide resolved
cfgPath := []string{
"../data/incorrect_obstacles_nav_cfg.json",
"../data/incorrect_bounding_regions_nav_cfg.json",
}
ctx := context.Background()
logger := logging.NewTestLogger(t)
for _, path := range cfgPath {
cfg, err := config.Read(ctx, path, logger)
test.That(t, err, test.ShouldBeNil)
test.That(t, cfg.Ensure(false, logger), test.ShouldBeNil)
myRobot, err := robotimpl.New(ctx, cfg, logger)
test.That(t, err, test.ShouldBeNil)
_, err = navigation.FromRobot(myRobot, "test_navigation")
test.That(t, err, test.ShouldNotBeNil)
test.That(t, strings.Contains(err.Error(), "unsupported Geometry type"), test.ShouldBeTrue)
}
}

func setupStartWaypoint(ctx context.Context, t *testing.T, logger logging.Logger) startWaypointState {
Expand Down Expand Up @@ -1697,9 +1720,8 @@ func TestValidateGeometry(t *testing.T) {
t.Run("fail case", func(t *testing.T) {
cfg = createBox(r3.Vector{X: 10, Y: 10, Z: 10})
_, err := cfg.Validate("")
expectedErr := "geometries specified through the navigation are not allowed to have a translation"
test.That(t, err, test.ShouldNotBeNil)
test.That(t, err.Error(), test.ShouldEqual, expectedErr)
test.That(t, strings.Contains(err.Error(), errGeomWithTranslation.Error()), test.ShouldBeTrue)
nicksanford marked this conversation as resolved.
Show resolved Hide resolved
})

t.Run("success case", func(t *testing.T) {
Expand Down
71 changes: 71 additions & 0 deletions services/navigation/data/incorrect_bounding_regions_nav_cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"components":
[{
"name": "test_camera",
"type": "camera",
"model": "fake"
},
{
"model": "fake",
"name": "test_base",
"type": "base"
},
{
"name": "test_movement",
"type": "movement_sensor",
"model": "fake"
}],
"services":
[{
"name": "blue_square",
"type": "vision",
"model": "color_detector",
"attributes": {
"segment_size_px": 100,
"detect_color": "#1C4599",
"hue_tolerance_pct": 0.07,
"value_cutoff_pct": 0.15
}
},
{
"name":"test_navigation",
"type": "navigation",
"attributes": {
"base":"test_base",
"movement_sensor":"test_movement",
"obstacle_detectors": [{
"vision_service": "blue_square",
"camera": "test_camera"
}],
"bounding_regions":
[{
"geometries":
[{
"label":"aLabel",
"type": "",
"orientation":{
"type":"ov_degrees",
"value":{
"X":1,
"Y":0,
"Z":0,
"Th": 90
}
},
"translation": {
"x": 0,
"y": 0,
"z": 0
}
}],
"location":{
"latitude": 1,
"longitude": 1
}
}],
"store":{
"type":"memory"
}
}
}]
}
71 changes: 71 additions & 0 deletions services/navigation/data/incorrect_obstacles_nav_cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"components":
[{
"name": "test_camera",
"type": "camera",
"model": "fake"
},
{
"model": "fake",
"name": "test_base",
"type": "base"
},
{
"name": "test_movement",
"type": "movement_sensor",
"model": "fake"
}],
"services":
[{
"name": "blue_square",
"type": "vision",
"model": "color_detector",
"attributes": {
"segment_size_px": 100,
"detect_color": "#1C4599",
"hue_tolerance_pct": 0.07,
"value_cutoff_pct": 0.15
}
},
{
"name":"test_navigation",
"type": "navigation",
"attributes": {
"base":"test_base",
"movement_sensor":"test_movement",
"obstacle_detectors": [{
"vision_service": "blue_square",
"camera": "test_camera"
}],
"obstacles":
[{
"geometries":
[{
"label":"aLabel",
"type": "",
"orientation":{
"type":"ov_degrees",
"value":{
"X":1,
"Y":0,
"Z":0,
"Th": 90
}
},
"translation": {
"x": 0,
"y": 0,
"z": 0
}
}],
"location":{
"latitude": 1,
"longitude": 1
}
}],
"store":{
"type":"memory"
}
}
}]
}
23 changes: 23 additions & 0 deletions services/navigation/data/nav_cfg.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@
"longitude": 1
}
}],
"bounding_regions":
[{
"geometries":
[{
"label":"aLabel2",
"orientation":{
"type":"ov_degrees",
"value":{
"X":1,
"Y":0,
"Z":0,
"Th": -90
}
},
"x":20,
"y":20,
"z":20
}],
"location":{
"latitude": 2,
"longitude": 2
}
}],
"store":{
"type":"memory"
}
Expand Down
Loading