From 7e90f635a0eba9ede0d3d893e12004c255adcbfc Mon Sep 17 00:00:00 2001 From: Clyde Bazile <34226620+bazile-clyde@users.noreply.github.com> Date: Thu, 13 Oct 2022 15:16:57 -0400 Subject: [PATCH 01/12] DATA 498 add labels to geometries in rdk (#1491) --- .../builtin/object_segmentation_test.go | 5 +- services/vision/client.go | 11 +++- services/vision/server_test.go | 3 + spatialmath/box.go | 7 ++- spatialmath/point.go | 7 ++- spatialmath/sphere.go | 7 ++- vision/object.go | 9 ++- vision/objectdetection/color_detector.go | 7 ++- vision/segmentation/color_objects.go | 2 + vision/segmentation/color_objects_test.go | 5 ++ vision/segmentation/detections_to_objects.go | 57 ++++++++----------- vision/segmentation/radius_clustering.go | 3 +- vision/segmentation/radius_clustering_test.go | 12 ++-- .../segmentation/radius_clustering_voxel.go | 5 +- .../radius_clustering_voxel_test.go | 4 +- vision/segmentation/segments.go | 26 +++++++-- 16 files changed, 114 insertions(+), 56 deletions(-) diff --git a/services/vision/builtin/object_segmentation_test.go b/services/vision/builtin/object_segmentation_test.go index ed962a21181a..cf9f19f8ef70 100644 --- a/services/vision/builtin/object_segmentation_test.go +++ b/services/vision/builtin/object_segmentation_test.go @@ -244,11 +244,13 @@ func TestFullClientServerLoop(t *testing.T) { client := vision.NewClientFromConn(context.Background(), conn, testVisionServiceName, logger) test.That(t, err, test.ShouldBeNil) + expectedLabel := "test_label" params := config.AttributeMap{ "min_points_in_plane": 100, "min_points_in_segment": 3, "clustering_radius_mm": 5., "mean_k_filtering": 10., + "label": expectedLabel, } err = client.AddSegmenter( context.Background(), @@ -262,10 +264,11 @@ func TestFullClientServerLoop(t *testing.T) { expectedBoxes := makeExpectedBoxes(t) for _, seg := range segs { - box, err := pointcloud.BoundingBoxFromPointCloud(seg) + box, err := pointcloud.BoundingBoxFromPointCloudWithLabel(seg, seg.Geometry.Label()) test.That(t, err, test.ShouldBeNil) test.That(t, box, test.ShouldNotBeNil) test.That(t, box.AlmostEqual(expectedBoxes[0]) || box.AlmostEqual(expectedBoxes[1]), test.ShouldBeTrue) + test.That(t, box.Label(), test.ShouldEqual, expectedLabel) } test.That(t, utils.TryClose(context.Background(), client), test.ShouldBeNil) diff --git a/services/vision/client.go b/services/vision/client.go index 503d4e26b3dd..f228cda276b0 100644 --- a/services/vision/client.go +++ b/services/vision/client.go @@ -316,7 +316,16 @@ func protoToObjects(pco []*commonpb.PointCloudObject) ([]*vision.Object, error) if err != nil { return nil, err } - objects[i], err = vision.NewObject(pc) + // Sets the label to the first non-empty label of any geometry; defaults to the empty string. + label := func() string { + for _, g := range o.Geometries.GetGeometries() { + if g.GetLabel() != "" { + return g.GetLabel() + } + } + return "" + }() + objects[i], err = vision.NewObjectWithLabel(pc, label) if err != nil { return nil, err } diff --git a/services/vision/server_test.go b/services/vision/server_test.go index 96e119d6c02d..8b94da6fdac6 100644 --- a/services/vision/server_test.go +++ b/services/vision/server_test.go @@ -292,11 +292,13 @@ func TestServerAddRemoveSegmenter(t *testing.T) { } func TestServerSegmentationGetObjects(t *testing.T) { + expectedLabel := "test_label" params := config.AttributeMap{ "min_points_in_plane": 100, "min_points_in_segment": 3, "clustering_radius_mm": 5., "mean_k_filtering": 10., + "label": expectedLabel, } segmenter, err := segmentation.NewRadiusClustering(params) test.That(t, err, test.ShouldBeNil) @@ -342,6 +344,7 @@ func TestServerSegmentationGetObjects(t *testing.T) { box, err := spatialmath.NewGeometryFromProto(object.Geometries.Geometries[0]) test.That(t, err, test.ShouldBeNil) test.That(t, box.AlmostEqual(expectedBoxes[0]) || box.AlmostEqual(expectedBoxes[1]), test.ShouldBeTrue) + test.That(t, box.Label(), test.ShouldEqual, expectedLabel) } } diff --git a/spatialmath/box.go b/spatialmath/box.go index 1cb0267647ac..b3c2d85a882a 100644 --- a/spatialmath/box.go +++ b/spatialmath/box.go @@ -54,9 +54,12 @@ func NewBox(pose Pose, dims r3.Vector, label string) (Geometry, error) { return &box{pose, [3]float64{0.5 * dims.X, 0.5 * dims.Y, 0.5 * dims.Z}, label}, nil } -// Label returns the label of the box. +// Label returns the label of this box. func (b *box) Label() string { - return b.label + if b != nil { + return b.label + } + return "" } // Pose returns the pose of the box. diff --git a/spatialmath/point.go b/spatialmath/point.go index e68461998b7d..698b4245b34e 100644 --- a/spatialmath/point.go +++ b/spatialmath/point.go @@ -48,9 +48,12 @@ func NewPoint(pt r3.Vector, label string) Geometry { return &point{NewPoseFromPoint(pt), label} } -// Label returns the labels of the point. +// Label returns the labels of this point. func (pt *point) Label() string { - return pt.label + if pt != nil { + return pt.label + } + return "" } // Pose returns the pose of the point. diff --git a/spatialmath/sphere.go b/spatialmath/sphere.go index 2a70f7735431..73fcb9421fc5 100644 --- a/spatialmath/sphere.go +++ b/spatialmath/sphere.go @@ -56,9 +56,12 @@ func NewSphere(pt r3.Vector, radius float64, label string) (Geometry, error) { return &sphere{NewPoseFromPoint(pt), radius, label}, nil } -// Label returns the label of the sphere. +// Label returns the label of this sphere. func (s *sphere) Label() string { - return s.label + if s != nil { + return s.label + } + return "" } // Pose returns the pose of the sphere. diff --git a/vision/object.go b/vision/object.go index 7950a230790e..fbd2e0b7b6e9 100644 --- a/vision/object.go +++ b/vision/object.go @@ -12,12 +12,17 @@ type Object struct { Geometry spatialmath.Geometry } -// NewObject calculates the metadata for an input pointcloud. +// NewObject creates a new vision.Object from a point cloud with an empty label. func NewObject(cloud pc.PointCloud) (*Object, error) { + return NewObjectWithLabel(cloud, "") +} + +// NewObjectWithLabel creates a new vision.Object from a point cloud with the given label. +func NewObjectWithLabel(cloud pc.PointCloud, label string) (*Object, error) { if cloud == nil { return NewEmptyObject(), nil } - box, err := pc.BoundingBoxFromPointCloud(cloud) + box, err := pc.BoundingBoxFromPointCloudWithLabel(cloud, label) if err != nil { return nil, err } diff --git a/vision/objectdetection/color_detector.go b/vision/objectdetection/color_detector.go index 60cd1f7805de..04b4fc886488 100644 --- a/vision/objectdetection/color_detector.go +++ b/vision/objectdetection/color_detector.go @@ -15,6 +15,7 @@ type ColorDetectorConfig struct { SaturationCutoff float64 `json:"saturation_cutoff_pct,omitempty"` ValueCutoff float64 `json:"value_cutoff_pct,omitempty"` DetectColorString string `json:"detect_color"` // hex string "#RRGGBB" + Label string `json:"label,omitempty"` } // NewColorDetector is a detector that identifies objects based on color. @@ -68,7 +69,11 @@ func NewColorDetector(cfg *ColorDetectorConfig) (Detector, error) { } valid = makeValidColorFunction(loValid, hiValid, sat, val) } - cd := connectedComponentDetector{valid, hueToString(hue)} + label := cfg.Label + if label == "" { + label = hueToString(hue) + } + cd := connectedComponentDetector{valid, label} // define the filter segmentSize := 5000 // default value if cfg.SegmentSize != 0 { diff --git a/vision/segmentation/color_objects.go b/vision/segmentation/color_objects.go index f0f72b412642..86bed0533e78 100644 --- a/vision/segmentation/color_objects.go +++ b/vision/segmentation/color_objects.go @@ -19,6 +19,7 @@ type ColorObjectsConfig struct { MeanK int `json:"mean_k"` // used for StatisticalFilter Sigma float64 `json:"sigma"` // used for StatisticalFilter MinSegmentSize int `json:"min_points_in_segment"` + Label string `json:"label,omitempty"` } // CheckValid checks to see in the input values are valid. @@ -67,6 +68,7 @@ func ColorObjects(params config.AttributeMap) (Segmenter, error) { SaturationCutoff: cfg.SaturationCutoff, ValueCutoff: cfg.ValueCutoff, DetectColorString: cfg.Color, + Label: cfg.Label, } detector, err := objectdetection.NewColorDetector(detCfg) if err != nil { diff --git a/vision/segmentation/color_objects_test.go b/vision/segmentation/color_objects_test.go index a1aa89e8f4b1..aee1c9a1763e 100644 --- a/vision/segmentation/color_objects_test.go +++ b/vision/segmentation/color_objects_test.go @@ -32,12 +32,14 @@ func TestColorObjects(t *testing.T) { ) test.That(t, err, test.ShouldBeNil) // create config + expectedLabel := "test_label" cfg := config.AttributeMap{ "hue_tolerance_pct": 0.025, "detect_color": "#6D2814", "mean_k": 50, "sigma": 1.5, "min_points_in_segment": 1000, + "label": expectedLabel, } // run segmenter segmenter, err := segmentation.ColorObjects(cfg) @@ -45,6 +47,7 @@ func TestColorObjects(t *testing.T) { objects, err := segmenter(context.Background(), cam) test.That(t, err, test.ShouldBeNil) test.That(t, objects, test.ShouldHaveLength, 1) + test.That(t, objects[0].Geometry.Label(), test.ShouldEqual, expectedLabel) // create config with no mean_k filtering cfg = config.AttributeMap{ "hue_tolerance_pct": 0.025, @@ -52,6 +55,7 @@ func TestColorObjects(t *testing.T) { "mean_k": -1, "sigma": 1.5, "min_points_in_segment": 1000, + "label": expectedLabel, } // run segmenter segmenter, err = segmentation.ColorObjects(cfg) @@ -59,6 +63,7 @@ func TestColorObjects(t *testing.T) { objects, err = segmenter(context.Background(), cam) test.That(t, err, test.ShouldBeNil) test.That(t, objects, test.ShouldHaveLength, 1) + test.That(t, objects[0].Geometry.Label(), test.ShouldEqual, expectedLabel) } func TestColorObjectsValidate(t *testing.T) { diff --git a/vision/segmentation/detections_to_objects.go b/vision/segmentation/detections_to_objects.go index 6084d137c6e8..20c8a531fe45 100644 --- a/vision/segmentation/detections_to_objects.go +++ b/vision/segmentation/detections_to_objects.go @@ -68,23 +68,26 @@ func DetectionSegmenter(detector objectdetection.Detector, meanK int, sigma, con if err != nil { return nil, err } - // TODO(bhaney): Is there a way to just project the detection boxes themselves? - pcs, err := detectionsToPointClouds(dets, confidenceThresh, img, dm, proj) - if err != nil { - return nil, err - } - // filter the point clouds to get rid of outlier points - objects := make([]*vision.Object, 0, len(pcs)) - for _, pc := range pcs { - filtered, err := filter(pc) + + objects := make([]*vision.Object, 0, len(dets)) + for _, d := range dets { + if d.Score() < confidenceThresh { + continue + } + // TODO(bhaney): Is there a way to just project the detection boxes themselves? + pc, err := detectionToPointCloud(d, img, dm, proj) + if err != nil { + return nil, err + } + pc, err = filter(pc) if err != nil { return nil, err } // if object was filtered away, skip it - if filtered.Size() == 0 { + if pc.Size() == 0 { continue } - obj, err := vision.NewObject(filtered) + obj, err := vision.NewObjectWithLabel(pc, d.Label()) if err != nil { return nil, err } @@ -95,28 +98,18 @@ func DetectionSegmenter(detector objectdetection.Detector, meanK int, sigma, con return seg, nil } -// detectionsToPointClouds turns 2D detections into 3D point clodus using the intrinsic camera projection parameters and the image. -func detectionsToPointClouds( - dets []objectdetection.Detection, - confidenceThresh float64, +func detectionToPointCloud( + d objectdetection.Detection, im *rimage.Image, dm *rimage.DepthMap, proj transform.Projector, -) ([]pointcloud.PointCloud, error) { - // project 2D detections to 3D pointclouds - pcs := make([]pointcloud.PointCloud, 0, len(dets)) - for _, d := range dets { - if d.Score() < confidenceThresh { - continue - } - bb := d.BoundingBox() - if bb == nil { - return nil, errors.New("detection bounding box cannot be nil") - } - pc, err := proj.RGBDToPointCloud(im, dm, *bb) - if err != nil { - return nil, err - } - pcs = append(pcs, pc) +) (pointcloud.PointCloud, error) { + bb := d.BoundingBox() + if bb == nil { + return nil, errors.New("detection bounding box cannot be nil") + } + pc, err := proj.RGBDToPointCloud(im, dm, *bb) + if err != nil { + return nil, err } - return pcs, nil + return pc, nil } diff --git a/vision/segmentation/radius_clustering.go b/vision/segmentation/radius_clustering.go index 2ea38bfbbd59..40b303777175 100644 --- a/vision/segmentation/radius_clustering.go +++ b/vision/segmentation/radius_clustering.go @@ -19,6 +19,7 @@ type RadiusClusteringConfig struct { MinPtsInSegment int `json:"min_points_in_segment"` ClusteringRadiusMm float64 `json:"clustering_radius_mm"` MeanKFiltering int `json:"mean_k_filtering"` + Label string `json:"label,omitempty"` } // CheckValid checks to see in the input values are valid. @@ -93,7 +94,7 @@ func (rcc *RadiusClusteringConfig) RadiusClustering(ctx context.Context, c camer if err != nil { return nil, err } - objects, err := NewSegmentsFromSlice(segments) + objects, err := NewSegmentsFromSlice(segments, rcc.Label) if err != nil { return nil, err } diff --git a/vision/segmentation/radius_clustering_test.go b/vision/segmentation/radius_clustering_test.go index 9bd8d3d5150b..6ef730dbf7b6 100644 --- a/vision/segmentation/radius_clustering_test.go +++ b/vision/segmentation/radius_clustering_test.go @@ -43,6 +43,7 @@ func TestPixelSegmentation(t *testing.T) { return pc.NewFromLASFile(artifact.MustPath("pointcloud/test.las"), logger) } // do segmentation + expectedLabel := "test_label" objConfig := config.AttributeMap{ "min_points_in_plane": 50000, "min_points_in_segment": 500, @@ -50,12 +51,13 @@ func TestPixelSegmentation(t *testing.T) { "mean_k_filtering": 50.0, "extra_uneeded_param": 4444, "another_extra_one": "hey", + "label": expectedLabel, } segmenter, err := segmentation.NewRadiusClustering(objConfig) test.That(t, err, test.ShouldBeNil) segments, err := segmenter(context.Background(), injectCamera) test.That(t, err, test.ShouldBeNil) - testSegmentation(t, segments) + testSegmentation(t, segments, expectedLabel) // do segmentation with no mean k filtering objConfig = config.AttributeMap{ "min_points_in_plane": 50000, @@ -64,19 +66,20 @@ func TestPixelSegmentation(t *testing.T) { "mean_k_filtering": -1., "extra_uneeded_param": 4444, "another_extra_one": "hey", + "label": expectedLabel, } segmenter, err = segmentation.NewRadiusClustering(objConfig) test.That(t, err, test.ShouldBeNil) segments, err = segmenter(context.Background(), injectCamera) test.That(t, err, test.ShouldBeNil) - testSegmentation(t, segments) + testSegmentation(t, segments, expectedLabel) } -func testSegmentation(t *testing.T, segments []*vision.Object) { +func testSegmentation(t *testing.T, segments []*vision.Object, expectedLabel string) { t.Helper() test.That(t, len(segments), test.ShouldBeGreaterThan, 0) for _, seg := range segments { - box, err := pc.BoundingBoxFromPointCloud(seg) + box, err := pc.BoundingBoxFromPointCloudWithLabel(seg, seg.Geometry.Label()) if seg.Size() == 0 { test.That(t, box, test.ShouldBeNil) test.That(t, err, test.ShouldNotBeNil) @@ -85,5 +88,6 @@ func testSegmentation(t *testing.T, segments []*vision.Object) { test.That(t, box, test.ShouldNotBeNil) test.That(t, err, test.ShouldBeNil) test.That(t, box.AlmostEqual(seg.Geometry), test.ShouldBeTrue) + test.That(t, box.Label(), test.ShouldEqual, expectedLabel) } } diff --git a/vision/segmentation/radius_clustering_voxel.go b/vision/segmentation/radius_clustering_voxel.go index 4a654e03e2c0..6fb6b7c0b58b 100644 --- a/vision/segmentation/radius_clustering_voxel.go +++ b/vision/segmentation/radius_clustering_voxel.go @@ -25,6 +25,7 @@ type RadiusClusteringVoxelConfig struct { AngleThresh float64 `json:"angle_threshold_degs"` CosineThresh float64 `json:"cosine_threshold"` // between -1 and 1, the value after evaluating Cosine(theta) DistanceThresh float64 `json:"distance_threshold_mm"` + Label string `json:"label,omitempty"` } // CheckValid checks to see in the input values are valid. @@ -35,7 +36,7 @@ func (rcc *RadiusClusteringVoxelConfig) CheckValid() error { if rcc.Lambda <= 0 { return errors.Errorf("lambda must be greater than 0, got %v", rcc.Lambda) } - radiusClustering := RadiusClusteringConfig{rcc.MinPtsInPlane, rcc.MinPtsInSegment, rcc.ClusteringRadiusMm, 50.0} + radiusClustering := RadiusClusteringConfig{rcc.MinPtsInPlane, rcc.MinPtsInSegment, rcc.ClusteringRadiusMm, 50.0, rcc.Label} err := radiusClustering.CheckValid() if err != nil { return err @@ -104,7 +105,7 @@ func (rcc *RadiusClusteringVoxelConfig) RadiusClusteringVoxels(ctx context.Conte return nil, err } objects = pc.PrunePointClouds(objects, rcc.MinPtsInSegment) - segments, err := NewSegmentsFromSlice(objects) + segments, err := NewSegmentsFromSlice(objects, rcc.Label) if err != nil { return nil, err } diff --git a/vision/segmentation/radius_clustering_voxel_test.go b/vision/segmentation/radius_clustering_voxel_test.go index 34eadc4304b1..98167c8ec5d0 100644 --- a/vision/segmentation/radius_clustering_voxel_test.go +++ b/vision/segmentation/radius_clustering_voxel_test.go @@ -51,6 +51,7 @@ func TestVoxelSegmentMeans(t *testing.T) { } // Do voxel segmentation + expectedLabel := "test_label" voxObjConfig := config.AttributeMap{ "voxel_size": 1.0, "lambda": 0.1, @@ -61,11 +62,12 @@ func TestVoxelSegmentMeans(t *testing.T) { "angle_threshold": 30, "cosine_threshold": 0.1, "distance_threshold": 0.1, + "label": expectedLabel, } segmenter, err := segmentation.NewRadiusClusteringFromVoxels(voxObjConfig) test.That(t, err, test.ShouldBeNil) voxSegments, err := segmenter(context.Background(), cam) test.That(t, err, test.ShouldBeNil) - testSegmentation(t, voxSegments) + testSegmentation(t, voxSegments, expectedLabel) } diff --git a/vision/segmentation/segments.go b/vision/segmentation/segments.go index 58fee6c7f4fa..3d5bf5a6f48d 100644 --- a/vision/segmentation/segments.go +++ b/vision/segmentation/segments.go @@ -25,10 +25,10 @@ func NewSegments() *Segments { } // NewSegmentsFromSlice creates a Segments struct from a slice of point clouds. -func NewSegmentsFromSlice(clouds []pc.PointCloud) (*Segments, error) { +func NewSegmentsFromSlice(clouds []pc.PointCloud, label string) (*Segments, error) { segments := NewSegments() for i, cloud := range clouds { - seg, err := vision.NewObject(cloud) + seg, err := vision.NewObjectWithLabel(cloud, label) if err != nil { return nil, err } @@ -64,6 +64,16 @@ func (c *Segments) SelectPointCloudFromPoint(x, y, z float64) (pc.PointCloud, er return nil, fmt.Errorf("no segment found at point (%v, %v, %v)", x, y, z) } +// getPointCloudAndLabel returns the *vision.Object from `objs` at `idx` and the label from +// vision.Object.spatialmath.Geometry if the Geometry exists, or otherwise an empty string. +func getPointCloudAndLabel(objs []*vision.Object, idx int) (*vision.Object, string) { + obj := objs[idx] + if obj.Geometry != nil { + return obj, obj.Geometry.Label() + } + return obj, "" +} + // AssignCluster assigns the given point to the cluster with the given index. func (c *Segments) AssignCluster(point r3.Vector, data pc.Data, index int) error { for index >= len(c.Objects) { @@ -77,7 +87,8 @@ func (c *Segments) AssignCluster(point r3.Vector, data pc.Data, index int) error if c.Objects[index].Size() == 0 { return nil } - c.Objects[index].Geometry, err = pc.BoundingBoxFromPointCloud(c.Objects[index]) + idx, label := getPointCloudAndLabel(c.Objects, index) + c.Objects[index].Geometry, err = pc.BoundingBoxFromPointCloudWithLabel(idx, label) if err != nil { return err } @@ -86,7 +97,7 @@ func (c *Segments) AssignCluster(point r3.Vector, data pc.Data, index int) error // MergeClusters moves all the points in index "from" to the segment at index "to". func (c *Segments) MergeClusters(from, to int) error { - // ensure no out of bounrs errors + // ensure no out of bounds errors index := utils.MaxInt(from, to) for index >= len(c.Objects) { c.Objects = append(c.Objects, vision.NewEmptyObject()) @@ -108,7 +119,12 @@ func (c *Segments) MergeClusters(from, to int) error { return err } c.Objects[from] = vision.NewEmptyObject() - c.Objects[to].Geometry, err = pc.BoundingBoxFromPointCloud(c.Objects[to]) + // because BoundingBoxFromPointCloudWithLabel takes a PointCloud interface as its first argument, only the + // vision.Object.pointcloud.PointCloud is passed to this method from our vision.Object, not the spatialmath.Geometry. + // Consequently, it cannot access spatialmath.Geometry.Label(). Therefore, we must pass the label here before this + // information is lost. + t, label := getPointCloudAndLabel(c.Objects, to) + c.Objects[to].Geometry, err = pc.BoundingBoxFromPointCloudWithLabel(t, label) if err != nil { return err } From 56a8865851603dc53943dafe054926538f0220a1 Mon Sep 17 00:00:00 2001 From: JohnN193 <92045055+JohnN193@users.noreply.github.com> Date: Thu, 13 Oct 2022 15:55:28 -0400 Subject: [PATCH 02/12] [DATA-558] remove SaveMapLoc from orbslam_yaml.go (#1493) --- services/slam/builtin/builtin.go | 1 + services/slam/builtin/builtin_test.go | 1 + services/slam/builtin/orbslam_yaml.go | 12 +++--------- services/slam/builtin/orbslam_yaml_test.go | 9 --------- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/services/slam/builtin/builtin.go b/services/slam/builtin/builtin.go index ab76b7c4641a..13ed71c8f713 100644 --- a/services/slam/builtin/builtin.go +++ b/services/slam/builtin/builtin.go @@ -664,6 +664,7 @@ func (slamSvc *builtIn) GetSLAMProcessConfig() pexec.ProcessConfig { args = append(args, "-data_dir="+slamSvc.dataDirectory) args = append(args, "-input_file_pattern="+slamSvc.inputFilePattern) args = append(args, "-port="+slamSvc.port) + args = append(args, "--aix-auto-update") return pexec.ProcessConfig{ ID: "slam_" + slamSvc.slamLib.AlgoName, diff --git a/services/slam/builtin/builtin_test.go b/services/slam/builtin/builtin_test.go index 85dfeb89c31c..066ad37723ab 100644 --- a/services/slam/builtin/builtin_test.go +++ b/services/slam/builtin/builtin_test.go @@ -881,6 +881,7 @@ func TestSLAMProcessSuccess(t *testing.T) { {"-data_dir=" + name}, {"-input_file_pattern=10:200:1"}, {"-port=localhost:4445"}, + {"--aix-auto-update"}, } for i, s := range cmd { diff --git a/services/slam/builtin/orbslam_yaml.go b/services/slam/builtin/orbslam_yaml.go index 0c750cc0ac45..f392db09660c 100644 --- a/services/slam/builtin/orbslam_yaml.go +++ b/services/slam/builtin/orbslam_yaml.go @@ -85,7 +85,7 @@ func (slamSvc *builtIn) orbCamMaker(camProperties *transform.PinholeCameraModel) if orbslam.Stereob, err = slamSvc.orbConfigToFloat("stereo_b", 0.0745); err != nil { return nil, err } - tmp, err := slamSvc.orbConfigToInt("rgb_flag", 1) + tmp, err := slamSvc.orbConfigToInt("rgb_flag", 0) if err != nil { return nil, err } @@ -119,7 +119,6 @@ type ORBsettings struct { StereoThDepth float64 `yaml:"Stereo.ThDepth"` DepthMapFactor float64 `yaml:"RGBD.DepthMapFactor"` FPSCamera int16 `yaml:"Camera.fps"` - SaveMapLoc string `yaml:"System.SaveAtlasToFile"` LoadMapLoc string `yaml:"System.LoadAtlasFromFile"` } @@ -145,19 +144,14 @@ func (slamSvc *builtIn) orbGenYAML(ctx context.Context, cam camera.Camera) error return err } - // TODO change time format to .Format(time.RFC3339Nano) https://viam.atlassian.net/browse/DATA-277 - timeStampNow := time.Now().UTC().Format(slamTimeFormat) - saveMapName := filepath.Join(slamSvc.dataDirectory, "map", slamSvc.cameraName+"_data_"+timeStampNow) - // timestamp to save at end of run - orbslam.SaveMapLoc = "\"" + saveMapName + "\"" - // Check for maps in the specified directory and add map to yaml config loadMapTimeStamp, loadMapName, err := slamSvc.checkMaps() if err != nil { slamSvc.logger.Debugf("Error occurred while parsing %s for maps, building map from scratch", slamSvc.dataDirectory) } if loadMapTimeStamp == "" { - loadMapTimeStamp = timeStampNow + // TODO change time format to .Format(time.RFC3339Nano) https://viam.atlassian.net/browse/DATA-277 + loadMapTimeStamp = time.Now().UTC().Format(slamTimeFormat) } else { orbslam.LoadMapLoc = "\"" + loadMapName + "\"" } diff --git a/services/slam/builtin/orbslam_yaml_test.go b/services/slam/builtin/orbslam_yaml_test.go index 0c54df1c4b46..3aeb2164d718 100644 --- a/services/slam/builtin/orbslam_yaml_test.go +++ b/services/slam/builtin/orbslam_yaml_test.go @@ -143,7 +143,6 @@ func TestOrbslamYAMLNew(t *testing.T) { //save a fake map for the next map using the previous timestamp fakeMap = filepath.Join(name, "map", attrCfgGood.Sensors[0]+"_data_"+yamlFileTimeStampGood) - test.That(t, orbslam.SaveMapLoc, test.ShouldEqual, "\""+fakeMap+"\"") outfile, err := os.Create(fakeMap + ".osa") test.That(t, err, test.ShouldBeNil) err = outfile.Close() @@ -173,14 +172,6 @@ func TestOrbslamYAMLNew(t *testing.T) { err = yaml.Unmarshal(yamlData, &orbslam) test.That(t, err, test.ShouldBeNil) test.That(t, orbslam.LoadMapLoc, test.ShouldEqual, "\""+fakeMap+"\"") - - // compare timestamps, saveTimeStamp should be more recent than oldTimeStamp - saveTimestampLoc := strings.Index(orbslam.SaveMapLoc, "_data_") + len("_data_") - saveTimeStamp, err := time.Parse(slamTimeFormat, orbslam.SaveMapLoc[saveTimestampLoc:len(orbslam.SaveMapLoc)-1]) - test.That(t, err, test.ShouldBeNil) - oldTimeStamp, err := time.Parse(slamTimeFormat, fakeMapTimestamp) - test.That(t, err, test.ShouldBeNil) - test.That(t, saveTimeStamp.After(oldTimeStamp), test.ShouldBeTrue) }) t.Run("New orbslamv3 service with high dataRateMs", func(t *testing.T) { From 2f8e4e78f215f6517e67f4bf9814ca19310e1d6b Mon Sep 17 00:00:00 2001 From: Cheuk <90270663+cheukt@users.noreply.github.com> Date: Thu, 13 Oct 2022 17:33:51 -0400 Subject: [PATCH 03/12] RSDK-739 remove misleading log when getting cloud config (#1495) a corresponding change to add more detail in error messages is in viamrobotics/app#747 --- config/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/reader.go b/config/reader.go index 40cc35d8fe6f..2592c3310bc0 100644 --- a/config/reader.go +++ b/config/reader.go @@ -420,7 +420,7 @@ func readFromCloud( unprocessedConfig, cached, err := getFromCloudOrCache(ctx, cloudCfg, shouldReadFromCache, logger) if err != nil { if !cached { - err = errors.Wrapf(err, "error getting cloud config, please make sure the RDK config located in %v is valid", originalCfg.ConfigFilePath) + err = errors.Wrap(err, "error getting cloud config") } return nil, err } From e24925cefd2a98539822f76227b9f88864fabea3 Mon Sep 17 00:00:00 2001 From: "Devin T. Currie" Date: Fri, 14 Oct 2022 11:43:08 -0400 Subject: [PATCH 04/12] APP-804 Fix component type tag rendering (#1494) --- Makefile | 6 +++- etc/e2e.sh | 29 +++++++++++++++++-- .../cypress/data/test_robot_config.json | 5 ++++ web/frontend/cypress/e2e/rc-controls.cy.ts | 1 + web/frontend/src/app.vue | 2 -- web/frontend/src/components/arm.vue | 1 + web/frontend/src/components/audio-input.vue | 2 +- web/frontend/src/components/base.vue | 1 + web/frontend/src/components/board.vue | 1 + web/frontend/src/components/camera.vue | 4 +-- web/frontend/src/components/gamepad.vue | 1 + web/frontend/src/components/gantry.vue | 1 + web/frontend/src/components/gripper.vue | 1 + .../src/components/input-controller.vue | 1 + web/frontend/src/components/motor-detail.vue | 1 + .../src/components/movement-sensor.vue | 1 + web/frontend/src/components/navigation.vue | 3 +- web/frontend/src/components/servo.vue | 1 + web/frontend/src/components/slam.vue | 3 +- web/runtime-shared/static/control.js | 4 +-- web/runtime-shared/static/main.css | 2 +- 21 files changed, 57 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 431779f25bad..fe9c1a085610 100644 --- a/Makefile +++ b/Makefile @@ -76,7 +76,11 @@ test-pi: test-e2e: go build $(LDFLAGS) -o bin/test-e2e/server web/cmd/server/main.go - ./etc/e2e.sh + ./etc/e2e.sh -o 'run' + +open-cypress-ui: + go build $(LDFLAGS) -o bin/test-e2e/server web/cmd/server/main.go + ./etc/e2e.sh -o 'open' test-integration: cd services/slam/builtin && sudo --preserve-env=APPIMAGE_EXTRACT_AND_RUN go test -v -run TestOrbslamIntegration diff --git a/etc/e2e.sh b/etc/e2e.sh index bfd93c16077c..ecaa6b3ed2dd 100755 --- a/etc/e2e.sh +++ b/etc/e2e.sh @@ -5,14 +5,37 @@ ROOT_DIR="$DIR/../" cd $ROOT_DIR -# Run server with test config +helpFunction() +{ + echo "" + echo "Usage: $0 -o " + echo -e "\t-o Whether or not to open the cypress UI or just run the tests" + exit 1 # Exit script after printing help +} + +while getopts "o:" opt +do + case "$opt" in + o ) OPEN="$OPTARG" ;; + ? ) helpFunction ;; + esac +done +# Run server with test config nohup ./bin/test-e2e/server --config web/frontend/cypress/data/test_robot_config.json & # Wait for interface to be live before running tests until nc -vz 127.0.0.1 8080; do sleep 2; done # Run tests (giving a long timeout as it can run slow in CI) - cd web/frontend -npm run cypress:ci -- -c defaultCommandTimeout=30000 + +if [ $OPEN == "open" ] ; then + npm run cypress -- -c defaultCommandTimeout=30000 +elif [ $OPEN == "run" ] ; then + npm run cypress:ci -- -c defaultCommandTimeout=30000 +else + helpFunction +fi + + diff --git a/web/frontend/cypress/data/test_robot_config.json b/web/frontend/cypress/data/test_robot_config.json index b4d28dc00d1b..bc8cee84ca5f 100644 --- a/web/frontend/cypress/data/test_robot_config.json +++ b/web/frontend/cypress/data/test_robot_config.json @@ -51,6 +51,11 @@ "type": "input_controller", "model": "fake" }, + { + "name": "test_audio", + "type": "audio_input", + "model": "fake" + }, { "name": "test_servo", "type": "servo", diff --git a/web/frontend/cypress/e2e/rc-controls.cy.ts b/web/frontend/cypress/e2e/rc-controls.cy.ts index 57b1ca9590f1..3849cc664065 100644 --- a/web/frontend/cypress/e2e/rc-controls.cy.ts +++ b/web/frontend/cypress/e2e/rc-controls.cy.ts @@ -12,6 +12,7 @@ describe('should load the page', () => { cy.contains('h2', 'test_motor_right').should('exist'); cy.contains('h2', 'test_input').should('exist'); cy.contains('h2', 'WebGamepad').should('exist'); + cy.contains('h2', 'test_audio').should('exist'); cy.contains('h2', 'test_board').should('exist'); cy.contains('h2', 'test_camera').should('exist'); cy.contains('h2', 'test_navigation').should('exist'); diff --git a/web/frontend/src/app.vue b/web/frontend/src/app.vue index 0cbdfff19851..3bf89012fee0 100644 --- a/web/frontend/src/app.vue +++ b/web/frontend/src/app.vue @@ -776,7 +776,6 @@ onMounted(async () => { v-for="camera in filterResources(resources, 'rdk', 'component', 'camera')" :key="camera.name" :camera-name="camera.name" - :crumbs="[camera.name]" :resources="resources" @toggle-camera="isOn => { viewCamera(camera.name, isOn) }" @refresh-camera="t => { viewCameraFrame(camera.name, t) }" @@ -803,7 +802,6 @@ onMounted(async () => { v-for="audioInput in filterResources(resources, 'rdk', 'component', 'audio_input')" :key="audioInput.name" :name="audioInput.name" - :crumbs="[audioInput.name]" /> diff --git a/web/frontend/src/components/arm.vue b/web/frontend/src/components/arm.vue index 0803a9cf55ba..209050512fb5 100644 --- a/web/frontend/src/components/arm.vue +++ b/web/frontend/src/components/arm.vue @@ -181,6 +181,7 @@ const armModifyAll = () => {
(); @@ -42,6 +41,7 @@ const toggleExpand = async () => {
diff --git a/web/frontend/src/components/base.vue b/web/frontend/src/components/base.vue index 32d1a2c409a4..b67010e63d5e 100644 --- a/web/frontend/src/components/base.vue +++ b/web/frontend/src/components/base.vue @@ -173,6 +173,7 @@ const handleSelectCamera = (event: string) => { {

diff --git a/web/frontend/src/components/camera.vue b/web/frontend/src/components/camera.vue index c043c976f35b..631e9108814c 100644 --- a/web/frontend/src/components/camera.vue +++ b/web/frontend/src/components/camera.vue @@ -11,7 +11,6 @@ import PCD from './pcd.vue'; interface Props { cameraName: string - crumbs: string[] resources: Resource[] } @@ -88,7 +87,8 @@ const exportScreenshot = (cameraName: string) => { >
diff --git a/web/frontend/src/components/gamepad.vue b/web/frontend/src/components/gamepad.vue index ad8f2955616f..142f00b4cdf8 100644 --- a/web/frontend/src/components/gamepad.vue +++ b/web/frontend/src/components/gamepad.vue @@ -190,6 +190,7 @@ watch(() => enabled, () => {
{
{
{
{