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

Remove plugin interface and support custom sensors #90

Merged
merged 22 commits into from Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/ci/packages.apt
Expand Up @@ -2,7 +2,6 @@ libignition-cmake2-dev
libignition-common4-dev
libignition-math6-dev
libignition-msgs8-dev
libignition-plugin-dev
libignition-rendering6-dev
libignition-tools-dev
libignition-transport11-dev
Expand Down
5 changes: 0 additions & 5 deletions CMakeLists.txt
Expand Up @@ -78,11 +78,6 @@ endif()
ign_find_package(ignition-msgs8 REQUIRED)
set(IGN_MSGS_VER ${ignition-msgs8_VERSION_MAJOR})

#--------------------------------------
# Find ignition-plugin
ign_find_package(ignition-plugin1 REQUIRED COMPONENTS all)
set(IGN_PLUGIN_VER ${ignition-plugin1_VERSION_MAJOR})

#--------------------------------------
# Find SDFormat
ign_find_package(sdformat12 REQUIRED)
Expand Down
31 changes: 31 additions & 0 deletions Migration.md
Expand Up @@ -5,6 +5,37 @@ Deprecated code produces compile-time warnings. These warning serve as
notification to users that their code should be upgraded. The next major
release will remove the deprecated code.

## Ignition Sensors 5.X to 6.X

1. Sensors aren't loaded as plugins anymore. Instead, downstream libraries must
link to the library of the sensor they're interested in, and instantiate
new sensors knowing their type. For example:

* `auto camera = std::make_unique<ignition::sensors::CameraSensor>();`
* `auto camera = sensorFactory.CreateSensor<ignition::sensors::CameraSensor>(_sdf);`
* `auto camera = manager.CreateSensor<ignition::sensors::CameraSensor>(_sdf);`

1. **include/sensors/SensorFactory.hh**
+ ***Deprecation*** SensorPlugin
+ ***Replacement*** None; see above.
+ ***Deprecation*** SensorTypePlugin
+ ***Replacement*** None; see above.
+ ***Deprecation*** std::unique_ptr<Sensor> CreateSensor(sdf::ElementPtr);
+ ***Replacement*** template<typename SensorType> std::unique_ptr<SensorType> CreateSensor(sdf::ElementPtr);
+ ***Deprecation*** std::unique_ptr<Sensor> CreateSensor(const sdf::Sensor &);
+ ***Replacement*** template<typename SensorType> std::unique_ptr<SensorType> CreateSensor(const sdf::Sensor &);
+ ***Deprecation*** void AddPluginPaths(const std::string &)
+ ***Replacement*** None; see above.
+ ***Deprecation*** IGN_SENSORS_REGISTER_SENSOR
+ ***Replacement*** None; see above.

1. **include/sensors/Manager.hh**
+ ***Deprecation*** SensorId CreateSensor(sdf::ElementPtr);
+ ***Replacement*** template<typename SensorType, typename SdfType> SensorType> \*CreateSensor(SdfType);
+ ***Deprecation*** SensorId CreateSensor(const sdf::Sensor &);
+ ***Replacement*** template<typename SensorType, typename SdfType> SensorType \*CreateSensor(SdfType);
+ ***Deprecation*** void AddPluginPaths(const std::string &)
+ ***Replacement*** None; see above.

## Ignition Sensors 3.X to 4.X

Expand Down
1 change: 0 additions & 1 deletion bitbucket-pipelines.yml
Expand Up @@ -24,7 +24,6 @@ pipelines:
libignition-math6-dev
libignition-msgs5-dev
libignition-tools-dev
libignition-plugin-dev
chapulina marked this conversation as resolved.
Show resolved Hide resolved
libignition-transport8-dev
libsdformat9-dev
# libignition-rendering3-dev
Expand Down
10 changes: 10 additions & 0 deletions examples/custom_sensor/CMakeLists.txt
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)

project(odometer)

find_package(ignition-cmake2 REQUIRED)
find_package(ignition-sensors6 REQUIRED)

add_library(${PROJECT_NAME} SHARED Odometer.cc)
target_link_libraries(${PROJECT_NAME}
PUBLIC ignition-sensors6::ignition-sensors6)
109 changes: 109 additions & 0 deletions examples/custom_sensor/Odometer.cc
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include <math.h>

#include <ignition/msgs/double.pb.h>

#include <ignition/common/Console.hh>
#include <ignition/sensors/Noise.hh>
#include <ignition/sensors/Util.hh>

#include "Odometer.hh"

using namespace custom;

//////////////////////////////////////////////////
bool Odometer::Load(const sdf::Sensor &_sdf)
{
auto type = ignition::sensors::customType(_sdf);
if ("odometer" != type)
{
ignerr << "Trying to load [odometer] sensor, but got type ["
<< type << "] instead." << std::endl;
return false;
}

// Load common sensor params
ignition::sensors::Sensor::Load(_sdf);

// Advertise topic where data will be published
this->pub = this->node.Advertise<ignition::msgs::Double>(this->Topic());

if (!_sdf.Element()->HasElement("ignition:odometer"))
{
igndbg << "No custom configuration for [" << this->Topic() << "]"
<< std::endl;
return true;
}

// Load custom sensor params
auto customElem = _sdf.Element()->GetElement("ignition:odometer");

if (!customElem->HasElement("noise"))
{
igndbg << "No noise for [" << this->Topic() << "]" << std::endl;
return true;
}

sdf::Noise noiseSdf;
noiseSdf.Load(customElem->GetElement("noise"));
this->noise = ignition::sensors::NoiseFactory::NewNoiseModel(noiseSdf);
if (nullptr == this->noise)
{
ignerr << "Failed to load noise." << std::endl;
return false;
}

return true;
}

//////////////////////////////////////////////////
bool Odometer::Update(const std::chrono::steady_clock::duration &_now)
{
ignition::msgs::Double msg;
*msg.mutable_header()->mutable_stamp() = ignition::msgs::Convert(_now);
auto frame = msg.mutable_header()->add_data();
frame->set_key("frame_id");
frame->add_value(this->Name());

this->totalDistance = this->noise->Apply(this->totalDistance);

msg.set_data(this->totalDistance);

this->AddSequence(msg.mutable_header());
this->pub.Publish(msg);

return true;
}

//////////////////////////////////////////////////
void Odometer::NewPosition(const ignition::math::Vector3d &_pos)
{
if (!isnan(this->prevPos.X()))
{
this->totalDistance += this->prevPos.Distance(_pos);
}
this->prevPos = _pos;
}

//////////////////////////////////////////////////
const ignition::math::Vector3d &Odometer::Position() const
{
return this->prevPos;
}

68 changes: 68 additions & 0 deletions examples/custom_sensor/Odometer.hh
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2021 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef ODOMETER_HH_
#define ODOMETER_HH_

#include <ignition/sensors/Sensor.hh>
#include <ignition/sensors/SensorTypes.hh>
#include <ignition/transport/Node.hh>

namespace custom
{
/// \brief Example sensor that publishes the total distance travelled by a
/// robot, with noise.
class Odometer : public ignition::sensors::Sensor
{
/// \brief Load the sensor with SDF parameters.
/// \param[in] _sdf SDF Sensor parameters.
/// \return True if loading was successful
public: virtual bool Load(const sdf::Sensor &_sdf) override;

/// \brief Update the sensor and generate data
/// \param[in] _now The current time
/// \return True if the update was successfull
public: virtual bool Update(
const std::chrono::steady_clock::duration &_now) override;

/// \brief Set the current postiion of the robot, so the odometer can
/// calculate the distance travelled.
/// \param[in] _pos Current position in world coordinates.
public: void NewPosition(const ignition::math::Vector3d &_pos);

/// \brief Get the latest world postiion of the robot.
/// \return The latest position given to the odometer.
public: const ignition::math::Vector3d &Position() const;

/// \brief Previous position of the robot.
private: ignition::math::Vector3d prevPos{std::nan(""), std::nan(""),
std::nan("")};

/// \brief Latest total distance.
private: double totalDistance{0.0};

/// \brief Noise that will be applied to the sensor data
private: ignition::sensors::NoisePtr noise{nullptr};

/// \brief Node for communication
private: ignition::transport::Node node;

/// \brief Publishes sensor data
private: ignition::transport::Node::Publisher pub;
};
}

#endif
38 changes: 38 additions & 0 deletions examples/custom_sensor/README.md
@@ -0,0 +1,38 @@
# Custom sensor

This example creates a simple custom sensor called `Odometer`, which
publishes the total distance travelled by a robot.

## Build

Compile the sensor as follows:

```
cd examples/custom_sensor
mkdir build
cd build
cmake ..
make
```

This will generate a shared library with the sensor called `libodometer`.

## Use

This sensor can be used with Ignition Gazebo, or with any downstream
application that uses the Ignition Sensors API. Listed here are two ways of
testing this sensor, one with Gazebo and one with a custom program.

### With a custom program

The [loop_sensor](../loop_sensor) example can be used to load an SDF file with
configuration for this sensor and run it in a loop. See that example's
instructions.

### With Ignition Gazebo

The
[custom_sensor_system](https://github.com/ignitionrobotics/ign-gazebo/tree/main/examples/plugin/custom_sensor_system)
example can be used to load this sensor into Gazebo and update it during the
simulation.

21 changes: 21 additions & 0 deletions examples/loop_sensor/CMakeLists.txt
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(loop_sensor)

find_package(ignition-sensors6 REQUIRED
# Find built-in sensors
COMPONENTS
altimeter
)

# A simple example of how to find custom sensors
add_subdirectory(../custom_sensor odometer)

add_executable(${PROJECT_NAME} main.cc)
target_link_libraries(${PROJECT_NAME} PUBLIC
ignition-sensors6::ignition-sensors6

# Link to custom sensors
odometer

# Link to built-in sensors
ignition-sensors6::altimeter)