This project aims to build middleware that facilitates communication and integration between the Webots robotics simulator and the Robocomp framework.
For the component to effectively communicate with the robot in Webots, it's essential to configure the robot's controller to <extern> in your Webots scene. This ensures that the robot's behavior is externally controlled by a program outside Webots, in this case, our middleware.
Open your Webots world file: This is typically a .wbt file where your robot and environment are defined.
Select your robot node: In the scene tree (usually on the left side of the Webots interface), find and select your robot node.
Modify the controller field: In the robot's properties (usually on the right side of the Webots interface), find the controller field. Change its value to <extern>.
Save the world file: Ensure you save the .wbt file after making this change.
Now, when you run the simulation in Webots, the robot will wait for an external controller (Webots2Robocomp in this case) to connect and take control.
This component implements diferents interfaces that works with the following measures:
- Lidar3D: milimeters.
Once the robot's controller is set to <extern>, ensure your middleware is ready to connect. Typically, you'd do this:
· Start Webots and play the simulation.
· Launch the middleware. It should automatically detect the robot waiting for an external controller and establish a connection.
Like any other component, Webots2Robocomp requires a configuration file to start. In etc/config or etc/config.toml, you can find an example of the configuration file.
To avoid modifying the config file directly in the repository, you can copy it to the component's home directory. This prevents changes from being overridden by future git pull commands:
cd <Webots2Robocomp's path>
cp etc/config etc/yourConfigAfter editing the new config file we can run the component:
cmake -B build && make -C build -j12 # Compile the component
bin/Webots2Robocomp etc/yourConfig # Execute the componentThis section explains how to work with the generated code of Webots2Robocomp, including what can be modified and how to use key features.
You can freely edit the following files:
- etc/* – Configuration files
- src/* – Component logic and implementation
- README.md – Documentation
The generated folder contains autogenerated files. Do not edit these files directly, as they will be overwritten every time the component is regenerated with RoboComp.
The ConfigLoader simplifies fetching configuration parameters. Use the get<>() method to retrieve parameters from the configuration file.
// Syntax
type variable = this->configLoader.get<type>("ParameterName");
// Example
int computePeriod = this->configLoader.get<int>("Period.Compute");RoboComp components utilize a state machine to manage the main execution flow. The default states are:
- Initialize:
- Executes once after the constructor.
- May use for parameter initialization, opening devices, and calculating constants.
- Compute:
- Executes cyclically after Initialize.
- Place your functional logic here. If an emergency is detected, call goToEmergency() to transition to the Emergency state.
- Emergency:
- Executes cyclically during emergencies.
- Once resolved, call goToRestore() to transition to the Restore state.
- Restore:
- Executes once to restore the component after an emergency.
- Transitions automatically back to the Compute state.
You can get the period of some state with de function getPeriod and set with setPeriod
int currentPeriod = getPeriod("Compute"); // Get the current Compute period
setPeriod("Compute", currentPeriod * 0.5); // Set Compute period to halfTo add a custom state, follow these steps in the constructor:
- Define Your State Use
GRAFCETStepto create your state. If any function is not required, usenullptr.
states["CustomState"] = std::make_unique<GRAFCETStep>("CustomState", period,
std::bind(&SpecificWorker::customLoop, this), // Cyclic function
std::bind(&SpecificWorker::customEnter, this), // On-enter function
std::bind(&SpecificWorker::customExit, this)); // On-exit function
- Define Transitions Add transitions between states using
addTransition. You can trigger transitions using Qt signals such asentered()andexited()or custom signals in .h.
// Syntax
states[srcState]->addTransition(originOfSignal, signal, dstState)
// Example
states["CustomState"]->addTransition(states["CustomState"].get(), SIGNAL(entered()), states["OtherState"].get());
states["Compute"]->addTransition(this, SIGNAL(customSignal()), states["CustomState"].get());
- Add State to the StateMachine Include your state in the state machine:
statemachine.addState(states["CustomState"].get());
The #define HIBERNATION_ENABLED flag in specificworker.h activates hibernation mode. When enabled, the component reduces its state execution frequency to 500ms if no method calls are received within 5 seconds. Once a method call is received, the period is restored to its original value.
Default hibernation monitoring runs every 500ms.
If you’re regenerating or adapting old components, here’s what has changed:
- Deprecated classes removed:
CommonBehavior,InnerModel,AGM,Monitors, andsrc/config.h. - Configuration parsing replaced with the new
ConfigLoader, supporting both .tomland legacy configuration formats. - Skeleton code split:
generated(non-editable) andsrc(editable). - Component period is now configurable in the configuration file.
- State machine integrated with predefined states:
Initialize,Compute,Emergency, andRestore. - With the
dsroption, you generateGin the GenericWorker, making the viewer independent. If you want to use thedsrviewer, you will need theQt GUI (QMainWindow)and thedsroption enabled in the CDSL. - Strings in the legacy config now need to be enclosed in quotes (
"").
To adapt older components to the new structure:
- Add
Period.ComputeandPeriod.Emergencyand swap Endpoints and Proxies with their names in theetc/configfile. - Merge the new
src/CMakeLists.txtand the oldCMakeListsSpecificfiles. - Modify
specificworker.h:- Add the
HIBERNATION_ENABLEDflag. - Update the constructor signature.
- Replace
setParamswith state definitions (Initialize,Compute, etc.).
- Add the
- Modify
specificworker.cpp:- Refactor the constructor entirely.
- Move
setParamslogic to theinitializestate usingConfigLoader.get<>(). - Remove the old timer and period logic and replace it with
getPeriod()andsetPeriod(). - Add the new function state
Emergency, andRestore. - Add the following code to the implements and publish functions:
#ifdef HIBERNATION_ENABLED hibernation = true; #endif
- Update Configuration Strings, ensure all strings in the
configunder legacy are enclosed in quotes (""), as required by the new structure. - Using DSR, if you use the DSR option, note that
Gis generated inGenericWorker, making the viewer independent. However, to use thedsrviewer, you must integrate aQt GUI (QMainWindow)and enable thedsroption in the CDSL. - Installing toml++, to use the new .toml configuration format, install the toml++ library:
mkdir ~/software 2> /dev/null; git clone https://github.com/marzer/tomlplusplus.git ~/software/tomlplusplus
cd ~/software/tomlplusplus && cmake -B build && sudo make install -C build -j12 && cd -- Installing qt6 Dependencies
sudo apt install qt6-base-dev qt6-declarative-dev qt6-scxml-dev libqt6statemachineqml6 libqt6statemachine6
mkdir ~/software 2> /dev/null; git clone https://github.com/GillesDebunne/libQGLViewer.git ~/software/libQGLViewer
cd ~/software/libQGLViewer && qmake6 *.pro && make -j12 && sudo make install && sudo ldconfig && cd -- Generated Code, When the component is generated, a
generatedfolder is created containing non-editable files. You can delete everything in thesrcdirectory except for:
src/specificworker.hsrc/specificworker.cppsrc/CMakeLists.txtsrc/mainUI.uiREADME.mdetc/configetc/config.toml- Your Clases...