RoFI Configuration

Configuration is a way of representing any collection of RoFI Modules in an universal manner. It contains all building blocks of the RoFI platform such as various modules and joints.

Using these blocks, you can specify every RoFI world – a set of rofibots (connected set of RoFI modules fixed in space) – and work with it. Configuration computes positions of every component and provides useful functions for manipulation with the whole world, including some validity checks (e.g. collision checks).

Usage

The main class is RofiWorld for which you create an instance and add all the modules you want to have in the world. You have to connect these modules together appropriately to form individual rofibots. If you want to use absolute positions, you have to fix one of the components of each rofibot in space, otherwise, the configuration cannot figure out its coordinates.

Example

Let us create a world with a single bot consisted of two universal modules.

#include <configuration/rofiworld.hpp>

// ...

RofiWorld world;
// add universal module with id 42 in the default state
auto& m1 = world.insert( UniversalModule( 42, 0_deg, 0_deg, 0_deg ) );
// add universal module with id 42 with beta set to 45 degrees and gamma to 90 degrees
auto& m2 = world.insert( UniversalModule( 66, 0_deg, 45_deg, 90_deg ) );

// connect A+X of the universal module with id = 42 to A-X of UM with id = 66
connect( m1.connectors()[ 2 ], m2.connectors()[ 0 ], Orientation::North );
// fix the position of the `shoe A` in { 0, 0, 0 }
connect< RigidJoint >( m1.bodies()[ 0 ], { 0, 0, 0 }, identity );

With the world in hand, you can then prepare it (i.e. compute positions of each part – rofibot – of the world) and check for its validity.

if ( auto prepared = world.prepare(); !prepared )
    std::cerr << "Could not prepare configuration: " << prepared.assume_error() << "\n";
if ( auto valid = world.isValid( SimpleCollision() ); !valid )
    std::cerr << "Invalid configuration: " << valid.assume_error() << "\n";

// or you can shorten the above to
auto ok = world.validate( SimpleCollision() );

// also, the SimpleCollision model is the default one, so you can ommit it too and get
auto ok = world.validate();

Types and Constants

using rofi::configuration::ModuleId = int

ModuleId.

enum class rofi::configuration::ComponentType

Values:

enumerator Roficom
enumerator UmBody
enumerator UmShoe
enumerator CubeBody
enum class rofi::configuration::ModuleType

Values:

enumerator Unknown
enumerator Universal
enumerator Pad
enumerator Cube
enum class rofi::configuration::roficom::Orientation

Values:

enumerator North
enumerator East
enumerator South
enumerator West

Classes

class RofiWorld

RoFI world.

The RofiWorld is composed out of modules.

Public Types

using ModuleInfoHandle = atoms::HandleSet<ModuleInfo>::handle_type
using RoficomJointHandle = atoms::HandleSet<RoficomJoint>::handle_type
using SpaceJointHandle = atoms::HandleSet<SpaceJoint>::handle_type

Public Functions

RofiWorld() = default
inline RofiWorld(const RofiWorld &other)
inline RofiWorld(RofiWorld &&other)
inline RofiWorld &operator=(RofiWorld other)
inline void swap(RofiWorld &other)
inline Module &insert(const Module &m)

Insert a module from the RofiWorld

The module position is not specified. You should connect the module to other modules via connect(). The module is assigned a unique id within the world.

Throws

std::logic_error – if module with the same ID is already present

Returns

reference to the newly created module.

template<std::derived_from<Module> ModuleT>
inline ModuleT &insert(const ModuleT &m)

Insert a module from the RofiWorld

The module position is not specified. You should connect the module to other modules via connect(). The module is assigned a unique id within the world.

Returns

reference to the newly created module.

inline Module *getModule(ModuleId id) const

Get pointer to module with given id within the RofiWorld.

inline Module *getModule(ModuleInfoHandle h) const

Get pointer to module with given id within the RofiWorld.

inline auto modules() const -> std::ranges::range auto

Get a range of modules.

inline auto modules() -> std::ranges::range auto

Get a range of modules.

inline auto modulesWithAbsPos() const -> std::ranges::range auto

Get a range of modules with their absolute positions.

this has to be prepared.

inline const auto &roficomConnections() const

Get a container of RoficomJoint.

inline const auto &referencePoints() const
inline void remove(ModuleId id)

Remove a module from the RofiWorld.

inline bool isPrepared() const

Return true if the configuration is prepared.

Configuration can be prepared with prepare.

inline atoms::Result<std::monostate> isValid(const Collision &collisionModel = SimpleCollision()) const

Decide whether the configuration is valid given the collision model.

Returns

result - the error gives textual description of the reason for invalidity

inline atoms::Result<std::monostate> validate(const Collision &collisionModel = SimpleCollision())

Prepare configuration if needed and decide whether it is valid with given collision model.

Returns

result - the error gives textual description of the reason for invalidity

atoms::Result<std::monostate> prepare()

Precompute position of all the modules in the configuration.

Returns

result error if the configuration is inconsistent

void setSpaceJointPositions(SpaceJointHandle jointId, std::span<const float> p)

Set position of a space joints specified by its id.

inline Matrix getModulePosition(ModuleId id)

Get position of a module specified by its id.

Throws

std::logic_error – if configuration is inconsistent or module with given ID doesn’t exist

inline Matrix getModulePosition(ModuleId id) const
void disconnect(RoficomJointHandle h)
void disconnect(SpaceJointHandle h)
class Module

RoFI module.

The module is composed out of components.

Subclassed by rofi::configuration::Cube, rofi::configuration::Pad, rofi::configuration::UniversalModule, rofi::configuration::UnknownModule

Public Functions

inline Module(ModuleType type, std::vector<Component> components, int connectorCount, std::vector<ComponentJoint> joints, ModuleId id, std::optional<int> rootComponent = std::nullopt)

Construct module.

Note that components contain all module components out of which first connectorCount are module connectors.

The user can optionally specify a root component (e.g, in case of cyclic joints). If no root component is specified, component with no ingoing joints is selected.

ATOMS_CLONEABLE_BASE(Module)
virtual ~Module() = default
inline ModuleId getId() const
bool setId(ModuleId newId)

Set ID of the module to the new value.

Checks if the new value is not used within its world, in which case the ID is changed to the new value. Otherwise the ID is left the same.

Returns

whether the value was changed

void setJointPositions(int idx, std::span<const float> p)
atoms::Result<std::monostate> changeJointPositionsBy(int idx, std::span<float> diff)

Changes parameters of joint positions by values in <diff>.

Assumes <idx> is at most index of last joint in joint container. Assumes <diff> contains as many values as joint has parameters. If values from <diff> added to values of current parameters are not bounded by pairs of values in joint limits, function does not change the positions and does not clear component positions (configuration is still prepared).

Parameters
  • idxJoint index

  • diff – Span of values to be added to current parameters (can be negative).

Returns

result_error if any of the resulting parameters does not respect corresponding joint limit.

inline Matrix getComponentRelativePosition(int idx)

Get a component position relative to module origin.

Throws

std::logic_error – if the components are inconsistent

inline Matrix getComponentRelativePosition(int idx) const

Get a component position relative to module origin.

Throws

std::logic_error – if the components are not prepared

void clearComponentPositions()
inline std::vector<Matrix> getOccupiedRelativePositions() const

Get a vector of occupied positions relative to module origin.

Throws

std::logic_error – if the components are not prepared

inline atoms::Result<std::monostate> prepare()

Precompute component relative positions.

Returns

result error if the components are inconsistent

inline auto configurableJoints()
inline auto configurableJoints() const
inline std::span<const Component> components() const

Get read-only view of the components.

inline std::span<Component> components()
inline std::span<const Component> bodies() const

Get read-only view of the bodies.

inline std::span<Component> bodies()
inline std::span<const ComponentJoint> joints() const
inline std::span<const Component> connectors() const

Get read-only view of the connectors.

inline std::span<Component> connectors()
inline int componentIdx(const Component &c) const

Get index of a component.

Throws

std::logic_error – if the component doesn’t belong to the module

Returns

index of the first equal component

Public Members

ModuleType type

module type

RofiWorld *parent

pointer to parenting RofiWorld

struct Component

Single body of a module.

Public Types

using JointId = int

Public Functions

inline Component(ComponentType type, std::vector<JointId> inJoints, std::vector<JointId> outJoints, Module *parent = nullptr)
inline explicit Component(ComponentType type)
bool operator==(const Component &o) const = default
int getIndexInParent() const

Get the index of component in parent.

Matrix getPosition() const

Get the absolute component position.

Throws

std::logic_error – if the world is not prepared

std::optional<std::pair<const Component&, roficom::Orientation>> getNearConnector() const

Find a connector of another module in the same RofiWorld.

that can be connected to

Throws

std::logic_error – if the world is not prepared

Returns

the connector and orientation

Returns

nullopt if no such connector exists

Public Members

ComponentType type
std::vector<JointId> inJoints
std::vector<JointId> outJoints
Module *parent = nullptr
struct Joint : public atoms::VisitableBase<Joint, JointVisitor>

Joint between two coordinate systems.

Joints represents a parametric description of positional relationship between two coordinate systems (e.g., component origins). This class in abstract. See below for concrete instances.

Each joint has Joint::paramCount() parameters (real value), which are stored in Joint::position. These params are, e.g., angle for rotation joint.

Subclassed by rofi::configuration::RoficomJoint

Public Functions

inline explicit Joint(std::vector<std::pair<float, float>> jointLimits)
virtual ~Joint() = default
ATOMS_CLONEABLE_BASE(Joint)
inline std::span<const std::pair<float, float>> jointLimits() const
inline std::span<const float> positions() const
inline virtual void setPositions(std::span<const float> pos)

Sets joint settings to corresponding values given by <pos>.

Assumes there are exactly as many values as there are joint settings.

Throws

std::logic_error – if the given settings do not respect joint limits.

inline virtual atoms::Result<std::monostate> changePositionsBy(std::span<const float> diff)

Changes each joint setting by the corresponding value in <diff>.

Assumes there are exactly as many values given as there are joint settings.

Returns

result error if the resulting values do not respect joint limits.

virtual Matrix sourceToDest() const = 0
inline virtual Matrix destToSource() const

Friends

friend std::ostream &operator<<(std::ostream &out, Joint &j)

Provides human readable text description of the joint.

struct RigidJoint : public atoms::Visitable<Joint, RigidJoint>

Public Functions

inline RigidJoint(const Matrix &sToDest)

Construct a rigid joint based on transformation between source and dest.

Example usage: RigidJoint( rotate( M_PI/2, { 1, 0, 0, 1 } ) * translate( { 20, 0, 0 } ) )

inline Matrix sourceToDest() const override
inline Matrix destToSource() const override
ATOMS_CLONEABLE(RigidJoint)
struct RotationJoint : public atoms::Visitable<Joint, RotationJoint>

Public Functions

inline RotationJoint(Vector sourceOrigin, Vector sourceAxis, Vector destOrigin, Vector desAxis, Angle min, Angle max)

Construct rotation joint by specifing the same axis and origin point in source coordinate system and destination coordinate system.

inline RotationJoint(Matrix pre, Vector axis, Matrix post, Angle min, Angle max)

Construct rotation joint by specifying transformation before rotation, followed by rotation axis with origin in (0, 0, 0), followed by another transformation.

inline Matrix sourceToDest() const override
inline Matrix destToSource() const override
inline Angle position() const
inline void setPosition(Angle pos)
inline std::pair<Angle, Angle> jointLimit() const
inline const Matrix pre() const
inline const Matrix post() const
inline const Vector axis() const
ATOMS_CLONEABLE(RotationJoint)

Friends

friend std::ostream &operator<<(std::ostream &out, Joint &j)

Provides human readable text description of the joint.

struct RoficomJoint : public rofi::configuration::Joint

Joint between two modules.

The joint is created between two components of two modules specified by module ids and corresponding component index.

Public Functions

inline RoficomJoint(roficom::Orientation o, RofiWorld::ModuleInfoHandle sourceModule, RofiWorld::ModuleInfoHandle destModule, int sourceConnector, int destConnector)
inline virtual Matrix sourceToDest() const override
ATOMS_CLONEABLE(RoficomJoint)
inline Module &getSourceModule(RofiWorld &world) const
inline const Module &getSourceModule(const RofiWorld &world) const
inline Module &getDestModule(RofiWorld &world) const
inline const Module &getDestModule(const RofiWorld &world) const

Public Members

roficom::Orientation orientation
RofiWorld::ModuleInfoHandle sourceModule
RofiWorld::ModuleInfoHandle destModule
int sourceConnector
int destConnector
struct ComponentJoint

Joint between two components of the same module.

Public Functions

inline ComponentJoint(atoms::ValuePtr<Joint> joint, int source, int dest)
ComponentJoint(ComponentJoint&&) = default
ComponentJoint &operator=(ComponentJoint&&) = default
inline ComponentJoint(const ComponentJoint &o)
inline ComponentJoint &operator=(const ComponentJoint &o)

Public Members

atoms::ValuePtr<Joint> joint
int sourceComponent
int destinationComponent
struct SpaceJoint

Joint between a fixed point in space and a module.

Public Functions

inline SpaceJoint(atoms::ValuePtr<Joint> joint, Vector refPoint, RofiWorld::ModuleInfoHandle destModule, int destComponent)
SpaceJoint(SpaceJoint&&) = default
SpaceJoint &operator=(SpaceJoint&&) = default
inline SpaceJoint(const SpaceJoint &o)
inline SpaceJoint &operator=(const SpaceJoint &o)

Public Members

atoms::ValuePtr<Joint> joint
Vector refPoint
RofiWorld::ModuleInfoHandle destModule
int destComponent
class NoCollision : public rofi::configuration::Collision

Completely ignores any collisions.

Public Functions

inline virtual bool operator()(const Module&, const Module&, Matrix, Matrix) const

Decide if two modules collide.

class SimpleCollision : public rofi::configuration::Collision

Each module component takes up a unit sphere of space.

Public Functions

inline virtual bool operator()(const Module &a, const Module &b, Matrix posA, Matrix posB) const

Decide if two modules collide.

Module Classes

class UniversalModule : public rofi::configuration::Module

Public Functions

ATOMS_CLONEABLE(UniversalModule)
inline explicit UniversalModule(int id)
inline UniversalModule(int id, Angle a, Angle b, Angle g)
inline Angle getAlpha() const
inline Angle getBeta() const
inline Angle getGamma() const
inline void setAlpha(Angle a)
inline void setBeta(Angle a)
inline void setGamma(Angle a)
inline Component getBodyA()
inline const Component getBodyA() const
inline Component getBodyB()
inline const Component getBodyB() const
inline const auto &getConnector(std::string_view cStr) const

Public Static Functions

static int translateComponent(std::string_view cStr)
static std::string_view translateComponent(int c)
class Pad : public rofi::configuration::Module

Public Functions

inline Pad(ModuleId id, int width, int height)
inline explicit Pad(ModuleId id, int size)
ATOMS_CLONEABLE(Pad)

Public Members

const int width = 0
const int height = 0
class UnknownModule : public rofi::configuration::Module

Public Functions

inline UnknownModule(std::vector<Component> components, int connectorCount, std::vector<ComponentJoint> joints, ModuleId id, std::optional<int> rootComponent = std::nullopt)
ATOMS_CLONEABLE(UnknownModule)

Functions

RofiWorld::RoficomJointHandle rofi::configuration::connect(const Component &c1, const Component &c2, roficom::Orientation o)

Connect two modules via connector.

Throws

std::logic_error – if components don’t belong to the same configuration

Returns

handle to the connection joint

template<typename JointT, typename ...Args>
RofiWorld::SpaceJointHandle rofi::configuration::connect(const Component &c, Vector refpoint, Args&&... args)

Connect a module’s component to a point in space via given joint type.

Template Parameters

JointT – connection joint type

Parameters
  • c – component to connect

  • refpoint – reference point in space

  • args – arguments to forward to JointT creation

Returns

handle to the connection joint

template<typename JointT, typename ...Args>
ComponentJoint rofi::configuration::makeComponentJoint(int source, int dest, Args&&... args)