custom
harmonic
plugin
Gazebo harmonic custom plugin
gazebo examples
Plugin library loaded
|
v
+------------------------------+
| Constructor (C++ object) |
+------------------------------+
|
v
+---------------------------------------------------+
| Configure() [ISystemConfigure] |
| - runs ONCE when plugin is attached/loaded |
| - read/write EntityComponentManager (ECM) |
| - parse SDF params, create components, cache IDs |
+---------------------------------------------------+
|
v
Simulation loop (every tick / iteration)
|
v
+---------------------------------------------------+
| PreUpdate() [ISystemPreUpdate] |
| - runs EVERY tick, BEFORE physics step |
| - read/write ECM |
| - apply commands (forces, joint targets, etc.) |
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| Update() [ISystemUpdate] (optional) |
| - runs EVERY tick, during the "update" phase |
| - read/write ECM |
| - typically physics/stepping related systems |
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| PostUpdate() [ISystemPostUpdate] |
| - runs EVERY tick, AFTER physics step |
| - READ-ONLY ECM (important!) |
| - publish state, compute observations/feedback |
+---------------------------------------------------+
|
v
(loop back to PreUpdate for next tick)
|
v
+---------------------------------------------------+
| Reset() [ISystemReset] (optional) |
| - runs when the sim/model/plugin is reset |
| - clear integrators, counters, internal state |
+---------------------------------------------------+
|
v
+------------------------------+
| Destructor (plugin unloaded) |
+------------------------------+
Rule of thumb
Control / write to world: PreUpdate()
Observe / publish state: PostUpdate()
One-time setup: Configure()
Clear internal state: Reset()
ECM (Entity Component Manager)
Instead of objects with C++ classes (like Classic Gazebo), Gazebo Sim uses an Entity–Component–System (ECS) architecture.
Entity = integer ID
Component = data attached to entity
System (plugin) = logic that reads/writes components
Entity
An Entity is just an ID (no methods, no class).
Examples of entities:
World
Model
Link
Joint
Sensor
Components
Components are typed data blobs attached to entities.
Component
Meaning
Pose
Position + orientation
LinearVelocity
Velocity
JointPosition
Joint angle
Name
Entity name
ParentEntity
Parent in tree
Link
Marks entity as a link
System
A System (plugin) reads/writes components via the ECM.
Simple demo:
Read Model pose
Get entity in configure method
Read entity pose component every simulation step
#include <gz/plugin/Register.hh>
#include <gz/sim/System.hh>
#include <gz/sim/components/Pose.hh>
#include <gz/common/Console.hh>
#include <gz/sim/Entity.hh>
using namespace gz ;
using namespace sim ;
class SimpleECM :
public gz :: sim :: System ,
public gz :: sim :: ISystemConfigure ,
public gz :: sim :: ISystemPreUpdate
{
public :
void Configure ( const gz :: sim :: Entity & entity ,
const std :: shared_ptr < const sdf :: Element > & ,
gz :: sim :: EntityComponentManager & ,
gz :: sim :: EventManager & ) override
{
modelEntity = entity ;
gzmsg << "Plugin attached to " << entity << " \n " ;
}
void PreUpdate ( const gz :: sim :: UpdateInfo & ,
gz :: sim :: EntityComponentManager & ecm ) override
{
// Read pose component from ecm for entity modelEntity
auto poseComp = ecm . Component < gz :: sim :: components :: Pose > ( modelEntity );
if ( ! poseComp ) return ;
auto pose = poseComp -> Data ();
gzmsg << "-----> Z = " << pose . Pos (). Z () << " \n " ;
}
private :
gz :: sim :: Entity modelEntity { kNullEntity };
};
GZ_ADD_PLUGIN ( SimpleECM , gz :: sim :: System ,
SimpleECM :: ISystemConfigure ,
SimpleECM :: ISystemPreUpdate )
GZ_ADD_PLUGIN_ALIAS ( SimpleECM ,
"gz::sim::systems::SimpleECM" )
├── .devcontainer
│ ├── Dockerfile
│ └── devcontainer.json
├── docker-compose.yaml
├── .gitignore
└── worlds
└── mini.world
└── models
└── simple_box
└── model.config
└── model.sdf
└── bin
└── src
└── simple
└── simple.cc
└── CMakeLists.txt
simple.cpp #include <gz/sim/System.hh>
#include <gz/plugin/Register.hh>
#include <iostream>
#include <gz/common/Console.hh>
using namespace gz ;
using namespace sim ;
/////////////////////////////////////////////////
class SimpleParamReader
: public System ,
public ISystemConfigure
{
public :
void Configure ( const Entity & ,
const std :: shared_ptr < const sdf :: Element > & _sdf ,
EntityComponentManager & ,
EventManager & ) override
{
std :: cout << "----------------------------- 0.2 ---------------------------------------" << std :: endl ;
if ( _sdf -> HasElement ( "test_value" ))
{
auto value = _sdf -> Get < std :: string > ( "test_value" );
gzmsg << "[SimpleParamReader] test_value: " << value << std :: endl ;
}
else
{
gzerr << "[SimpleParamReader] No <test_value> found in SDF" << std :: endl ;
}
gzmsg << "Hello (info)" << std :: endl ;
gzwarn << "Something looks odd" << std :: endl ;
gzerr << "Something failed!" << std :: endl ;
gzdbg << "Debug detail: x=" << 42 << " \n " << std :: endl ;
gzlog << "Trace detail" << std :: endl ;
std :: cout << "--------------------------------------------------------------------" << std :: endl ;
}
};
GZ_ADD_PLUGIN ( SimpleParamReader ,
System ,
SimpleParamReader :: ISystemConfigure )
GZ_ADD_PLUGIN_ALIAS ( SimpleParamReader ,
"gz::sim::systems::SimpleParamReader" )
CMakeLists.txt cmake_minimum_required ( VERSION 3.10 )
project ( SimpleParamReader )
find_package ( gz-sim8 REQUIRED )
find_package ( gz-plugin2 REQUIRED )
add_library ( SimpleParamReader SHARED src/simple/simple.cc )
target_link_libraries ( SimpleParamReader
gz-sim8::gz-sim8
gz-plugin2::gz-plugin2
)
install ( TARGETS SimpleParamReader
LIBRARY DESTINATION ${ CMAKE_SOURCE_DIR } /bin )
<?xml version="1.0"?>
<sdf version= "1.7" >
<model name= "simple_box" >
<static> false</static>
<link name= "link" >
...
</link>
<plugin
name= "gz::sim::systems::SimpleParamReader"
filename= "libSimpleParamReader.so" >
<test_value> HelloWorld</test_value>
</plugin>
</model>
</sdf>
VSCode
.vscode/settings.json {
"configurations" : [
{
"name" : "Linux" ,
"includePath" : [
"${workspaceFolder}/**" ,
"/usr/include/gz/plugin2" ,
"/usr/include/gz/sim8" ,
"/usr/include/gz/utils2" ,
"/usr/include/gz/msgs10" ,
"/usr/include/gz/common5" ,
"/usr/include/gz/math7" ,
"/usr/include/gz/transport13" ,
"/usr/include/gz/sdformat14"
],
"defines" : [],
"compilerPath" : "/usr/bin/gcc" ,
"cStandard" : "c17" ,
"cppStandard" : "gnu++17" ,
"intelliSenseMode" : "linux-gcc-x64"
}
],
"version" : 4
}
Build and install
cmake -S . -B build
cmake --build build
cmake --install build
GZ_SIM_SYSTEM_PLUGIN_PATH
export GZ_SIM_SYSTEM_PLUGIN_PATH = $( pwd ) /bin:$GZ_SIM_SYSTEM_PLUGIN_PATH