mujoco_ros_utils
ExternalForce.cpp
Go to the documentation of this file.
1 #include "ExternalForce.h"
2 
3 #include <mujoco/mujoco.h>
4 
5 #include <iostream>
6 
7 namespace MujocoRosUtils
8 {
9 
11 {
12  mjpPlugin plugin;
13  mjp_defaultPlugin(&plugin);
14 
15  plugin.name = "MujocoRosUtils::ExternalForce";
16  plugin.capabilityflags |= mjPLUGIN_PASSIVE;
17 
18  const char * attributes[] = {"topic_name", "vis_scale"};
19 
20  plugin.nattribute = sizeof(attributes) / sizeof(attributes[0]);
21  plugin.attributes = attributes;
22 
23  plugin.nstate = +[](const mjModel *, // m
24  int // plugin_id
25  ) { return 0; };
26 
27  plugin.nsensordata = +[](const mjModel *, // m
28  int, // plugin_id
29  int // sensor_id
30  ) { return 0; };
31 
32  plugin.needstage = mjSTAGE_ACC;
33 
34  plugin.init = +[](const mjModel * m, mjData * d, int plugin_id)
35  {
36  auto * plugin_instance = ExternalForce::Create(m, d, plugin_id);
37  if(!plugin_instance)
38  {
39  return -1;
40  }
41  d->plugin_data[plugin_id] = reinterpret_cast<uintptr_t>(plugin_instance);
42  return 0;
43  };
44 
45  plugin.destroy = +[](mjData * d, int plugin_id)
46  {
47  delete reinterpret_cast<ExternalForce *>(d->plugin_data[plugin_id]);
48  d->plugin_data[plugin_id] = 0;
49  };
50 
51  plugin.reset = +[](const mjModel * m, double *, // plugin_state
52  void * plugin_data, int plugin_id)
53  {
54  auto * plugin_instance = reinterpret_cast<class ExternalForce *>(plugin_data);
55  plugin_instance->reset(m, plugin_id);
56  };
57 
58  plugin.compute = +[](const mjModel * m, mjData * d, int plugin_id, int // capability_bit
59  )
60  {
61  auto * plugin_instance = reinterpret_cast<class ExternalForce *>(d->plugin_data[plugin_id]);
62  plugin_instance->compute(m, d, plugin_id);
63  };
64 
65  plugin.visualize = +[](const mjModel * m, mjData * d, const mjvOption * opt, mjvScene * scn, int plugin_id)
66  {
67  auto * plugin_instance = reinterpret_cast<class ExternalForce *>(d->plugin_data[plugin_id]);
68  plugin_instance->visualize(m, d, opt, scn, plugin_id);
69  };
70 
71  mjp_registerPlugin(&plugin);
72 }
73 
74 ExternalForce * ExternalForce::Create(const mjModel * m, mjData * d, int plugin_id)
75 {
76  // topic_name
77  const char * topic_name_char = mj_getPluginConfig(m, plugin_id, "topic_name");
78  std::string topic_name = "";
79  if(strlen(topic_name_char) > 0)
80  {
81  topic_name = std::string(topic_name_char);
82  }
83 
84  // vis_scale
85  const char * vis_scale_char = mj_getPluginConfig(m, plugin_id, "vis_scale");
86  mjtNum vis_scale = 0.1;
87  if(strlen(vis_scale_char) > 0)
88  {
89  vis_scale = strtod(vis_scale_char, nullptr);
90  }
91 
92  // Set body_id
93  int body_id = 0;
94  for(; body_id < m->nbody; body_id++)
95  {
96  if(m->body_plugin[body_id] == plugin_id)
97  {
98  break;
99  }
100  }
101  if(body_id == m->nbody)
102  {
103  mju_error("[ExternalForce] Plugin not found in bodies.");
104  return nullptr;
105  }
106 
107  std::cout << "[ExternalForce] Create." << std::endl;
108 
109  return new ExternalForce(m, d, body_id, topic_name, vis_scale);
110 }
111 
112 ExternalForce::ExternalForce(const mjModel *, // m
113  mjData *, // d
114  int body_id,
115  const std::string & topic_name,
116  mjtNum vis_scale)
117 : body_id_(body_id), topic_name_(topic_name), vis_scale_(vis_scale)
118 {
119  if(topic_name_.empty())
120  {
121  topic_name_ = "/external_force";
122  }
123 
124  int argc = 0;
125  char ** argv = nullptr;
126  if(!rclcpp::ok())
127  {
128  rclcpp::init(argc, argv);
129  }
130  rclcpp::NodeOptions node_options;
131 
132  nh_ = rclcpp::Node::make_shared("mujoco_ros", node_options);
133  sub_ = nh_->create_subscription<mujoco_ros_utils::msg::ExternalForce>(
134  topic_name, 1, std::bind(&ExternalForce::callback, this, std::placeholders::_1));
135  // Use a dedicated queue so as not to call callbacks of other modules
136  executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
137  executor_->add_node(nh_);
138 }
139 
140 void ExternalForce::reset(const mjModel *, // m
141  int // plugin_id
142 )
143 {
144  msg_ = nullptr;
145 }
146 
147 void ExternalForce::compute(const mjModel *, // m
148  mjData * d,
149  int // plugin_id
150 )
151 {
152  // Call ROS callback
153  executor_->spin_once(std::chrono::seconds(0));
154 
155  if(end_time_ >= 0 && end_time_ <= d->time)
156  {
157  end_time_ = -1;
158  msg_ = nullptr;
159  }
160 
161  if(!msg_)
162  {
163  return;
164  }
165 
166  mjtNum pos_local[3];
167  pos_local[0] = msg_->pos.x;
168  pos_local[1] = msg_->pos.y;
169  pos_local[2] = msg_->pos.z;
170  mjtNum force[3];
171  force[0] = msg_->force.x;
172  force[1] = msg_->force.y;
173  force[2] = msg_->force.z;
174  mjtNum pos_world[3];
175  mju_rotVecMat(pos_world, pos_local, d->xmat + 9 * body_id_);
176  mju_addTo3(pos_world, d->xpos + 3 * body_id_);
177  mjtNum moment_arm[3];
178  mju_sub3(moment_arm, pos_world, d->xipos + 3 * body_id_);
179  mjtNum moment[3];
180  mju_cross(moment, moment_arm, force);
181 
182  mjtNum * data_force = d->xfrc_applied + 6 * body_id_;
183  mjtNum * data_moment = d->xfrc_applied + 6 * body_id_ + 3;
184  mju_copy3(data_force, force);
185  mju_copy3(data_moment, moment);
186 
187  if(end_time_ < 0)
188  {
189  end_time_ = d->time + msg_->duration.sec + msg_->duration.nanosec * 1e-9;
190  }
191 }
192 
193 void ExternalForce::visualize(const mjModel *, // m
194  mjData * d,
195  const mjvOption *, // opt
196  mjvScene * scn,
197  int // plugin_id
198 )
199 {
200  if(!msg_)
201  {
202  return;
203  }
204 
205  if(vis_scale_ <= 0)
206  {
207  return;
208  }
209 
210 #if mjVERSION_HEADER >= 300
211  mj_markStack(d);
212 #else
213  mjMARKSTACK;
214 #endif
215 
216  mjtNum pos_local[3];
217  pos_local[0] = msg_->pos.x;
218  pos_local[1] = msg_->pos.y;
219  pos_local[2] = msg_->pos.z;
220  mjtNum force[3];
221  force[0] = msg_->force.x;
222  force[1] = msg_->force.y;
223  force[2] = msg_->force.z;
224  mjtNum pos_world[3];
225  mju_rotVecMat(pos_world, pos_local, d->xmat + 9 * body_id_);
226  mju_addTo3(pos_world, d->xpos + 3 * body_id_);
227  mjtNum arrow_end[3];
228  mju_addScl3(arrow_end, pos_world, force, vis_scale_);
229  float rgba[4] = {1.0, 0.0, 0.0, 1.0};
230  constexpr mjtNum width = 0.01;
231  mjvGeom * force_geom = scn->geoms + scn->ngeom;
232  mjv_initGeom(force_geom, mjGEOM_NONE, NULL, NULL, NULL, rgba);
233  mjv_makeConnector(force_geom, mjGEOM_ARROW, width, pos_world[0], pos_world[1], pos_world[2], arrow_end[0],
234  arrow_end[1], arrow_end[2]);
235  force_geom->objtype = mjOBJ_UNKNOWN;
236  force_geom->objid = -1;
237  force_geom->category = mjCAT_DECOR;
238  force_geom->segid = scn->ngeom;
239  scn->ngeom++;
240 
241 #if mjVERSION_HEADER >= 300
242  mj_freeStack(d);
243 #else
244  mjFREESTACK;
245 #endif
246 }
247 
248 void ExternalForce::callback(const mujoco_ros_utils::msg::ExternalForce::SharedPtr msg)
249 {
250  if(end_time_ > 0)
251  {
252  mju_warning("[ExternalForce] New message received while processing a previous message. Ignore the new message.");
253  return;
254  }
255  msg_ = std::make_shared<mujoco_ros_utils::msg::ExternalForce>(*msg);
256 }
257 
258 } // namespace MujocoRosUtils
Plugin to apply external force.
Definition: ExternalForce.h:18
std::shared_ptr< mujoco_ros_utils::msg::ExternalForce > msg_
External force message.
Definition: ExternalForce.h:88
static ExternalForce * Create(const mjModel *m, mjData *d, int plugin_id)
Create an instance.
void visualize(const mjModel *m, mjData *d, const mjvOption *opt, mjvScene *scn, int plugin_id)
Visualize.
rclcpp::Subscription< mujoco_ros_utils::msg::ExternalForce >::SharedPtr sub_
ROS publisher for external force.
Definition: ExternalForce.h:79
ExternalForce(ExternalForce &&)=default
Copy constructor.
mjtNum end_time_
End time to apply external force (-1 if no external force is applied)
Definition: ExternalForce.h:91
void reset(const mjModel *m, int plugin_id)
Reset.
std::string topic_name_
Topic name of external force.
Definition: ExternalForce.h:85
rclcpp::Node::SharedPtr nh_
ROS node handle.
Definition: ExternalForce.h:73
static void RegisterPlugin()
Register plugin.
rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_
ROS callback queue.
Definition: ExternalForce.h:76
mjtNum vis_scale_
Arrow length scale (negative value for no visualization)
Definition: ExternalForce.h:94
void callback(const mujoco_ros_utils::msg::ExternalForce::SharedPtr msg)
Constructor.
void compute(const mjModel *m, mjData *d, int plugin_id)
Compute.