diff --git a/CMakeLists.txt b/CMakeLists.txt index b2c1e4f8..65983edc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) #============================================================================ # Initialize the project #============================================================================ -project(gz-sensors7 VERSION 7.1.0) +project(gz-sensors7 VERSION 7.2.0) #============================================================================ # Find gz-cmake diff --git a/Changelog.md b/Changelog.md index e60fcae1..dc0d1bfc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,38 @@ ### Gazebo Sensors 7.X.X +### Gazebo Sensors 7.2.0 (2023-04-13) + +1. Cleanup resources in CameraSensor destructor + * [Pull request #340](https://github.com/gazebosim/gz-sensors/pull/340) + +1. CI workflow: use checkout v3 + * [Pull request #335](https://github.com/gazebosim/gz-sensors/pull/335) + +1. Rename COPYING to LICENSE + * [Pull request #334](https://github.com/gazebosim/gz-sensors/pull/334) + +1. Fix links in Changelog + * [Pull request #330](https://github.com/gazebosim/gz-sensors/pull/330) + +1. Fix flaky triggered bounding box camera test + * [Pull request #329](https://github.com/gazebosim/gz-sensors/pull/329) + +1. Fix Camera info test + * [Pull request #326](https://github.com/gazebosim/gz-sensors/pull/326) + +1. Added trigger to BoundingBoxCamera + * [Pull request #322](https://github.com/gazebosim/gz-sensors/pull/322) + +1. clean up rendering resources + * [Pull request #324](https://github.com/gazebosim/gz-sensors/pull/324) + +1. Added Camera Info topic support for cameras + * [Pull request #285](https://github.com/gazebosim/gz-sensors/pull/285) + +1. ign -> gz Migrate Ignition Headers : gz-sensors + * [Pull request #260](https://github.com/gazebosim/gz-sensors/pull/260) + ### Gazebo Sensors 7.1.0 (2023-02-09) 1. Added airspeed sensor diff --git a/src/BoundingBoxCameraSensor.cc b/src/BoundingBoxCameraSensor.cc index 0adbfee7..777dc14a 100644 --- a/src/BoundingBoxCameraSensor.cc +++ b/src/BoundingBoxCameraSensor.cc @@ -235,7 +235,8 @@ bool BoundingBoxCameraSensor::Load(const sdf::Sensor &_sdf) else { this->dataPtr->triggerTopic = - transport::TopicUtils::AsValidTopic(this->dataPtr->triggerTopic); + transport::TopicUtils::AsValidTopic( + this->Topic() + "/trigger"); if (this->dataPtr->triggerTopic.empty()) { diff --git a/src/CameraSensor.cc b/src/CameraSensor.cc index afef5875..eeedd4f7 100644 --- a/src/CameraSensor.cc +++ b/src/CameraSensor.cc @@ -454,7 +454,8 @@ bool CameraSensor::Load(const sdf::Sensor &_sdf) else { this->dataPtr->triggerTopic = - transport::TopicUtils::AsValidTopic(this->dataPtr->triggerTopic); + transport::TopicUtils::AsValidTopic( + this->Topic() + "/trigger"); if (this->dataPtr->triggerTopic.empty()) { diff --git a/test/integration/triggered_boundingbox_camera.cc b/test/integration/triggered_boundingbox_camera.cc index 424e7e51..2cc37558 100644 --- a/test/integration/triggered_boundingbox_camera.cc +++ b/test/integration/triggered_boundingbox_camera.cc @@ -64,6 +64,8 @@ class TriggeredBoundingBoxCameraTest: public testing::Test, // Create a BoundingBox Camera sensor from a SDF and gets a boxes message public: void BoxesWithBuiltinSDF(const std::string &_renderEngine); + // Create a BoundingBox Camera sensor from a SDF with empty trigger topic + public: void EmptyTriggerTopic(const std::string &_renderEngine); }; /// \brief mutex for thread safety @@ -213,12 +215,100 @@ void TriggeredBoundingBoxCameraTest::BoxesWithBuiltinSDF( gz::rendering::unloadEngine(engine->Name()); } +void TriggeredBoundingBoxCameraTest::EmptyTriggerTopic( + const std::string &_renderEngine) +{ + std::string path = gz::common::joinPaths(PROJECT_SOURCE_PATH, "test", + "sdf", "triggered_boundingbox_camera_sensor_topic_builtin.sdf"); + sdf::SDFPtr doc(new sdf::SDF()); + sdf::init(doc); + ASSERT_TRUE(sdf::readFile(path, doc)); + ASSERT_NE(nullptr, doc->Root()); + ASSERT_TRUE(doc->Root()->HasElement("model")); + auto modelPtr = doc->Root()->GetElement("model"); + ASSERT_TRUE(modelPtr->HasElement("link")); + auto linkPtr = modelPtr->GetElement("link"); + ASSERT_TRUE(linkPtr->HasElement("sensor")); + auto sensorPtr = linkPtr->GetElement("sensor"); + + // Skip unsupported engines + if (_renderEngine != "ogre2") + { + gzdbg << "Engine '" << _renderEngine + << "' doesn't support bounding box cameras" << std::endl; + return; + } + + // Setup gz-rendering with an empty scene + auto *engine = gz::rendering::engine(_renderEngine); + if (!engine) + { + gzdbg << "Engine '" << _renderEngine + << "' is not supported" << std::endl; + return; + } + + gz::rendering::ScenePtr scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + BuildScene(scene); + + gz::sensors::Manager mgr; + + sdf::Sensor sdfSensor; + sdfSensor.Load(sensorPtr); + + std::string type = sdfSensor.TypeStr(); + EXPECT_EQ(type, "boundingbox_camera"); + + gz::sensors::BoundingBoxCameraSensor *sensor = + mgr.CreateSensor(sdfSensor); + ASSERT_NE(sensor, nullptr); + EXPECT_FALSE(sensor->HasConnections()); + sensor->SetScene(scene); + + // trigger camera through topic + std::string triggerTopic = + "/test/integration/triggered_bbcamera/trigger"; + + gz::transport::Node node; + auto pub = node.Advertise(triggerTopic); + gz::msgs::Boolean msg; + msg.set_data(true); + pub.Publish(msg); + // sleep to wait for trigger msg to be received before calling mgr.RunOnce + std::this_thread::sleep_for(2s); + + // we should receive images and boxes after trigger + { + std::string boxTopic = + "/test/integration/triggered_bbcamera"; + WaitForMessageTestHelper + helper(boxTopic); + mgr.RunOnce(std::chrono::steady_clock::duration::zero(), true); + EXPECT_TRUE(helper.WaitForMessage(10s)) << helper; + g_mutex.lock(); + EXPECT_EQ(g_boxes.size(), size_t(2)); + g_mutex.unlock(); + } + + // Clean up + mgr.Remove(sensor->Id()); + engine->DestroyScene(scene); + gz::rendering::unloadEngine(engine->Name()); +} + ////////////////////////////////////////////////// TEST_P(TriggeredBoundingBoxCameraTest, BoxesWithBuiltinSDF) { BoxesWithBuiltinSDF(GetParam()); } +////////////////////////////////////////////////// +TEST_P(TriggeredBoundingBoxCameraTest, EmptyTriggerTopic) +{ + EmptyTriggerTopic(GetParam()); +} + INSTANTIATE_TEST_SUITE_P(BoundingBoxCameraSensor, TriggeredBoundingBoxCameraTest, RENDER_ENGINE_VALUES, gz::rendering::PrintToStringParam()); diff --git a/test/integration/triggered_camera.cc b/test/integration/triggered_camera.cc index 31d86be6..8aa2eec1 100644 --- a/test/integration/triggered_camera.cc +++ b/test/integration/triggered_camera.cc @@ -63,6 +63,9 @@ class TriggeredCameraTest: public testing::Test, // Create a Camera sensor from a SDF and gets a image message public: void ImagesWithBuiltinSDF(const std::string &_renderEngine); + + // Create a Camera sensor from a SDF with empty trigger topic + public: void EmptyTriggerTopic(const std::string &_renderEngine); }; void TriggeredCameraTest::ImagesWithBuiltinSDF(const std::string &_renderEngine) @@ -128,6 +131,9 @@ void TriggeredCameraTest::ImagesWithBuiltinSDF(const std::string &_renderEngine) msg.set_data(true); pub.Publish(msg); + // sleep to wait for trigger msg to be received before calling mgr.RunOnce + std::this_thread::sleep_for(2s); + // check camera image after trigger { std::string imageTopic = @@ -154,6 +160,70 @@ void TriggeredCameraTest::ImagesWithBuiltinSDF(const std::string &_renderEngine) gz::rendering::unloadEngine(engine->Name()); } +void TriggeredCameraTest::EmptyTriggerTopic(const std::string &_renderEngine) +{ + std::string path = gz::common::joinPaths(PROJECT_SOURCE_PATH, "test", + "sdf", "triggered_camera_sensor_topic_builtin.sdf"); + sdf::SDFPtr doc(new sdf::SDF()); + sdf::init(doc); + ASSERT_TRUE(sdf::readFile(path, doc)); + ASSERT_NE(nullptr, doc->Root()); + ASSERT_TRUE(doc->Root()->HasElement("model")); + auto modelPtr = doc->Root()->GetElement("model"); + ASSERT_TRUE(modelPtr->HasElement("link")); + auto linkPtr = modelPtr->GetElement("link"); + ASSERT_TRUE(linkPtr->HasElement("sensor")); + auto sensorPtr = linkPtr->GetElement("sensor"); + + // Setup gz-rendering with an empty scene + auto *engine = gz::rendering::engine(_renderEngine); + if (!engine) + { + gzdbg << "Engine '" << _renderEngine + << "' is not supported" << std::endl; + return; + } + + gz::rendering::ScenePtr scene = engine->CreateScene("scene"); + + gz::sensors::Manager mgr; + + gz::sensors::CameraSensor *sensor = + mgr.CreateSensor(sensorPtr); + ASSERT_NE(sensor, nullptr); + EXPECT_FALSE(sensor->HasConnections()); + sensor->SetScene(scene); + + sdf::Sensor sdfSensor; + sdfSensor.Load(sensorPtr); + EXPECT_EQ(true, sdfSensor.CameraSensor()->Triggered()); + + // trigger camera through default generated topic + gz::transport::Node triggerNode; + std::string triggerTopic = + "/test/integration/triggered_camera/trigger"; + + auto pub = triggerNode.Advertise(triggerTopic); + gz::msgs::Boolean msg; + msg.set_data(true); + pub.Publish(msg); + + // check camera image after trigger + { + std::string imageTopic = + "/test/integration/triggered_camera"; + WaitForMessageTestHelper helper(imageTopic); + mgr.RunOnce(std::chrono::steady_clock::duration::zero(), true); + EXPECT_TRUE(helper.WaitForMessage(10s)) << helper; + } + + // Clean up + auto sensorId = sensor->Id(); + EXPECT_TRUE(mgr.Remove(sensorId)); + engine->DestroyScene(scene); + gz::rendering::unloadEngine(engine->Name()); +} + ////////////////////////////////////////////////// TEST_P(TriggeredCameraTest, ImagesWithBuiltinSDF) { @@ -161,5 +231,12 @@ TEST_P(TriggeredCameraTest, ImagesWithBuiltinSDF) ImagesWithBuiltinSDF(GetParam()); } +////////////////////////////////////////////////// +TEST_P(TriggeredCameraTest, EmptyTriggerTopic) +{ + gz::common::Console::SetVerbosity(4); + EmptyTriggerTopic(GetParam()); +} + INSTANTIATE_TEST_SUITE_P(CameraSensor, TriggeredCameraTest, RENDER_ENGINE_VALUES, gz::rendering::PrintToStringParam()); diff --git a/test/sdf/triggered_boundingbox_camera_sensor_topic_builtin.sdf b/test/sdf/triggered_boundingbox_camera_sensor_topic_builtin.sdf new file mode 100644 index 00000000..cf6a1448 --- /dev/null +++ b/test/sdf/triggered_boundingbox_camera_sensor_topic_builtin.sdf @@ -0,0 +1,23 @@ + + + + + + 10 + /test/integration/triggered_bbcamera + + true + 1.05 + + 320 + 240 + + + 0.1 + 10.0 + + + + + + diff --git a/test/sdf/triggered_camera_sensor_topic_builtin.sdf b/test/sdf/triggered_camera_sensor_topic_builtin.sdf new file mode 100644 index 00000000..84a9943a --- /dev/null +++ b/test/sdf/triggered_camera_sensor_topic_builtin.sdf @@ -0,0 +1,23 @@ + + + + + + 10 + /test/integration/triggered_camera + + true + 1.05 + + 256 + 257 + + + 0.1 + 10.0 + + + + + +