18 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
28 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
29 #include <mvsim/mvsim-msgs/TimeStampedPose.pb.h>
33 using namespace mvsim;
39 if (anim_keyframes_path_ && !anim_keyframes_path_->empty())
41 auto& poseSeq = anim_keyframes_path_.value();
43 mrpt::math::TPose3D q;
45 const double tMax = mrpt::Clock::toDouble(poseSeq.rbegin()->first);
48 mrpt::Clock::fromDouble(std::fmod(context.simul_time, tMax)), q, interOk);
50 if (interOk) this->
setPose(initial_q_ + q);
53 if (!b2dBody_)
return;
56 const auto qq = simulable_parent_->applyWorldRenderOffset(q_);
57 b2dBody_->SetTransform(
b2Vec2(qq.x, qq.y), q_.yaw);
60 b2dBody_->SetLinearVelocity(
b2Vec2(dq_.vx, dq_.vy));
61 b2dBody_->SetAngularVelocity(dq_.omega);
68 std::unique_lock lck(q_mtx_);
73 const b2Vec2& pos = b2dBody_->GetPosition();
74 const float angle = b2dBody_->GetAngle();
75 const auto off = simulable_parent_->worldRenderOffset();
76 q_.x = pos(0) - off.
x;
77 q_.y = pos(1) - off.
y;
83 if (
auto* vo =
meAsVisualObject(); vo) vo->guiUpdate(std::nullopt, std::nullopt);
86 const b2Vec2& vel = b2dBody_->GetLinearVelocity();
87 const float w = b2dBody_->GetAngularVelocity();
93 ddq_lin_ = (q_.translation() - former_q_.translation()) * (1.0 / context.
dt);
97 isInCollision_ =
false;
98 if (
b2ContactEdge* cl = b2dBody_->GetContactList(); cl !=
nullptr)
100 for (
auto contact = cl->contact; contact !=
nullptr; contact = contact->GetNext())
103 const auto shA = cl->contact->GetFixtureA()->GetShape();
104 const auto shB = cl->contact->GetFixtureB()->GetShape();
106 if (cl->contact->GetFixtureA()->IsSensor())
continue;
107 if (cl->contact->GetFixtureB()->IsSensor())
continue;
112 di.
transformA = cl->contact->GetFixtureA()->GetBody()->GetTransform();
113 di.
transformB = cl->contact->GetFixtureB()->GetBody()->GetTransform();
121 if (dO.
distance < simulable_parent_->collisionThreshold() ||
122 cl->contact->IsTouching())
123 isInCollision_ =
true;
128 hadCollisionFlag_ = hadCollisionFlag_ || isInCollision_;
132 internalHandlePublish(context);
136 [[maybe_unused]]
const mrpt::math::TVector2D& force,
137 [[maybe_unused]]
const mrpt::math::TPoint2D& applyPoint)
143 std::shared_lock lck(q_mtx_);
145 mrpt::math::TTwist2D local_vel = dq_;
146 local_vel.rotate(-q_.yaw);
152 std::shared_lock lck(q_mtx_);
154 return {q_.x, q_.y, q_.yaw};
159 std::shared_lock lck(q_mtx_);
160 return mrpt::poses::CPose3D(q_);
165 std::shared_lock lck(q_mtx_);
166 return isInCollision_;
171 std::shared_lock lck(q_mtx_);
172 return hadCollisionFlag_;
177 std::unique_lock lck(q_mtx_);
178 hadCollisionFlag_ =
false;
186 using namespace std::string_literals;
191 std::optional<mrpt::math::TPose3D> initPose;
194 mrpt::math::TPose3D p;
199 "%lf %lf %lf", &p.x, &p.y, &p.yaw))
200 THROW_EXCEPTION_FMT(
"Error parsing <init_pose>%s</init_pose>", nPose->value());
201 p.yaw *= M_PI / 180.0;
207 mrpt::math::TPose3D p;
212 "%lf %lf %lf %lf %lf %lf ", &p.x, &p.y, &p.z, &p.yaw, &p.pitch, &p.roll))
213 THROW_EXCEPTION_FMT(
"Error parsing <init_pose3d>%s</init_pose3d>", nPose3->value());
214 p.yaw *= M_PI / 180.0;
215 p.pitch *= M_PI / 180.0;
216 p.roll *= M_PI / 180.0;
222 THROW_EXCEPTION(
"Missing required XML node <init_pose>x y phi</init_pose>");
227 initPose && xml_skip_elevation_adjust ==
nullptr)
232 auto queryPt = initPose->translation();
235 if (
auto meBlock =
dynamic_cast<mvsim::Block*
>(
this); meBlock)
237 queryPt.z += 0.5 * meBlock->block_z_max();
241 queryPt.z += 0.5 * meVeh->chassisZMax();
247 ASSERT_EQUAL_(queryPt.z, queryPt.z);
249 if (std::optional<float> elev = simulable_parent_->getHighestElevationUnder(queryPt); elev)
251 initPose->z = elev.value();
258 initial_q_ = *initPose;
266 mrpt::math::TTwist2D dq;
271 "%lf %lf %lf", &dq.vx, &dq.vy, &dq.omega))
272 THROW_EXCEPTION_FMT(
"Error parsing <init_vel>%s</init_vel>", nInitVel->value());
273 dq.omega *= M_PI / 180.0;
276 dq.rotate(this->
getPose().yaw);
283 if (
auto node = rootNode.
first_node(
"publish"); node)
286 params[
"publish_pose_topic"] =
TParamEntry(
"%s", &publishPoseTopic_);
287 params[
"publish_pose_period"] =
TParamEntry(
"%lf", &publishPosePeriod_);
289 params[
"publish_relative_pose_topic"] =
TParamEntry(
"%s", &publishRelativePoseTopic_);
290 std::string listObjects;
291 params[
"publish_relative_pose_objects"] =
TParamEntry(
"%s", &listObjects);
293 auto varValues = simulable_parent_->user_defined_variables();
294 varValues[
"NAME"] =
name_;
300 bool publishEnabled =
true;
302 auxPar[
"enabled"] =
TParamEntry(
"%bool", &publishEnabled);
306 if (!publishEnabled) publishPoseTopic_.clear();
309 if (!listObjects.empty())
311 mrpt::system::tokenize(
315 (publishRelativePoseOfOtherObjects_.empty() && publishRelativePoseTopic_.empty()) ||
316 (!publishRelativePoseOfOtherObjects_.empty() && !publishRelativePoseTopic_.empty()));
322 if (
auto nAnim = rootNode.
first_node(
"animation"); nAnim)
324 auto aType = nAnim->first_attribute(
"type");
325 ASSERTMSG_(aType,
"<animation> tag requires a type=\"...\" attribute");
326 const std::string sType = aType->value();
328 if (sType ==
"keyframes")
330 auto& poseSeq = anim_keyframes_path_.emplace();
331 poseSeq.setInterpolationMethod(mrpt::poses::imLinearSlerp);
333 for (
auto n = nAnim->first_node(); n; n = n->next_sibling())
335 if (strcmp(n->name(),
"time_pose") == 0)
337 mrpt::math::TPose3D p;
344 "%lf %lf %lf %lf", &t, &p.x, &p.y, &p.yaw))
345 THROW_EXCEPTION_FMT(
"Error parsing <time_pose>:\n%s", n->value());
346 p.yaw *= M_PI / 180.0;
348 poseSeq.insert(mrpt::Clock::fromDouble(t), p);
350 else if (strcmp(n->name(),
"time_pose3d") == 0)
352 mrpt::math::TPose3D p;
359 "%lf %lf %lf %lf %lf %lf %lf", &t, &p.x, &p.y, &p.z, &p.yaw, &p.pitch,
361 THROW_EXCEPTION_FMT(
"Error parsing <time_pose3d>:\n%s", n->value());
362 p.yaw *= M_PI / 180.0;
363 p.pitch *= M_PI / 180.0;
364 p.roll *= M_PI / 180.0;
366 poseSeq.insert(mrpt::Clock::fromDouble(t), p);
374 THROW_EXCEPTION_FMT(
"Invalid animation type='%s'", sType.c_str());
382 void Simulable::internalHandlePublish(
const TSimulContext& context)
384 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
385 std::shared_lock lck(q_mtx_);
389 if (publishPoseTopic_.empty() && publishRelativePoseTopic_.empty())
return;
393 const double tNow = mrpt::Clock::toDouble(mrpt::Clock::now());
394 if (tNow < publishPoseLastTime_ + publishPosePeriod_)
return;
396 publishPoseLastTime_ = tNow;
398 if (!publishPoseTopic_.empty())
400 mvsim_msgs::TimeStampedPose msg;
401 msg.set_unixtimestamp(tNow);
402 msg.set_objectid(
name_);
404 auto pose = msg.mutable_pose();
408 pose->set_yaw(q_.yaw);
409 pose->set_pitch(q_.pitch);
410 pose->set_roll(q_.roll);
412 client.publishTopic(publishPoseTopic_, msg);
415 if (!publishRelativePoseTopic_.empty())
417 mvsim_msgs::TimeStampedPose msg;
418 msg.set_unixtimestamp(tNow);
419 msg.set_relativetoobjectid(
name_);
425 for (
const auto& otherId : publishRelativePoseOfOtherObjects_)
427 if (
auto itObj = allObjects.find(otherId); itObj != allObjects.end())
429 msg.set_objectid(otherId);
431 const auto relPose = itObj->second->q_ - q_;
433 auto pose = msg.mutable_pose();
434 pose->set_x(relPose.x);
435 pose->set_y(relPose.y);
436 pose->set_z(relPose.z);
437 pose->set_yaw(relPose.yaw);
438 pose->set_pitch(relPose.pitch);
439 pose->set_roll(relPose.roll);
441 client.publishTopic(publishRelativePoseTopic_, msg);
445 std::cerr <<
"[WARNING] Trying to publish relative pose of '" << otherId
446 <<
"' wrt '" <<
name_
447 <<
"' but could not find any object in the world with "
462 #if defined(MVSIM_HAS_ZMQ) && defined(MVSIM_HAS_PROTOBUF)
464 if (!publishPoseTopic_.empty())
467 if (!publishRelativePoseTopic_.empty())
468 c.
advertiseTopic<mvsim_msgs::TimeStampedPose>(publishRelativePoseTopic_);
477 std::unique_lock lck(q_mtx_);
484 if (
auto* vo = me.
meAsVisualObject(); vo) vo->guiUpdate(std::nullopt, std::nullopt);
487 if (notifyChange)
const_cast<Simulable*
>(
this)->notifySimulableSetPose(p);
492 std::shared_lock lck(q_mtx_);
500 std::shared_lock lck(q_mtx_);
506 std::shared_lock lck(q_mtx_);
512 std::unique_lock lck(q_mtx_);
514 const_cast<mrpt::math::TTwist2D&
>(dq_) = dq;
518 mrpt::math::TTwist2D local_dq = dq.rotated(q_.yaw);
520 b2dBody_->SetLinearVelocity(
b2Vec2(local_dq.vx, local_dq.vy));
521 b2dBody_->SetAngularVelocity(dq.omega);