Skip to content

Commit

Permalink
Merge pull request #730 from ignitionrobotics/particle_emitter
Browse files Browse the repository at this point in the history
Particle emitter based on SDF
  • Loading branch information
nkoenig committed Apr 9, 2021
1 parent 0eb4514 commit 0ec8a43
Show file tree
Hide file tree
Showing 18 changed files with 1,218 additions and 0 deletions.
5 changes: 5 additions & 0 deletions examples/worlds/particle_emitter.sdf
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<?xml version="1.0" ?>

<!-- NOTE: This world uses a particle emitter that is implemented as
a plugin. We recommend using particle emitters based on the SDF
specification. See the test/worlds/particle_emitter2.sdf example.
-->

<!--
Launch this example with:
Expand Down
119 changes: 119 additions & 0 deletions examples/worlds/particle_emitter2.sdf
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?xml version="1.0" ?>

<!--
Launch this example with:
ign gazebo -r particle_emitter.sdf
Try modifying some parameters of the emitter:
To disable the particle emitter:
ign topic -t /model/fog_generator/link/fog_link/particle_emitter/emitter/cmd -m ignition.msgs.ParticleEmitter -p 'emitting: {data: false}'
Enable back the particle emitter:
ign topic -t /model/fog_generator/link/fog_link/particle_emitter/emitter/cmd -m ignition.msgs.ParticleEmitter -p 'emitting: {data: true}'
Then, change the particle rate:
ign topic -t /model/fog_generator/link/fog_link/particle_emitter/emitter/cmd -m ignition.msgs.ParticleEmitter -p 'rate: {data: 100}'
-->

<sdf version="1.6">
<world name="particle_emitters">

<physics name="1ms" type="ode">
<max_step_size>0.001</max_step_size>
<real_time_factor>1.0</real_time_factor>
</physics>
<plugin
filename="ignition-gazebo-physics-system"
name="ignition::gazebo::systems::Physics">
<!-- Use TPE in order to use nested models -->
<engine><filename>libignition-physics-tpe-plugin.so</filename></engine>
</plugin>
<plugin
filename="ignition-gazebo-user-commands-system"
name="ignition::gazebo::systems::UserCommands">
</plugin>
<plugin
filename="ignition-gazebo-scene-broadcaster-system"
name="ignition::gazebo::systems::SceneBroadcaster">
</plugin>
<plugin
filename="ignition-gazebo-particle-emitter2-system"
name="ignition::gazebo::systems::ParticleEmitter2">
</plugin>

<light type="directional" name="sun">
<cast_shadows>true</cast_shadows>
<pose>0 0 10 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.5 0.5 0.5 1</specular>
<attenuation>
<range>1000</range>
<constant>0.9</constant>
<linear>0.01</linear>
<quadratic>0.001</quadratic>
</attenuation>
<direction>-0.5 0.1 -0.9</direction>
</light>

<model name="ground_plane">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<plane>
<normal>0 0 1</normal>
</plane>
</geometry>
</collision>
<visual name="visual">
<geometry>
<plane>
<normal>0 0 1</normal>
<size>100 100</size>
</plane>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1</ambient>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.8 0.8 0.8 1</specular>
</material>
</visual>
</link>
</model>

<include>
<uri>https://fuel.ignitionrobotics.org/1.0/openrobotics/models/fog generator</uri>
</include>

<!-- Nested model example, where the particles are bright red
billboards -->
<model name="nested">
<static>true</static>
<pose>20 20 0 0 0 0</pose>
<model name="fog_generator">
<link name="fog_link_nested">
<particle_emitter name="emitter" type="box">
<emitting>true</emitting>
<size>10 10 0</size>
<particle_size>1 1 1</particle_size>
<lifetime>25</lifetime>
<min_velocity>0.1</min_velocity>
<max_velocity>0.2</max_velocity>
<scale_rate>0.5</scale_rate>
<rate>5</rate>
<material>
<diffuse>1.0 0.0 0.0</diffuse>
<specular>1.0 0.0 0.0</specular>
</material>
</particle_emitter>
</link>
</model>
</model>

</world>
</sdf>
38 changes: 38 additions & 0 deletions include/ignition/gazebo/Conversions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <ignition/msgs/inertial.pb.h>
#include <ignition/msgs/light.pb.h>
#include <ignition/msgs/material.pb.h>
#include <ignition/msgs/particle_emitter.pb.h>
#include <ignition/msgs/physics.pb.h>
#include <ignition/msgs/scene.pb.h>
#include <ignition/msgs/sensor.pb.h>
Expand All @@ -47,6 +48,7 @@
#include <sdf/Light.hh>
#include <sdf/Material.hh>
#include <sdf/Noise.hh>
#include <sdf/ParticleEmitter.hh>
#include <sdf/Physics.hh>
#include <sdf/Scene.hh>
#include <sdf/Sensor.hh>
Expand Down Expand Up @@ -624,6 +626,42 @@ namespace ignition
/// \return Axis aligned box object.
template<>
math::AxisAlignedBox convert(const msgs::AxisAlignedBox &_in);

/// \brief Generic conversion from a particle emitter SDF object to another
/// type.
/// \param[in] _in Particle emitter SDF object.
/// \return Conversion result.
/// \tparam Out Output type.
template<class Out>
Out convert(const sdf::ParticleEmitter &/*_in*/)
{
Out::ConversionNotImplemented;
}

/// \brief Specialized conversion from a particle emitter SDF object to
/// a particle emitter message object.
/// \param[in] _in Particle emitter SDF object.
/// \return Particle emitter message.
template<>
msgs::ParticleEmitter convert(const sdf::ParticleEmitter &_in);

/// \brief Generic conversion from a particle emitter SDF object to another
/// type.
/// \param[in] _in Particle emitter SDF object.
/// \return Conversion result.
/// \tparam Out Output type.
template<class Out>
Out convert(const msgs::ParticleEmitter &/*_in*/)
{
Out::ConversionNotImplemented;
}

/// \brief Specialized conversion from a particle emitter SDF object to
/// a particle emitter message object.
/// \param[in] _in Particle emitter SDF object.
/// \return Particle emitter message.
template<>
sdf::ParticleEmitter convert(const msgs::ParticleEmitter &_in);
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions include/ignition/gazebo/SdfEntityCreator.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <sdf/Light.hh>
#include <sdf/Link.hh>
#include <sdf/Model.hh>
#include <sdf/ParticleEmitter.hh>
#include <sdf/Physics.hh>
#include <sdf/Sensor.hh>
#include <sdf/Visual.hh>
Expand Down Expand Up @@ -140,6 +141,13 @@ namespace ignition
/// \sa CreateEntities(const sdf::Model *)
public: Entity CreateEntities(const sdf::Sensor *_sensor);

/// \brief Create all entities that exist in the
/// sdf::ParticleEmitter object.
/// \param[in] _emitter SDF ParticleEmitter object.
/// \return ParticleEmitter entity.
/// \sa CreateEntities(const sdf::Link *)
public: Entity CreateEntities(const sdf::ParticleEmitter *_emitter);

/// \brief Request an entity deletion. This will insert the request
/// into a queue. The queue is processed toward the end of a simulation
/// update step.
Expand Down
20 changes: 20 additions & 0 deletions include/ignition/gazebo/Util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,25 @@ namespace ignition
std::string IGNITION_GAZEBO_VISIBLE validTopic(
const std::vector<std::string> &_topics);

/// \brief Helper function that returns a valid Ignition Transport topic
/// consisting of the scoped name for the provided entity.
///
/// For example, if the provided entity has a scoped name of
/// `my_model::my_link::my_sensor` then the resulting topic name will
/// be `/model/my_model/link/my_link/sensor/my_sensor`. If _excludeWorld
/// is false, then the topic name will be prefixed by `/world/WORLD_NAME/`,
/// where `WORLD_NAME` is the name of the world.
///
/// \param[in] _entity The entity to generate the topic name for.
/// \param[in] _ecm The entity component manager.
/// \param[in] _excludeWorld True to exclude the world name from the topic.
/// \return An Ignition Transport topic name based on the scoped name of
/// the provided entity, or empty string if a topic name could not be
/// generated.
std::string topicFromScopedName(const Entity &_entity,
const EntityComponentManager &_ecm,
bool _excludeWorld = true);

/// \brief Environment variable holding resource paths.
const std::string kResourcePathEnv{"IGN_GAZEBO_RESOURCE_PATH"};

Expand All @@ -168,6 +187,7 @@ namespace ignition
/// \brief Environment variable holding paths to custom rendering engine
/// plugins.
const std::string kRenderPluginPathEnv{"IGN_GAZEBO_RENDER_ENGINE_PATH"};

}
}
}
Expand Down
127 changes: 127 additions & 0 deletions src/Conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1326,3 +1326,130 @@ math::AxisAlignedBox ignition::gazebo::convert(const msgs::AxisAlignedBox &_in)
out.Max() = msgs::Convert(_in.max_corner());
return out;
}

//////////////////////////////////////////////////
template<>
IGNITION_GAZEBO_VISIBLE
msgs::ParticleEmitter ignition::gazebo::convert(const sdf::ParticleEmitter &_in)
{
msgs::ParticleEmitter out;
out.set_name(_in.Name());
switch(_in.Type())
{
default:
case sdf::ParticleEmitterType::POINT:
out.set_type(msgs::ParticleEmitter::POINT);
break;
case sdf::ParticleEmitterType::BOX:
out.set_type(msgs::ParticleEmitter::BOX);
break;
case sdf::ParticleEmitterType::CYLINDER:
out.set_type(msgs::ParticleEmitter::CYLINDER);
break;
case sdf::ParticleEmitterType::ELLIPSOID:
out.set_type(msgs::ParticleEmitter::ELLIPSOID);
break;
}

msgs::Set(out.mutable_pose(), _in.RawPose());
msgs::Set(out.mutable_size(), _in.Size());
msgs::Set(out.mutable_particle_size(), _in.ParticleSize());
out.mutable_rate()->set_data(_in.Rate());
out.mutable_duration()->set_data(_in.Duration());
out.mutable_emitting()->set_data(_in.Emitting());
out.mutable_lifetime()->set_data(_in.Lifetime());
if (_in.Material())
{
out.mutable_material()->CopyFrom(convert<msgs::Material>(*_in.Material()));
}
out.mutable_min_velocity()->set_data(_in.MinVelocity());
out.mutable_max_velocity()->set_data(_in.MaxVelocity());
msgs::Set(out.mutable_color_start(), _in.ColorStart());
msgs::Set(out.mutable_color_end(), _in.ColorEnd());
out.mutable_scale_rate()->set_data(_in.ScaleRate());
out.mutable_color_range_image()->set_data(_in.ColorRangeImage());

if (!_in.ColorRangeImage().empty())
{
std::string path = asFullPath(_in.ColorRangeImage(), _in.FilePath());

common::SystemPaths systemPaths;
systemPaths.SetFilePathEnv(kResourcePathEnv);
std::string absolutePath = systemPaths.FindFile(path);

if (!absolutePath.empty())
out.mutable_color_range_image()->set_data(absolutePath);
}

/// \todo(nkoenig) Modify the particle_emitter.proto file to
/// have a topic field.
if (!_in.Topic().empty())
{
auto header = out.mutable_header()->add_data();
header->set_key("topic");
header->add_value(_in.Topic());
}

return out;
}

//////////////////////////////////////////////////
template<>
IGNITION_GAZEBO_VISIBLE
sdf::ParticleEmitter ignition::gazebo::convert(const msgs::ParticleEmitter &_in)
{
sdf::ParticleEmitter out;
out.SetName(_in.name());
switch(_in.type())
{
default:
case msgs::ParticleEmitter::POINT:
out.SetType(sdf::ParticleEmitterType::POINT);
break;
case msgs::ParticleEmitter::BOX:
out.SetType(sdf::ParticleEmitterType::BOX);
break;
case msgs::ParticleEmitter::CYLINDER:
out.SetType(sdf::ParticleEmitterType::CYLINDER);
break;
case msgs::ParticleEmitter::ELLIPSOID:
out.SetType(sdf::ParticleEmitterType::ELLIPSOID);
break;
}
out.SetRawPose(msgs::Convert(_in.pose()));
out.SetSize(msgs::Convert(_in.size()));
out.SetParticleSize(msgs::Convert(_in.particle_size()));
out.SetMinVelocity(msgs::Convert(_in.min_velocity()));
out.SetMaxVelocity(msgs::Convert(_in.max_velocity()));
out.SetColorStart(msgs::Convert(_in.color_start()));
out.SetColorEnd(msgs::Convert(_in.color_end()));

if (_in.has_material())
{
out.SetMaterial(convert<sdf::Material>(_in.material()));
}

if (_in.has_rate())
out.SetRate(_in.rate().data());
if (_in.has_duration())
out.SetDuration(_in.duration().data());
if (_in.has_emitting())
out.SetEmitting(_in.emitting().data());
if (_in.has_lifetime())
out.SetLifetime(_in.lifetime().data());
if (_in.has_scale_rate())
out.SetScaleRate(_in.scale_rate().data());
if (_in.has_color_range_image())
out.SetColorRangeImage(_in.color_range_image().data());

for (int i = 0; i < _in.header().data_size(); ++i)
{
auto data = _in.header().data(i);
if (data.key() == "topic" && data.value_size() > 0)
{
out.SetTopic(data.value(0));
}
}

return out;
}
Loading

0 comments on commit 0ec8a43

Please sign in to comment.