Configuration
Configuration is a way of representing any bot 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 rofibot and work with it. Configuration computes positions of every component within the bot and provides useful functions for manipulation with such rofibot, including some validity checks (e.g., collision checks).
Using the configuration is pretty straightforward. The main class is
Rofibot
for which you create an
instance and add all the modules you have within one bot. You have to connect
them appropriately and if you want to use absolute positions, you have to
fix one of the bot’s components in space (otherwise, the configuration cannot
figure out its coordinates because everything is kept relative).
For example, let us create a small bot with two universal modules.
#include <configuration/rofibot.hpp>
// ...
Rofibot bot;
// add universal module with id 42 in the default state
auto& m1 = bot.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 = bot.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 bot in hand, you can then prepare it (i.e., compute its positions) and check for validity.
bot.prepare();
auto [ ok, err ] = bot.isValid( SimpleCollision() );
if ( !ok )
std::cerr << "invalid configuration: " << err << "\n";
// or you can shorten the above to
auto [ ok, err ] = bot.validate( SimpleCollision() );
// also, the SimpleCollision model is the default one, so you can ommit it too and get
auto [ ok, err ] = bot.validate();
Types and Constants
-
using rofi::configuration::ModuleId = int
ModuleId.
-
enum class rofi::configuration::ComponentType
Values:
-
enumerator UmShoe
-
enumerator UmBody
-
enumerator Roficom
-
enumerator UmShoe
Classes
-
class rofi::configuration::Rofibot
RoFI bot.
The rofibot is composed out of modules.
Public Types
-
using RoficomJointHandle = atoms::HandleSet<RoficomJoint>::handle_type
-
using SpaceJointHandle = atoms::HandleSet<SpaceJoint>::handle_type
Public Functions
-
Rofibot() = default
-
inline Module &insert(const Module &m)
Insert a module from the Rofibot.
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 rofibot.
Returns a reference to the newly created module.
-
template<std::derived_from<Module> ModuleT>
inline ModuleT &insert(const ModuleT &m) Insert a module from the Rofibot.
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 rofibot.
Returns a reference to the newly created module.
-
inline Module *getModule(ModuleId id) const
Get pointer to module with given id within the Rofibot.
-
inline Module *getModule(ModuleInfoHandle h) const
Get pointer to module with given id within the Rofibot.
-
inline const auto &modules() const
Get a container of ModuleInfo.
-
inline const auto &roficomConnections() const
Get a container of RoficomJoint.
-
inline const auto &referencePoints() const
-
inline bool isPrepared() const
Return true if the configuration is prepared.
Configuration can be prepared with
prepare
.
-
template<typename Collision = SimpleCollision>
inline std::pair<bool, std::string> isValid(Collision collisionModel = Collision()) const Decide whether the configuration is valid given the collision model.
- Returns
A pair - first item indicates the validity, the second one gives textual description of the reason for invalidity
-
template<typename Collision = SimpleCollision>
inline std::pair<bool, std::string> validate(Collision collisionModel = Collision()) Prepare configuration if needed and decide whether it is valid with given collision model.
- Returns
A pair - first item indicates the validity, the second one gives textual description of the reason for invalidity
-
void prepare()
Precompute position of all the modules in the configuration.
Raises std::runtime_error if the configuration is inconsistent, and, therefore, it cannot be
-
void setSpaceJointPositions(SpaceJointHandle jointId, std::span<const float> p)
Set position of a space joints specified by its id.
-
void disconnect(RoficomJointHandle h)
-
void disconnect(SpaceJointHandle h)
-
using RoficomJointHandle = atoms::HandleSet<RoficomJoint>::handle_type
-
class rofi::configuration::Module
RoFI module.
The module is composed out of components.
Subclassed by 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.
-
virtual ~Module() = default
-
bool setId(ModuleId newId)
Set ID of the module to the new value.
Checks if the new value is not used within its parental rofibot, if it’s in use, the ID is left the same and the method returns False. Otherwise the ID is changed. Returns True on success.
-
void setJointPositions(int idx, std::span<const float> p)
-
inline Matrix getComponentRelativePosition(int idx)
Get a component position relative to module origin.
Raises std::logic_error if the components are inconsistent
-
inline Matrix getComponentRelativePosition(int idx) const
Get a component position relative to module origin.
Raises 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.
Raises std::logic_error if the components are not prepared
-
inline void prepare()
Precompute component relative positions.
Raises std::logic_error if the components are inconsistent
-
inline auto configurableJoints()
-
inline auto configurableJoints() const
-
inline std::span<const ComponentJoint> joints() const
-
inline Module(ModuleType type, std::vector<Component> components, int connectorCount, std::vector<ComponentJoint> joints, ModuleId id, std::optional<int> rootComponent = std::nullopt)
-
struct rofi::configuration::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
-
inline std::span<const std::pair<float, float>> jointLimits() const
-
inline std::span<const float> positions() const
-
inline void setPositions(std::span<const float> pos)
-
virtual Matrix sourceToDest() const = 0
-
inline virtual Matrix destToSource() const
-
inline explicit Joint(std::vector<std::pair<float, float>> jointLimits)
-
struct rofi::configuration::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)
-
inline RigidJoint(const Matrix &sToDest)
-
struct rofi::configuration::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)
-
inline RotationJoint(Vector sourceOrigin, Vector sourceAxis, Vector destOrigin, Vector desAxis, Angle min, Angle max)
-
struct rofi::configuration::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, Rofibot::ModuleInfoHandle sourceModule, Rofibot::ModuleInfoHandle destModule, int sourceConnector, int destConnector)
-
inline virtual Matrix sourceToDest() const override
-
ATOMS_CLONEABLE(RoficomJoint)
Public Members
-
roficom::Orientation orientation
-
Rofibot::ModuleInfoHandle sourceModule
-
Rofibot::ModuleInfoHandle destModule
-
int sourceConnector
-
int destConnector
-
inline RoficomJoint(roficom::Orientation o, Rofibot::ModuleInfoHandle sourceModule, Rofibot::ModuleInfoHandle destModule, int sourceConnector, int destConnector)
-
struct rofi::configuration::ComponentJoint
Joint between two components of the same module.
Public Functions
-
ComponentJoint(ComponentJoint&&) = default
-
ComponentJoint &operator=(ComponentJoint&&) = default
-
inline ComponentJoint(const ComponentJoint &o)
-
inline ComponentJoint &operator=(const ComponentJoint &o)
-
ComponentJoint(ComponentJoint&&) = default
-
struct rofi::configuration::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)
-
int getIndexInParent() const
Get the index of component in parent.
-
Matrix getPosition() const
Get the absolute component position.
Raises std::logic_error if the rofibot is not prepared
-
std::optional<std::pair<const Component&, roficom::Orientation>> getNearConnector() const
Find a connector of another module in the same Rofibot that can be connected to.
Returns the connector and orientation Returns
nullopt
if no such connector existsRaises std::logic_error if the rofibot is not prepared
-
using JointId = int
-
struct rofi::configuration::SpaceJoint
Joint between a fixed point in space and a module.
Public Functions
-
inline SpaceJoint(atoms::ValuePtr<Joint> joint, Vector refPoint, Rofibot::ModuleInfoHandle destModule, int destComponent)
-
SpaceJoint(SpaceJoint&&) = default
-
SpaceJoint &operator=(SpaceJoint&&) = default
-
inline SpaceJoint(const SpaceJoint &o)
-
inline SpaceJoint &operator=(const SpaceJoint &o)
-
inline SpaceJoint(atoms::ValuePtr<Joint> joint, Vector refPoint, Rofibot::ModuleInfoHandle destModule, int destComponent)
-
class rofi::configuration::NoCollision
Collision model ignoring collision.
-
class rofi::configuration::SimpleCollision
Collision model taking into account only spherical collisions of the shoes.
Modules
-
class rofi::configuration::UniversalModule : public rofi::configuration::Module
Public Types
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 const auto &getConnector(const std::string &cStr) const
-
ATOMS_CLONEABLE(UniversalModule)
-
class rofi::configuration::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)
-
inline UnknownModule(std::vector<Component> components, int connectorCount, std::vector<ComponentJoint> joints, ModuleId id, std::optional<int> rootComponent = std::nullopt)
Functions
-
Rofibot::RoficomJointHandle rofi::configuration::connect(const Component &c1, const Component &c2, roficom::Orientation o)
Connect two modules via connector.
Requires that both modules belong to the same Rofibot, otherwise std::logic_error is thrown.
-
template<typename JointT, typename ...Args>
Rofibot::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.
First argument specified the component, the rest of the arguments are forwarded
Returns ID of the joint which can be used for setting parameters of the joint
-
template<typename JointT, typename ...Args>
ComponentJoint rofi::configuration::makeComponentJoint(int source, int dest, Args&&... args)
Serialization
Configuration also supports serialization to and from json format via functions toJSON and fromJSON respectively, so that you can save your configuration into a file and load it as needed. For the json itself we use nlohman::json library.
The configuration description consists of three main parts: modules, moduleJoints, and spaceJoints.
The minimal configuration looks like this.
#include <configuration/serialization.hpp>
// the json library supports string literals
auto js = "{ \"modules\" : [], \"spaceJoints\" : [], \"moduleJoints\" : [] }"_json;
Rofibot bot = fromJSON( js );
// and we can continue as before
If we were to represent the configuration with two universal modules shown above, we could do it with this json
{
"modules" : [
{
"id" : 42,
"type" : "universal",
"alpha" : 0,
"beta" : 0,
"gamma" : 0
},
{
"id" : 66,
"type" : "universal",
"alpha" : 0,
"beta" : 45,
"gamma" : 90
}
],
"moduleJoints" : [
{
"orientation" : "East",
"from" : { "id" : 66, "connector" : "A+X" },
"to" : { "id" : 42, "connector" : "A-X" }
}
],
"spaceJoints" : [
{
"point" : [ 0, 0, 0 ],
"to" : {
"id" : 42,
"component" : 6
},
"joint" : {
"type" : "rigid",
"sourceToDestination" : [ [1, 0, 0, 0]
, [0, 1, 0, 0]
, [0, 0, 1, 0]
, [0, 0, 0, 1] ]
}
}
]
}
You are not limited to universal modules only, currently we support a module Pad representing a 5x4 pad of RoFICoMs which can be represented as
{
"id" : 66,
"type" : "pad",
"width" : 5,
"height" : 4
}
and there is also a representation of an arbitrary module corresponding to the UnknownModule. Its attributes mirror the class
{
"id" : 66,
"components" : [ < array of components > ],
"joints" : [ < array of joints > ]
}
where the component has three possible values
[
{
"type" : "roficom"
},
{
"type" : "UM shoe"
},
{
"type" : "UM body"
}
]
and joint is represented as
{
"from" : < component >,
"destination" : < component >,
"sourceToDestination" : < matrix >,
"joint" : < joint >
}
where possible values of the joint are either RigidJoint represented as
{
"type" : "rigid"
}
or the RotationJoint which requires appropriate matrices
{
"type" : "rotational",
"axis" : < 4-dimensional array >,
"preMatrix" : < matrix >,
"postMatrix" : < matrix >,
"min" : < lower-limit – number >,
"max" : < upper-limit – number >
}
Matrices are, as shown above, represented by 4x4 dimensional array. Or, for the identity matrix, you can use a string representation, just write “identity” instead of [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]].
-
template<typename Callback>
inline nlohmann::json rofi::configuration::serialization::toJSON(const Rofibot &bot, Callback attrCb) Serialize given Rofibot to json.
Callback for attributes has to cover all of these possible arguments:
callback for a module gets: const reference to the Module itself
callback for a joint gets: const reference to the Joint itself and its index within the module
callback for a component gets: const reference to the Component or ComponentJoint and its index
callback for a SpaceJoint or a RoficomJoint gets a const reference to the appropriate joint
- Parameters
attrCb – a suitable function or Callable object that returns a
nlohmann::json
which is then stored into appropriate"attributes"
field
The callback is optional. It provides you with the ability to extend the json representation with an “attributes” property, which can be added to any object within the json. It can contain some metadata you might use when working with and sharing the configuration description. For details, see the section below.
-
template<typename Callback>
inline Rofibot rofi::configuration::serialization::fromJSON(const nlohmann::json &j, Callback attrCb) Load a Rofibot from given json.
Callback for attributes has to cover all of these possible arguments:
callback for a Module gets: const reference for the json[ “attributes” ] and const reference to the Module itself
callback for a Joint gets: const reference for the json[ “attributes” ] and const reference to the Joint itself and its index within the module
callback for a Component and ComponentJoint gets: const reference for the json[ “attributes” ] and a const reference to the Component itself and its index within the module
callback for a SpaceJoint or a RoficomJoint gets: const reference for the json[ “attributes” ] and a handle for given connection
- Parameters
j – json with a Rofibot
attrCb – a suitable function or Callable object that process appropriate
"attributes"
fields
Here you can provide a callback function, that is used for parsing the optional “attributes” field. If no callback is provided, the field, if present, is ignored. The callback is written in the same way as for toJSON.
Attributes callback
You can extend the json description of a configuration with “attributes” field. This field can be present in any object within the configuration, so the callback function has to be able to accept every corresponding type. The possible callback for toJSON that stores a ModuleId to “attributes” looks like
overload{ []( const Module& m ) { return nlohmann::json( m.getId() ); },
[]( const ComponentJoint&, int jointIndex ) { return nlohmann::json{}; },
[]( const Component&, int componentIndex ) { return nlohmann::json{}; },
[]( const RoficomJoint& ) { return nlohmann::json{}; },
[]( const SpaceJoint& ) { return nlohmann::json{}; }
};
You can see that every function returns a nlohman::json which is then stored to appropriate “attributes” field.
To collect these attributes you can then use this callback
std::vector< ModuleId > ids;
overload{ [ &ids ]( const nlohmann::json& j, const Module& m ) {
ids.push_back( j );
},
[]( const nlohmann::json&, const ComponentJoint&, int jointIndex ) { return; },
[]( const nlohmann::json&, const Component&, int componentIndex ) { return; },
[]( const nlohmann::json&, Rofibot::RoficomJointHandle ) { return; },
[]( const nlohmann::json&, Rofibot::SpaceJointHandle ) { return; },
};
See, that the main difference is in the arguments – callback given to fromJSON takes a json that is the content of the respective “attributes” field.