00001
00002
00003
00004
00005 #include "ros/ros.h"
00006 #include <geometry_msgs/TransformStamped.h>
00007 #include <tf/transform_broadcaster.h>
00008 #include <fstream>
00009 #include <string>
00010 #include <time.h>
00011 #include <sstream>
00012 #include <iomanip>
00013 #include <boost/regex.hpp>
00014 #include <kdl/frames.hpp>
00015 #include <kdl_parser/kdl_parser.hpp>
00016
00017
00018 class URDF_Writer
00019 {
00020 public:
00021 ros::NodeHandle nh;
00022 ros::Subscriber sub;
00023 std::string parent_frame_id;
00024 std::string child_frame_id;
00025
00026 KDL::Tree kdl_tree;
00027
00028 std::string urdf_tree;
00029 std::string output_filename;
00030
00031 URDF_Writer()
00032 {
00033
00034 nh.getParam("robot_description", urdf_tree);
00035
00036 nh.getParam("urdf_output_filename", output_filename);
00037
00038 sub = nh.subscribe("camera_pose_static_transform_update", 10, &URDF_Writer::MyCallbackFunc, this);
00039
00040
00041
00042 if (!kdl_parser::treeFromString(urdf_tree, kdl_tree))
00043 {
00044 ROS_ERROR("Failed to construct kdl tree");
00045
00046 }
00047 }
00048
00049
00050
00051 void MyCallbackFunc(const geometry_msgs::TransformStamped::ConstPtr& msg)
00052 {
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 KDL::Rotation R = KDL::Rotation::Quaternion(msg->transform.rotation.x,
00071 msg->transform.rotation.y,
00072 msg->transform.rotation.z,
00073 msg->transform.rotation.w);
00074 parent_frame_id = msg->header.frame_id;
00075 child_frame_id = msg->child_frame_id;
00076
00077 double Roll, Pitch, Yaw;
00078 double px, py, pz;
00079
00080 px = msg->transform.translation.x;
00081 py = msg->transform.translation.y;
00082 pz = msg->transform.translation.z;
00083
00084 R.GetRPY(Roll, Pitch, Yaw);
00085
00086
00087
00088
00089
00090 std::string::const_iterator start, end;
00091
00092 std::string snippet_to_remove_a = "((^)|(^ +))<joint name=\"" + child_frame_id + "_joint\"" + ".*" + "</joint>\n";
00093 boost::regex re1a(snippet_to_remove_a.c_str());
00094 std::string snippet_to_remove_b = "((^)|(^ +))<link name=\"" + child_frame_id + ".*" + "/>\n";
00095 boost::regex re1b(snippet_to_remove_b.c_str());
00096 std::string snippet_to_remove_c = "((^)|(^ +))<!-- added after running camera_pose_calibration -->\n";
00097 boost::regex re1c(snippet_to_remove_c.c_str());
00098
00099 boost::match_results<std::string::const_iterator> match1;
00100 boost::match_flag_type flag1 = boost::match_default;
00101
00102 printf("\nRemoving out-dated description xml snippet that was previously added by urdf_writer (if found)...\n");
00103
00104 start = urdf_tree.begin();
00105 end = urdf_tree.end();
00106 if (regex_search(start, end, match1, re1a, flag1))
00107 {
00108 urdf_tree.erase(match1.position(), match1[0].second-match1[0].first);
00109
00110
00111
00112 printf("...\n");
00113 }
00114
00115 start = urdf_tree.begin();
00116 end = urdf_tree.end();
00117 if (regex_search(start, end, match1, re1b, flag1))
00118 {
00119 urdf_tree.erase(match1.position(), match1[0].second-match1[0].first);
00120
00121 printf("...\n");
00122 }
00123
00124 start = urdf_tree.begin();
00125 end = urdf_tree.end();
00126 if (regex_search(start, end, match1, re1c, flag1))
00127 {
00128 urdf_tree.erase(match1.position(), match1[0].second-match1[0].first);
00129
00130 printf("...\n");
00131 }
00132
00133
00134
00135
00136 printf("Adding the xml snippet for the new camera frame to the urdf file ...\n\n");
00137
00138
00139
00140
00141
00142
00143
00144
00145 start = urdf_tree.begin();
00146 end = urdf_tree.end();
00147
00148 boost::match_results<std::string::const_iterator> match2;
00149 boost::match_flag_type flags = boost::match_default;
00150
00151 int location = 0;
00152 boost::regex re2("</robot>");
00153 if(regex_search(start, end, match2, re2, flags))
00154 {
00155 location = match2.position();
00156
00157
00158 }
00159
00160
00161
00162
00163
00164
00165
00166 std::ostringstream buffer1, buffer2;
00167 buffer1 << Roll <<" " << Pitch <<" "<< Yaw;
00168 buffer2 << px << " " << py << " " << pz;
00169 std::string urdf_snippet =
00170 " <!-- added after running camera_pose_calibration -->\n"
00171 " <joint name=\""+ child_frame_id + "_joint\" type=\"fixed\">" + "\n" +
00172 " <origin rpy=\"" + buffer1.str() + "\" xyz=\"" + buffer2.str() + "\"/>" + "\n" +
00173 " <parent link=\"" + parent_frame_id + "\"/>" + "\n" +
00174 " <child link=\"" + child_frame_id + "\"/>" + "\n" +
00175 " </joint>" + "\n" +
00176 " <link name=\""+ child_frame_id + "\" type=\"camera\"/>" + "\n";
00177
00178 urdf_tree.insert(location, urdf_snippet);
00179
00180 std::ofstream wr(output_filename.c_str(), std::ios::trunc);
00181
00182 if (wr.is_open())
00183 {
00184 wr<<urdf_tree;
00185 printf("New urdf file generated.\n");
00186 printf("File path: %s\n\n", output_filename.c_str());
00187 }
00188 else
00189 {
00190 printf("Error opening file.\n\n");
00191 }
00192
00193 wr.close();
00194
00195
00196
00197
00198
00199
00200 std::string ss="\"" + parent_frame_id +"\"";
00201 std::string::const_iterator s1,e1;
00202 s1 = urdf_tree.begin();
00203 e1 = urdf_tree.end();
00204 boost::match_results<std::string::const_iterator> m;
00205 boost::match_flag_type f = boost::match_default;
00206
00207 ss = "<link name=" + ss ;
00208
00209 boost::regex pa(ss);
00210
00211 if(regex_search(s1, e1, m, pa, f))
00212 {
00213 printf("The parent link of [%s_joint] is verifed in the updated .urdf file (at %d)\n", child_frame_id.c_str(), int(m.position()));
00214 }
00215 else
00216 {
00217 ROS_WARN("The parent link of [%s_joint] seems missing in the updated .urdf file.\n You will receive an error if you do\n\n $ rosrun urdf check_urdf your_urdf.urdf\n\n",
00218 child_frame_id.c_str() );
00219 }
00220
00221
00222 }
00223
00224 };
00225
00226
00227
00228 int main(int argc, char **argv)
00229 {
00230 ros::init(argc, argv, "urdf_writer");
00231
00232 URDF_Writer my_urdf_writer;
00233
00234 ros::spin();
00235
00236
00237 return 0;
00238
00239 }