Skip to content

Commit

Permalink
Motion and sensor models are not mixins (#291)
Browse files Browse the repository at this point in the history
Big patch to make motion and sensor models independent classes. It also
removes utilities that are no longer needed.

Related to #279.

💥 **Breaking change!** This removes some of the runtime support
utilities we added for mixins. Please note that statically defined
mixins are still fully supported (and will be until the migration is
complete) and runtime dispatch through virtual interfaces is still there
as well.

Signed-off-by: Nahuel Espinosa <[email protected]>
  • Loading branch information
nahueespinosa authored Jan 17, 2024
1 parent 80e2fe1 commit d3bd038
Show file tree
Hide file tree
Showing 25 changed files with 323 additions and 1,078 deletions.
81 changes: 62 additions & 19 deletions beluga/include/beluga/localization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ namespace beluga {
* - \ref localization.hpp
*/

/// Composes multiple interfaces into a single interface type.
/**
* \tparam Interfaces Interfaces to combine.
*/
template <class... Interfaces>
struct compose_interfaces : public Interfaces... {
/// Virtual destructor.
/**
* Makes it so at least one of the interfaces provides a virtual destructor.
*/
~compose_interfaces() override = default;
};

/// A null mixin interface. Meant to be the default value for an optional customization point.
class NullMixinInterface {
public:
Expand All @@ -70,30 +83,60 @@ class NullMixin : public Mixin {
* \tparam CustomExtensionMixinInterface An optional mixin interface for the user to customize the filter.
*/
template <class Map, class CustomExtensionMixinInterface = NullMixinInterface>
using LaserLocalizationInterface2d = beluga::mixin::compose_interfaces<
using LaserLocalizationInterface2d = beluga::compose_interfaces<
BaseParticleFilterInterface,
StorageInterface<Sophus::SE2d, beluga::Weight>,
EstimationInterface2d,
OdometryMotionModelInterface2d,
LaserSensorModelInterface2d<Map>,
CustomExtensionMixinInterface>;

/// \cond

/// Wrapper to convert a motion model class into a mixin.
template <typename Mixin, typename Model>
struct MotionMixin : public Mixin, public Model {
using update_type = typename Model::update_type;

template <typename... Args>
constexpr explicit MotionMixin(Model model, Args&&... args)
: Model(std::move(model)), Mixin(static_cast<decltype(args)>(args)...) {}

void update_motion(const update_type& pose) { Model::update_motion(pose); }
};

/// Wrapper to convert a sensor model class into a mixin.
template <typename Mixin, typename Model>
struct SensorMixin : public Mixin, public Model {
using measurement_type = typename Model::measurement_type;
using map_type = typename Model::map_type;

template <typename... Args>
constexpr explicit SensorMixin(Model model, Args&&... args)
: Model(std::move(model)), Mixin(static_cast<decltype(args)>(args)...) {}

void update_sensor(measurement_type&& measurement) { Model::update_sensor(std::move(measurement)); }
void update_map(map_type&& map) { Model::update_map(std::move(map)); }
};

/// \endcond

/// An implementation of Monte Carlo Localization.
/**
* An instance of this class template implements beluga::LaserLocalizationInterface2d
* and \ref LocalizationPage.
*
* \tparam MotionDescriptor A descriptor of a mixin that implements \ref MotionModelPage.
* \tparam SensorDescriptor A descriptor of a mixin that implements \ref SensorModelPage.
* \tparam MotionModel A class that implements \ref MotionModelPage.
* \tparam SensorModel A class that implements \ref SensorModelPage.
* \tparam Map Environment representation type consistent with the sensor descriptor.
* \tparam CustomExtensionMixinInterface An optional mixin interface for the user to customize the filter.
* \tparam Interface An optional mixin interface for the user to customize the filter.
* \tparam CustomExtensionMixin An optional mixin type for the user to customize the filter.
*/
template <
class MotionDescriptor,
class SensorDescriptor,
class MotionModel,
class SensorModel,
class Map,
class CustomExtensionMixinInterface = NullMixinInterface,
class Interface = NullMixinInterface,
template <class> class CustomExtensionMixin = NullMixin>
using MonteCarloLocalization2d = ciabatta::mixin<
BootstrapParticleFilter,
Expand All @@ -102,27 +145,27 @@ using MonteCarloLocalization2d = ciabatta::mixin<
RandomStateGenerator,
NaiveSampler,
FixedLimiter,
MotionDescriptor::template mixin,
SensorDescriptor::template mixin,
ciabatta::curry<MotionMixin, MotionModel>::template mixin,
ciabatta::curry<SensorMixin, SensorModel>::template mixin,
CustomExtensionMixin,
ciabatta::provides<LaserLocalizationInterface2d<Map, CustomExtensionMixinInterface>>::template mixin>;
ciabatta::provides<Interface>::template mixin>;

/// An implementation of Adaptive Monte Carlo Localization.
/**
* An instance of this class template implements beluga::LaserLocalizationInterface2d
* and \ref LocalizationPage.
*
* \tparam MotionDescriptor A descriptor of a mixin that implements \ref MotionModelPage.
* \tparam SensorDescriptor A descriptor of a mixin that implements \ref SensorModelPage.
* \tparam MotionModel A class that implements \ref MotionModelPage.
* \tparam SensorModel A class that implements \ref SensorModelPage.
* \tparam Map Environment representation type consistent with the sensor descriptor.
* \tparam CustomExtensionMixinInterface An optional mixin interface for the user to customize the filter.
* \tparam Interface An optional mixin interface for the user to customize the filter.
* \tparam CustomExtensionMixin An optional mixin type for the user to customize the filter.
*/
template <
class MotionDescriptor,
class SensorDescriptor,
class MotionModel,
class SensorModel,
class Map,
class CustomExtensionMixinInterface = NullMixinInterface,
class Interface = NullMixinInterface,
template <class> class CustomExtensionMixin = NullMixin>
using AdaptiveMonteCarloLocalization2d = ciabatta::mixin<
BootstrapParticleFilter,
Expand All @@ -131,10 +174,10 @@ using AdaptiveMonteCarloLocalization2d = ciabatta::mixin<
RandomStateGenerator,
AdaptiveSampler,
ciabatta::curry<KldLimiter, Sophus::SE2d>::mixin,
MotionDescriptor::template mixin,
SensorDescriptor::template mixin,
ciabatta::curry<MotionMixin, MotionModel>::template mixin,
ciabatta::curry<SensorMixin, SensorModel>::template mixin,
CustomExtensionMixin,
ciabatta::provides<LaserLocalizationInterface2d<Map, CustomExtensionMixinInterface>>::template mixin>;
ciabatta::provides<Interface>::template mixin>;

} // namespace beluga

Expand Down
76 changes: 0 additions & 76 deletions beluga/include/beluga/mixin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,90 +15,14 @@
#ifndef BELUGA_MIXIN_HPP
#define BELUGA_MIXIN_HPP

#include <memory>

#include <beluga/mixin/descriptor.hpp>
#include <beluga/mixin/particle_filter.hpp>
#include <beluga/mixin/sampling.hpp>
#include <beluga/mixin/storage.hpp>
#include <beluga/mixin/utility.hpp>
#include <ciabatta/ciabatta.hpp>

/**
* \file
* \brief Implementation of mixin utilities and extensions.
*/

namespace beluga::mixin {

/// Composes multiple interfaces into a single interface type.
/**
* \tparam Interfaces Interfaces to combine.
*/
template <class... Interfaces>
struct compose_interfaces : public Interfaces... {
/// Virtual destructor.
/**
* Makes it so at least one of the interfaces provides a virtual destructor.
*/
~compose_interfaces() override = default;
};

/// Helper method to get descriptor parameters or forward the value.
/**
* \tparam T The type of the input value.
* \param value A value to get the params from, or to forward.
* \return The params with the same value category of the input value or
* the input value forwarded.
*/
template <class T>
constexpr auto&& params_or_forward(T&& value) noexcept {
if constexpr (is_descriptor_v<T> && has_params_v<T>) {
return forward_like<T>(value.params);
} else {
return std::forward<T>(value);
}
}

/// Constructs a mixin and wraps it into a `std::unique_ptr` to a given interface.
/**
* This method can be used to create different mixin alternatives based on
* the input arguments. The input arguments can be parameters of the mixin constructor
* or descriptor variants holding parameters of the mixin constructor.
*
* This function will use the descriptor information to instantiate the correct
* mixin type and construct it with the given parameters.
*
* Descriptors can also contain no parameters, in which case the type information
* will be used to deduce the mixin type and there is no need to forward parameter
* values to the constructor.
*
* All the possible mixin alternatives from the input variants must implement `Interface`,
* and the `Interface` type must be specified since this function must return the
* same type for all possible combinations of variants.
*
* Examples:
* \snippet test/beluga/test_mixin.cpp Using make_mixin
*
* \tparam Interface The interface type used to create the std::unique_ptr.
* \tparam Base A base mixin template taking descriptors.
* \tparam Args The input argument or descriptor types from which to instantiate the mixin.
* \param args The input arguments or descriptor instances from which to construct the mixin.
* \return A `std::unique_ptr` of an instance of type `Interface`.
*/
template <class Interface, template <class...> class Base, class... Args>
auto make_mixin(Args&&... args) {
return visit_everything(
[](auto&&... args) {
using InnerArgs = list<decltype(args)...>; // avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86859
using Concrete = mixin_from_descriptors_t<Base, filter<is_descriptor, InnerArgs>>;
return std::apply(
[](auto&&... args) -> std::unique_ptr<Interface> { return std::make_unique<Concrete>(args...); },
make_tuple_with<is_not_descriptor>(params_or_forward(args)...));
},
args...);
}

} // namespace beluga::mixin

#endif
157 changes: 0 additions & 157 deletions beluga/include/beluga/mixin/descriptor.hpp

This file was deleted.

Loading

0 comments on commit d3bd038

Please sign in to comment.