6 #include "../core/log.h" 7 #include "../core/transformer.h" 8 #include "../core/workspace.h" 9 #include "../render/mesh.h" 12 #include <moveit/robot_model/robot_model.h> 13 #include <moveit/robot_model_loader/robot_model_loader.h> 14 #include <moveit/robot_state/conversions.h> 15 #include <moveit/robot_state/robot_state.h> 17 #include <geometric_shapes/shape_operations.h> 19 #include <assimp/Importer.hpp> 20 #include <assimp/config.h> 21 #include <assimp/postprocess.h> 22 #include <assimp/scene.h> 24 #include <eigen_conversions/eigen_msg.h> 26 static std::shared_ptr<Mesh>
27 createShapeMesh(
const urdf::VisualSharedPtr &visual) {
28 auto geometry = visual->geometry;
29 switch (geometry->type) {
30 case urdf::Geometry::SPHERE: {
31 auto *sphere = (
const urdf::Sphere *)geometry.get();
32 return std::make_shared<Mesh>(Eigen::Scaling(
float(sphere->radius)) *
35 case urdf::Geometry::BOX: {
36 auto *box = (
const urdf::Box *)geometry.get();
37 return std::make_shared<Mesh>(
38 Eigen::Scaling(Eigen::Vector3f(box->dim.x * 0.5, box->dim.y * 0.5,
42 case urdf::Geometry::CYLINDER: {
43 auto *cylinder = (
const urdf::Cylinder *)geometry.get();
44 return std::make_shared<Mesh>(
45 Eigen::Scaling(Eigen::Vector3f(cylinder->radius, cylinder->radius,
46 cylinder->length * 0.5)) *
54 std::shared_ptr<Material> material = []() {
56 return std::make_shared<Material>();
58 Eigen::Isometry3d pose = Eigen::Isometry3d::Identity();
59 const moveit::core::LinkModel *moveit_link =
nullptr;
60 size_t link_index = 0;
61 size_t part_index = 0;
63 std::shared_ptr<Mesh> mesh;
64 RobotLink(
const moveit::core::LinkModel *moveit_link,
65 const Eigen::Isometry3d &pose,
const std::shared_ptr<Mesh> &mesh)
66 : moveit_link(moveit_link), link_index(moveit_link->getLinkIndex()),
67 pose(pose), mesh(mesh), frame(moveit_link->getName()) {}
71 moveit::core::RobotModelConstPtr moveit_robot;
72 std::vector<std::shared_ptr<RobotLink>> links;
75 robot_model_loader::RobotModelLoader moveit_loader(name,
false);
76 moveit_robot = moveit_loader.getModel();
78 LOG_ERROR(
"failed to load robot model " << name);
82 auto urdf_model = moveit_robot->getURDF();
83 for (
auto &urdf_link_pair : urdf_model->links_) {
84 auto urdf_link = urdf_link_pair.second;
85 if (
const moveit::core::LinkModel *moveit_link =
86 moveit_robot->getLinkModel(urdf_link->name)) {
87 for (
auto &urdf_visual : urdf_link->visual_array) {
88 if (urdf_visual->geometry) {
89 size_t part_index = 0;
90 auto rot = urdf_visual->origin.rotation;
91 auto pos = urdf_visual->origin.position;
92 Eigen::Isometry3d visual_pose =
93 Eigen::Isometry3d(Eigen::Translation3d(pos.x, pos.y, pos.z)) *
95 Eigen::Quaterniond(rot.w, rot.x, rot.y, rot.z));
96 if (
auto mesh = createShapeMesh(urdf_visual)) {
97 auto link =
new RobotLink(moveit_link, visual_pose, mesh);
98 if (
auto mat = urdf_visual->material) {
100 LOG_DEBUG(
"urdf material color " 101 << urdf_link->name <<
" " << mat->color.r <<
" " 102 << mat->color.g <<
" " << mat->color.b <<
" " 104 link->material->color().r() = mat->color.r;
105 link->material->color().g() = mat->color.g;
106 link->material->color().b() = mat->color.b;
107 link->material->color().a() = mat->color.a;
108 link->material->texture() = mat->texture_filename;
110 LOG_DEBUG(
"no material for " << urdf_link->name);
112 links.emplace_back(link);
113 }
else if (urdf_visual->geometry->type == urdf::Geometry::MESH) {
114 auto *urdf_mesh = (
const urdf::Mesh *)urdf_visual->geometry.get();
115 if (urdf_mesh->filename.empty()) {
116 LOG_ERROR(
"empty mesh file name")
121 loadResource(urdf_mesh->filename, data);
122 }
catch (std::exception &ex) {
123 LOG_ERROR(
"failed to read mesh file " << urdf_mesh->filename);
126 LOG_ERROR(
"failed to read mesh file " << urdf_mesh->filename);
128 std::string assimp_hint;
130 std::strrchr(urdf_mesh->filename.c_str(),
'.')) {
132 for (
auto &c : assimp_hint) {
135 if (std::strstr(assimp_hint.c_str(),
"stl")) {
141 aiProcessPreset_TargetRealtime_MaxQuality |
142 aiProcess_Triangulate;
143 Assimp::Importer ai_importer;
144 ai_importer.SetPropertyFloat(
145 AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 60.0);
146 if (import_options.recomputeNormals()) {
147 ai_importer.SetPropertyInteger(
148 AI_CONFIG_PP_RVC_FLAGS,
149 aiComponent_NORMALS |
150 aiComponent_TANGENTS_AND_BITANGENTS);
151 import_flags |= aiProcess_RemoveComponent;
161 auto *ai_scene = ai_importer.ReadFileFromMemory(
162 data.data(), data.size(), import_flags,
163 assimp_hint.c_str());
165 if (!import_options.recomputeNormals() &&
166 import_options.smoothNormals()) {
167 bool has_normapmaps =
false;
168 for (
size_t i = 0; i < ai_scene->mNumMaterials; i++) {
169 if (ai_scene->mMaterials[i]->GetTextureCount(
170 aiTextureType_NORMALS) > 0) {
171 has_normapmaps =
true;
174 if (!has_normapmaps) {
175 ai_importer.FreeScene();
176 ai_importer.SetPropertyInteger(
177 AI_CONFIG_PP_RVC_FLAGS,
178 aiComponent_NORMALS |
179 aiComponent_TANGENTS_AND_BITANGENTS);
184 import_flags |= aiProcess_RemoveComponent;
185 ai_scene = ai_importer.ReadFileFromMemory(
186 data.data(), data.size(), import_flags,
187 assimp_hint.c_str());
190 std::function<void(
const Eigen::Isometry3d &,
193 load = [&](
const Eigen::Isometry3d &parent_pose,
194 const aiNode *node) {
197 Eigen::Matrix4d pose_matrix = Eigen::Matrix4d::Identity();
198 for (
size_t row = 0; row < 4; row++) {
199 for (
size_t col = 0; col < 4; col++) {
200 pose_matrix(row, col) =
201 node->mTransformation[row][col];
206 Eigen::Isometry3d pose =
207 parent_pose * Eigen::Isometry3d(pose_matrix);
208 for (
size_t node_mesh_index = 0;
209 node_mesh_index < node->mNumMeshes;
212 ai_scene->mMeshes[node->mMeshes[node_mesh_index]];
214 for (
size_t i = 0; i < ai_mesh->mNumVertices; i++) {
215 mesh_data.positions.push_back(Eigen::Vector3f(
216 ai_mesh->mVertices[i].x, ai_mesh->mVertices[i].y,
217 ai_mesh->mVertices[i].z));
218 if (ai_mesh->mNormals) {
219 mesh_data.normals.push_back(Eigen::Vector3f(
220 ai_mesh->mNormals[i].x, ai_mesh->mNormals[i].y,
221 ai_mesh->mNormals[i].z));
223 if (ai_mesh->mTextureCoords[0]) {
224 mesh_data.texcoords.push_back(Eigen::Vector2f(
225 ai_mesh->mTextureCoords[0][i].x,
226 ai_mesh->mTextureCoords[0][i].y));
228 if (ai_mesh->mTangents) {
229 mesh_data.tangents.push_back(
230 Eigen::Vector3f(ai_mesh->mTangents[i].x,
231 ai_mesh->mTangents[i].y,
232 ai_mesh->mTangents[i].z));
234 if (ai_mesh->mBitangents) {
235 mesh_data.bitangents.push_back(
236 Eigen::Vector3f(ai_mesh->mBitangents[i].x,
237 ai_mesh->mBitangents[i].y,
238 ai_mesh->mBitangents[i].z));
241 for (
size_t i = 0; i < ai_mesh->mNumFaces; i++) {
242 if (ai_mesh->mFaces[i].mNumIndices == 3) {
243 for (
size_t j = 0; j < 3; j++) {
244 mesh_data.indices.push_back(
245 ai_mesh->mFaces[i].mIndices[j]);
247 }
else if (ai_mesh->mFaces[i].mNumIndices > 3) {
248 LOG_ERROR(
"invalid triangle " 249 << ai_mesh->mFaces[i].mNumIndices);
253 if (mesh_data.indices.empty() ||
254 mesh_data.positions.empty()) {
255 LOG_WARN(
"empty mesh " << urdf_mesh->filename <<
" " 256 << node->mName.C_Str());
260 auto link = std::shared_ptr<RobotLink>(
262 std::make_shared<Mesh>(mesh_data)));
265 ai_scene->mMaterials[ai_mesh->mMaterialIndex];
268 if (aiGetMaterialColor(ai_material,
269 AI_MATKEY_COLOR_DIFFUSE,
270 &color) == AI_SUCCESS) {
271 link->material->color().r() = color.r;
272 link->material->color().g() = color.g;
273 link->material->color().b() = color.b;
276 auto tex = [&](std::string &url, aiTextureType type) {
277 if (ai_material->GetTextureCount(type) > 0) {
279 ai_material->GetTexture(type, 0, &str);
281 if (
const char *new_end = std::strrchr(
282 urdf_mesh->filename.c_str(),
'/')) {
285 urdf_mesh->filename.c_str(),
286 new_end - urdf_mesh->filename.c_str()) +
293 tex(link->material->texture(), aiTextureType_DIFFUSE);
294 tex(link->material->normals(), aiTextureType_NORMALS);
295 link->part_index = ++part_index;
296 links.push_back(link);
299 for (
size_t i = 0; i < node->mNumChildren; i++) {
300 load(pose, node->mChildren[i]);
303 ai_scene->mRootNode->mTransformation = aiMatrix4x4();
305 Eigen::Isometry3d(Eigen::Scaling(Eigen::Vector3d(
306 urdf_mesh->scale.x, urdf_mesh->scale.y,
307 urdf_mesh->scale.z))),
308 ai_scene->mRootNode);
312 LOG_ERROR(
"failed to decode mesh " << urdf_mesh->filename);
317 LOG_ERROR(
" failed to create geometry for link " 323 LOG_ERROR(
"link not found " << urdf_link->name);
326 LOG_SUCCESS(
"robot model loaded");
331 std::unordered_set<std::string> variable_names;
332 std::vector<std::shared_ptr<MeshRenderer>> mesh_renderers;
333 std::shared_ptr<RobotModel> robot_model;
334 moveit::core::RobotState moveit_state;
335 RobotState(
const std::shared_ptr<RobotModel> &robot_model,
336 std::shared_ptr<MaterialOverride> material_override)
337 : robot_model(robot_model), moveit_state(robot_model->moveit_robot) {
338 moveit_state.setToDefaultValues();
341 for (
size_t i = 0; i < robot_model->links.size(); i++) {
342 mesh_renderers.push_back(create<MeshRenderer>(
343 robot_model->links.at(i)->mesh, robot_model->links.at(i)->material,
347 for (
auto &n : moveit_state.getVariableNames()) {
348 variable_names.insert(n);
354 MeshDisplayBase::renderSync(context);
355 bool invalidated = _invalidated.poll();
356 if (invalidated || _watcher.changed(description(), importOptions()) ||
357 !_robot_model_loader) {
358 static auto manager =
359 std::make_shared<ResourceManager<Loader<RobotModel>, std::string,
361 _robot_model_loader = manager->load(description(), importOptions());
363 _robot_model_loader->clear();
365 _robot_state =
nullptr;
366 GlobalEvents::instance()->redraw();
369 bool double_sided = doubleSided();
370 for (
auto &r : _robot_state->mesh_renderers) {
371 r->options().double_sided = double_sided;
377 MeshDisplayBase::renderAsync(context);
378 if (!_robot_state && _robot_model_loader) {
379 if (
auto robot_model = _robot_model_loader->load()) {
380 if (robot_model->moveit_robot) {
382 node()->create<
RobotState>(robot_model, _material_override);
383 GlobalEvents::instance()->redraw();
391 std::unordered_map<std::string, double> _positions, _temp;
392 void push(
const sensor_msgs::JointState &message) {
393 for (
size_t i = 0; i < message.name.size() && i < message.position.size();
395 _temp[message.name.at(i)] = message.position.at(i);
400 virtual void push(
const std::shared_ptr<const Message> &msg, int64_t start,
401 int64_t end)
override {
402 if (
auto message = msg->instantiate<sensor_msgs::JointState>()) {
405 if (
auto message = msg->instantiate<moveit_msgs::DisplayRobotState>()) {
406 push(message->state.joint_state);
409 virtual void commit()
override {
410 std::lock_guard<std::mutex> lock(_mutex);
414 std::lock_guard<std::mutex> lock(_mutex);
415 for (
auto &pair : _positions) {
416 if (robot_state.variable_names.find(pair.first) !=
417 robot_state.variable_names.end()) {
418 robot_state.moveit_state.setVariablePosition(pair.first, pair.second);
424 void RobotStateDisplayBase::refreshTopic(
const std::string &topic) {
425 if (!_subscriber || topic != _subscriber->topic()) {
426 _subscriber = std::make_shared<TimeSeriesSubscriber>(topic);
427 _subscriber->duration(0.5);
428 _listener = std::make_shared<RobotStateTimeSeriesListener>();
429 _subscriber->addListener(_listener);
434 if (_robot_state && _listener) {
435 _listener->apply(*_robot_state);
436 for (
size_t i = 0; i < _robot_state->robot_model->links.size(); i++) {
437 auto &link = _robot_state->robot_model->links[i];
438 _robot_state->mesh_renderers.at(i)->pose(
441 _robot_state->moveit_state
442 .getGlobalLinkTransform(
443 _robot_state->robot_model->moveit_robot->getLinkModel(
447 _robot_state->mesh_renderers.at(i)->show();
450 RobotDisplayBase::renderSync(context);
455 auto message = topic().message();
456 if (_robot_state && message) {
458 moveit::core::robotStateMsgToRobotState(message->state,
459 _robot_state->moveit_state);
460 }
catch (
const std::exception &ex) {
461 LOG_ERROR(ex.what());
463 for (
size_t i = 0; i < _robot_state->robot_model->links.size(); i++) {
464 auto &link = _robot_state->robot_model->links[i];
465 _robot_state->mesh_renderers.at(i)->pose(
468 _robot_state->moveit_state
469 .getGlobalLinkTransform(
470 _robot_state->robot_model->moveit_robot->getLinkModel(
474 _robot_state->mesh_renderers.at(i)->show();
477 RobotDisplayBase::renderSync(context);
481 RobotDisplayBase::renderAsync(context);
537 _display_trajectory_message = topic().message();
538 _max_steps = maxSteps();
539 _show_all = showAllStates();
540 if (_update_parameter_watcher.changed(showAllStates(), speed())) {
541 std::unique_lock<std::mutex> lock(_update_mutex);
542 _update_show_all = showAllStates();
543 _update_speed = speed();
544 _update_condition.notify_all();
546 RobotDisplayBase::renderSync(context);
550 std::shared_ptr<RobotModel> robot_model;
551 if (_robot_model_loader) {
552 robot_model = _robot_model_loader->load();
561 if (_trajectory_watcher.changed(_display_trajectory_message, _max_steps,
564 if (robot_model && _display_trajectory_message) {
566 if (robot_model->moveit_robot) {
616 std::map<ros::Duration, std::shared_ptr<RobotState>> states;
618 ros::Duration start_time = ros::Duration(0.0);
620 for (
auto &robot_trajectory :
621 _display_trajectory_message->trajectory) {
624 auto &joint_trajectory = robot_trajectory.joint_trajectory;
625 for (
size_t iframe = 0; iframe < joint_trajectory.points.size();
627 auto &point = joint_trajectory.points[iframe];
628 auto &robot_state = states[start_time + point.time_from_start];
630 robot_state = node()->create<
RobotState>(robot_model,
632 robot_state->moveit_state.setToDefaultValues();
634 moveit::core::robotStateMsgToRobotState(
635 _display_trajectory_message->trajectory_start,
636 robot_state->moveit_state);
637 }
catch (
const std::exception &ex) {
638 LOG_ERROR(ex.what());
641 for (
size_t ijoint = 0;
643 robot_trajectory.joint_trajectory.joint_names.size();
645 if (ijoint < point.positions.size()) {
646 if (robot_state->variable_names.find(
647 robot_trajectory.joint_trajectory
648 .joint_names[ijoint]) !=
649 robot_state->variable_names.end()) {
650 robot_state->moveit_state.setVariablePosition(
651 robot_trajectory.joint_trajectory.joint_names[ijoint],
652 point.positions[ijoint]);
660 auto &md_trajectory = robot_trajectory.multi_dof_joint_trajectory;
661 for (
size_t iframe = 0; iframe < md_trajectory.points.size();
663 for (
size_t ijoint = 0;
664 ijoint < md_trajectory.joint_names.size(); ijoint++) {
665 auto &joint_name = md_trajectory.joint_names[ijoint];
667 md_trajectory.points[iframe].transforms[ijoint];
670 md_trajectory.points[iframe].time_from_start];
673 robot_model, _material_override);
674 robot_state->moveit_state.setToDefaultValues();
676 moveit::core::robotStateMsgToRobotState(
677 _display_trajectory_message->trajectory_start,
678 robot_state->moveit_state);
679 }
catch (
const std::exception &ex) {
680 LOG_ERROR(ex.what());
683 if (
auto *joint_model =
684 robot_state->moveit_state.getJointModel(joint_name)) {
685 Eigen::Affine3d pose = Eigen::Affine3d::Identity();
686 tf::transformMsgToEigen(transform, pose);
687 robot_state->moveit_state.setJointPositions(joint_model,
695 ros::Duration duration = ros::Duration(0.0);
696 if (!robot_trajectory.joint_trajectory.points.empty()) {
698 duration, robot_trajectory.joint_trajectory.points.back()
701 if (!robot_trajectory.multi_dof_joint_trajectory.points.empty()) {
704 robot_trajectory.multi_dof_joint_trajectory.points.back()
707 start_time += duration;
713 for (
auto &pair : states) {
714 auto &robot_state = pair.second;
715 robot_state->moveit_state.update();
716 for (
size_t i = 0; i < robot_state->robot_model->links.size(); i++) {
717 auto &link = robot_state->robot_model->links[i];
718 robot_state->mesh_renderers.at(i)->pose(
720 Eigen::Isometry3d(robot_state->moveit_state
721 .getGlobalLinkTransform(
722 robot_state->robot_model->moveit_robot
723 ->getLinkModel(link->link_index))
728 _trajectory.emplace_back((pair.first - states.begin()->first).toSec(),
732 LOG_WARN(
"no robot model");
735 GlobalEvents::instance()->redraw();
737 std::unique_lock<std::mutex> lock(_update_mutex);
738 _update_times.clear();
739 for (ssize_t i = 0; i < _trajectory.size(); i++) {
740 _update_times.push_back(_trajectory[i].first -
741 _trajectory[std::max(ssize_t(0), i - 1)].first);
743 _update_condition.notify_all();
747 MeshDisplayBase::renderAsync(context);
749 if (!_trajectory.empty()) {
752 std::unique_lock<std::mutex> lock(_update_mutex);
755 j = (j % _trajectory.size());
756 for (
size_t i = 0; i < _trajectory.size(); i++) {
757 auto &pair = _trajectory[i];
758 bool vis = (_show_all || i == j);
759 for (
auto &renderer : pair.second->mesh_renderers) {
760 renderer->visible(vis);
766 RobotTrajectoryDisplay::RobotTrajectoryDisplay() {
767 _update_thread = std::thread([
this]() {
768 LOG_DEBUG(
"start robot trajectory update thread");
769 size_t current_frame_index = 0;
770 std::chrono::steady_clock::time_point last_tick =
771 std::chrono::steady_clock::now();
772 std::unique_lock<std::mutex> lock(_update_mutex);
777 if (_update_times.size() < 2 || _update_show_all || _update_speed == 0) {
778 _update_condition.wait(lock);
780 current_frame_index = (current_frame_index % _update_times.size());
781 double update_time = _update_times[current_frame_index];
783 (last_tick + std::chrono::duration<double>(
784 update_time / std::max(1e-12, _update_speed)));
785 if (std::chrono::steady_clock::now() >= timeout) {
786 current_frame_index++;
787 current_frame_index = (current_frame_index % _update_times.size());
788 _frame_update = current_frame_index;
789 last_tick = std::chrono::steady_clock::now();
790 GlobalEvents::instance()->redraw();
793 _update_condition.wait_until(lock, timeout);
797 LOG_DEBUG(
"exit robot trajectory update thread");
801 RobotTrajectoryDisplay::~RobotTrajectoryDisplay() {
803 std::unique_lock<std::mutex> lock(_update_mutex);
805 _update_condition.notify_all();
807 _update_thread.join();
812 context.pose.setIdentity();
813 _transformer =
LockScope()->document()->display()->transformer;
815 for (
size_t i = 0; i < _robot_state->robot_model->links.size(); i++) {
816 auto &link = _robot_state->robot_model->links.at(i);
817 if (
auto transform = link->frame.pose(_transformer)) {
818 _robot_state->mesh_renderers.at(i)->pose((*transform) * link->pose);
819 _robot_state->mesh_renderers.at(i)->show();
821 _robot_state->mesh_renderers.at(i)->hide();
825 RobotDisplayBase::renderSync(context);
829 RobotDisplayBase::renderAsync(context);