Models, Links, Joints and Sensors
- Models
- Reusing Gazebo-related devices across profiles
- Accessing Links
- Accessing Joints
- Recursive Models
- Using Sensors
In this section, we will learn how models defined in a Gazebo SDF world are made accessible within the Syskit system. We will limit ourselves to the supported built-in elements of a model: links, joints and sensors. The next section will cover plugins.
Models
The gist of things is to "dedicate" a Syskit profile to be the interface for a given
model in Gazebo, the same way that we usually "dedicate" a profile for a given robot
system. This profile, usually called Base
will contain a use_gazebo_model
stanza.
module MyBundle
module Profiles
module Gazebo
profile "Base" do
# prefix_device_with_name is a backward compatibility thing.
# Just pass true.
use_gazebo_model "model://ModelName", prefix_device_with_name: true
end
end
end
end
This stanza will define a number of devices for links, sensors and plugins
These devices are named after the full gazebo name, with gazebo's ::
separator replaced by _
and
resp. _link
, _sensor
and _plugin
suffixes.
For instance, in
<model name="wet_paint">
<link name="camera" />
</model>
the device that represents the model will be named wet_paint
and the one for
the link wet_paint_camera_link
, respectively accessible via Base.wet_paint_dev
and
Base.wet_paint_camera_link_dev
. See our tutorial for
a live example.
The stanza exposes a device per link. This device, of type
CommonModels::Devices::Gazebo::Link
exposes the whole link state (pose, velocity and acceleration), and allows to
apply efforts to it through its Wrench
input port.
When the model is root in the world, i.e. is not child of another model, a device of type CommonModels::Devices::Gazebo::RootModel will also be created. This device exposes the model's pose and allows to change it. It is useful mainly to place a model in a certain pose without having to control it through forces. However, if you do not want to lose composability of your models, do not use this feature.
Note: an ill-documented behavior of Gazebo is that a model pose is the pose of its canonical link, which in general is the first link of the model
Reusing Gazebo-related devices across profiles
One must never have two use_gazebo_model
stanzas with the same model in two different
profiles that are used on the same system. The recommended way to deal with the need
to share gazebo-related devices across profiles is to have a Base
profile that does
the use_gazebo_model
, and then refer to these devices explicitly, as e.g.
Base.wet_paint_camera_dev
Accessing Links
Instead of using the pre-defined link devices, we recommend that you define
devices for the links you need through the sdf_export_link
stanza. This stanza
creates a
CommonModels::Devices::Gazebo::Link
device that allows to read the status of the link, as well as apply an effort (a
wrench) on it.
module MyBundle
module Profiles
module Gazebo
profile "Base" do
# prefix_device_with_name is a backward compatibility thing.
# Just pass true.
use_gazebo_model "model://model_name", prefix_device_with_name: true
sdf_export_link(
model_name_dev, as: "some2other",
from_frame: "model_name::some",
to_frame: "model_name::other"
)
end
end
end
end
The as
argument declares the device name (which in this case will therefore be
accessed with Base.some2other_dev
). from_frame
defines the name of the link
whose pose the device's pose output will publish, and to_frame
the name of the
reference link (i.e. w.r.t. the from_frame
link's pose will be calculated).
The to_frame
is considered fixed in these calculations (i.e. we do not compute
relative velocities). The world
frame represents the frame attached to the origin
of the Gazebo world.
We recommend following these conventions
to name the exported link, that is always ${from_frame}2${to_frame}
. Note that the
world frame is always available via world
.
For instance, assuming we have a vehicle's model named customvehicle
and that this
vehicle has a camera attached to a tilt unit. The SDF could be:
<model name="custom_vehicle">
<link name="cog" />
<link name="camera" />
<joint name="camera2cog" type="revolute">
<parent>cog</parent>
<child>camera</child>
</joint>
</model>
Within the simulation, one could get access to the camera2cog
transform through
the camera2cog_dev
device declared by:
module CustomVehicle
module Profiles
module Gazebo
module Base
use_gazebo_model "model://custom_vehicle", prefix_device_with_name: true
sdf_export_link(
custom_vehicle_dev,
as: "camera2cog", from_frame: "custom_vehicle::camera",
to_frame: "custom_vehicle::cog"
)
end
end
end
end
Accessing Joints
Subset of the joints can be exported as single devices via the
sdf_export_joint
stanza. This defines an interface of type
CommonModels::Services::JointsControlledSystem
, through which you can control
the joints and read its status. For instance, assuming our custom vehicle has a pan-tilt
unit for the camera, with separate pan and tilt joints, the following declaration will
create a Base.camera_ptu_dev
device that will have one input and one output
of type base::samples::Joints
, in which the elements will be first the tilt and then
the pan joint.
module CustomVehicle
module Profiles
module Gazebo
module Base
use_gazebo_model "model://custom_vehicle", prefix_device_with_name: true
sdf_export_joint(
custom_vehicle_dev,
as: "camera_ptu",
ignore_joint_names: true,
joint_names: [
"custom_vehicle::camera_tilt_joint",
"custom_vehicle::camera_pan_joint"
]
)
end
end
end
end
The ignore_joint_names
instructs the component to assume that the order of the joints
on input is the declared order, and not care about the joint names. We recommend working
this way.
Gazebo supports setting a joint's effort, position and velocity. The input joints
must have exactly one of these fields set. If more than one is set, the model task will
go into the INVALID_JOINT_COMMAND
exception.
Recursive Models
As long as you
- use the model device only to read its position,
- use
sdf_export_link
andsdf_export_joint
, - use
ignore_joint_names: true
insdf_export_joint
Then the gazebo-syskit integration gracefully handles having the model used in a profile as a submodel of another in the world that is being actually loaded. This allows for instance to define profiles that control complex parts of a system (e.g. a manipulator), test them separately and then combine them in a single system.
How is this different from Gazebo ? While sdformat allows to have a <model>
inside another, as well
as include a model inside another, what it does is lexically "flatten" the SDF to
have a single model. That is, all joints and links from submodels are placed in their
parent model, only adding the submodel name as prefix. It means that link and joint
names change when you combine your models.
For instance, from the perspective of Gazebo
<model name="base">
<model name="left_arm">
<link name="base" />
</model>
<model name="right_arm">
<link name="base" />
</model>
</model>
is actually managed as:
<model name="base">
<link name="left_arm::base" />
<link name="left_arm::right_arm">
</model>
Using Sensors
Apart from links and models, the use_gazebo_model
stanza will create devices to expose devices that are present in the sdformat model.
The Syskit support for Gazebo handles only a subset of the sensors available in Gazebo.
All sensor-related components are declared in the
simulation/orogen/rock_gazebo
package.
ray
are exposed asrock_gazebo::LaserScanTask
imu
are exposed asrock_gazebo::ImuTask
gps
are exposed asrock_gazebo::GPSTask
camera
are exposed asrock_gazebo::CameraTask
The devices are named after the sensor's full name, with the _sensor
suffix, e.g.
a camera
camera in the wet_paint
model would be wet_paint_camera_sensor_dev
.
In doubt, just open the syskit IDE and check the profile.