00001
00009 #include <opencv2/core/core.hpp>
00010 #include <aruco/aruco.h>
00011
00012 #include <ros/ros.h>
00013 #include <tf/transform_broadcaster.h>
00014 #include <visualization_msgs/Marker.h>
00015
00016 #define VISUAL_MARKER_SIZE 0.08
00017
00018 enum position_t
00019 {
00020 FIXED,
00021 RELATIVE,
00022 FLOATING,
00023
00024 POSITION_NR_ITEMS
00025 };
00026
00027 struct board_t
00028 {
00029 int uid;
00030 std::string name;
00031 position_t type;
00032
00033 std::string relativeName;
00034 tf::Transform transform;
00035 };
00036
00037 struct relative_board_t
00038 {
00039 board_t board;
00040 std::map<std::string, tf::Transform> transforms_map;
00041 };
00042
00043 struct camera_t
00044 {
00045 int uid;
00046 std::string name;
00047 position_t type;
00048
00049 tf::Transform transform;
00050 };
00051
00052 class ArSysViewer
00053 {
00054 private:
00055 std::string map_path;
00056 std::map<std::string, board_t> boards_map;
00057 std::map<std::string, relative_board_t> relativeBoards_map;
00058 std::map<std::string, camera_t> cameras_map;
00059 double digital_filter_change_rate;
00060
00061 ros::Subscriber transform_sub;
00062 ros::Publisher rviz_marker_pub;
00063 tf::TransformBroadcaster broadcaster;
00064 ros::NodeHandle nh;
00065
00066 public:
00067 ArSysViewer()
00068 : nh("~")
00069 {
00070 transform_sub = nh.subscribe ("/transform", 1, &ArSysViewer::transform_callback, this);
00071
00072 rviz_marker_pub = nh.advertise <visualization_msgs::Marker> ("visualization_marker", 0);
00073
00074 nh.param<std::string>("map_path", map_path, "map.yml");
00075 nh.param<double>("digital_filter_change_rate", digital_filter_change_rate, 0.5);
00076
00077 readFromFile(map_path.c_str());
00078 ROS_INFO("ArSys node started with boards map: %s", map_path.c_str());
00079 }
00080
00081 void readFromFile ( string sfile ) throw ( cv::Exception )
00082 {
00083 try
00084 {
00085 cv::FileStorage fs ( sfile,cv::FileStorage::READ );
00086 readFromFile ( fs );
00087 }
00088 catch (std::exception &ex)
00089 {
00090 throw cv::Exception ( 81818,"ArSysViewer::readFromFile",ex.what()+string(" file=)")+sfile ,__FILE__,__LINE__ );
00091 }
00092 }
00093
00094
00095 void readFromFile ( cv::FileStorage &fs ) throw ( cv::Exception )
00096 {
00097
00098 if (fs["ar_map_boards"].name() != "ar_map_boards" || fs["ar_map_cameras"].name() != "ar_map_cameras")
00099 throw cv::Exception ( 81818,"ArSysViewer::readFromFile","invalid file type" ,__FILE__,__LINE__ );
00100
00101 cv::FileNode FnBoards=fs["ar_map_boards"];
00102 for (cv::FileNodeIterator it = FnBoards.begin(); it != FnBoards.end(); ++it)
00103 {
00104 board_t board;
00105
00106 board.uid = boards_map.size();
00107 board.name = (std::string)(*it)["name"];
00108 if ((std::string)(*it)["type"] == "fixed")
00109 {
00110 board.type = FIXED;
00111
00112 }
00113 else if ((std::string)(*it)["type"] == "relative")
00114 {
00115 board.type = RELATIVE;
00116 board.relativeName = (std::string)(*it)["relativeName"];
00117 }
00118 else
00119 {
00120 if ((std::string)(*it)["type"] != "floating") ROS_WARN("Unknow board type: %s for board %s, assuming floating",
00121 ((std::string)(*it)["type"]).c_str(),
00122 board.name.c_str());
00123 board.type = FLOATING;
00124 board.transform = tf::Transform::getIdentity();
00125 }
00126 if (board.type == FIXED || board.type == RELATIVE)
00127 {
00128 vector<float> coordinates3d;
00129 cv::FileNode FnPose = (*it)["pose"];
00130 cv::FileNodeIterator itc = FnPose.begin();
00131
00132 (*itc)>>coordinates3d;
00133 if (coordinates3d.size() != 3)
00134 throw cv::Exception ( 81818,"ArSysViewer::readFromFile","invalid file type 3" ,__FILE__,__LINE__ );
00135 tf::Vector3 ref_origin(coordinates3d[0], coordinates3d[1], coordinates3d[2]);
00136
00137 (*++itc)>>coordinates3d;
00138 if (coordinates3d.size() != 3)
00139 throw cv::Exception ( 81818,"ArSysViewer::readFromFile","invalid file type 3" ,__FILE__,__LINE__ );
00140 tf::Quaternion ref_rotation = tf::createQuaternionFromRPY(coordinates3d[0], coordinates3d[1], coordinates3d[2]);
00141
00142 board.transform = tf::Transform(ref_rotation, ref_origin);
00143
00144 if (board.type == RELATIVE)
00145 {
00146 if (relativeBoards_map.count(board.relativeName) == 0)
00147 {
00148 relative_board_t relativeBoard;
00149
00150 relativeBoard.board.uid = relativeBoards_map.size();
00151 relativeBoard.board.name = board.relativeName;
00152 relativeBoard.board.type = FLOATING;
00153 relativeBoard.board.transform = tf::Transform::getIdentity();
00154
00155 relativeBoards_map.insert(std::make_pair(relativeBoard.board.name, relativeBoard));
00156 }
00157 relativeBoards_map[board.relativeName].transforms_map.insert(std::make_pair(board.name, board.transform));
00158 board.transform = tf::Transform::getIdentity();
00159 }
00160 }
00161
00162 boards_map.insert(std::make_pair(board.name, board));
00163 }
00164
00165 cv::FileNode FnCameras=fs["ar_map_cameras"];
00166 for (cv::FileNodeIterator it = FnCameras.begin(); it != FnCameras.end(); ++it)
00167 {
00168 camera_t camera;
00169
00170 camera.uid = cameras_map.size();
00171 camera.name = (std::string)(*it)["name"];
00172 if ((std::string)(*it)["type"] == "fixed")
00173 {
00174 camera.type = FIXED;
00175
00176 vector<float> coordinates3d;
00177 cv::FileNode FnPose = (*it)["pose"];
00178 cv::FileNodeIterator itc = FnPose.begin();
00179
00180 (*itc)>>coordinates3d;
00181 if (coordinates3d.size() != 3)
00182 throw cv::Exception ( 81818,"ArSysViewer::readFromFile","invalid file type 3" ,__FILE__,__LINE__ );
00183 tf::Vector3 ref_origin(coordinates3d[0], coordinates3d[1], coordinates3d[2]);
00184
00185 (*++itc)>>coordinates3d;
00186 if (coordinates3d.size() != 3)
00187 throw cv::Exception ( 81818,"ArSysViewer::readFromFile","invalid file type 3" ,__FILE__,__LINE__ );
00188 tf::Quaternion ref_rotation = tf::createQuaternionFromRPY(coordinates3d[0], coordinates3d[1], coordinates3d[2]);
00189
00190 camera.transform = tf::Transform(ref_rotation, ref_origin);
00191 }
00192 else
00193 {
00194 if ((std::string)(*it)["type"] != "floating") ROS_WARN("Unknow camera type: %s for camera %s, assuming floating",
00195 ((std::string)(*it)["type"]).c_str(),
00196 camera.name.c_str());
00197 camera.type = FLOATING;
00198 camera.transform = tf::Transform::getIdentity();
00199 }
00200
00201 cameras_map.insert(std::make_pair(camera.name, camera));
00202 }
00203 }
00204
00205 tf::Transform& digital_filter(tf::Transform &dst, const tf::Transform &src)
00206 {
00207
00208
00209 tf::Vector3 posOld = dst.getOrigin();
00210 tf::Vector3 posNew = src.getOrigin();
00211 tf::Vector3 pos
00212 (
00213 (1 - digital_filter_change_rate) * posOld.x() + digital_filter_change_rate * posNew.x(),
00214 (1 - digital_filter_change_rate) * posOld.y() + digital_filter_change_rate * posNew.y(),
00215 (1 - digital_filter_change_rate) * posOld.z() + digital_filter_change_rate * posNew.z()
00216 );
00217 dst.setOrigin(pos);
00218
00219 tf::Quaternion ornOld = dst.getRotation();
00220 tf::Quaternion ornNew = src.getRotation();
00221 tf::Quaternion orn
00222 (
00223 (1 - digital_filter_change_rate) * ornOld.x() + digital_filter_change_rate * ornNew.x(),
00224 (1 - digital_filter_change_rate) * ornOld.y() + digital_filter_change_rate * ornNew.y(),
00225 (1 - digital_filter_change_rate) * ornOld.z() + digital_filter_change_rate * ornNew.z(),
00226 (1 - digital_filter_change_rate) * ornOld.w() + digital_filter_change_rate * ornNew.w()
00227 );
00228 dst.setRotation(orn);
00229
00230 return dst;
00231 }
00232
00233 void transform_callback (const geometry_msgs::TransformStamped& transformMsg)
00234 {
00235 if (cameras_map.count(transformMsg.header.frame_id) == 0)
00236 {
00237 ROS_WARN("Map file does not contain an entry for the '%s' camera! Adding as floating", transformMsg.header.frame_id.c_str());
00238
00239 camera_t camera;
00240 camera.uid = cameras_map.size();
00241 camera.name = transformMsg.header.frame_id;
00242 camera.type = FLOATING;
00243 camera.transform = tf::Transform::getIdentity();
00244 cameras_map.insert(std::make_pair(camera.name, camera));
00245 }
00246 if (boards_map.count(transformMsg.child_frame_id) == 0)
00247 {
00248 ROS_WARN("Map file does not contain an entry for the '%s' board! Adding as floating", transformMsg.child_frame_id.c_str());
00249
00250 board_t board;
00251 board.uid = boards_map.size();
00252 board.name = transformMsg.child_frame_id;
00253 board.type = FLOATING;
00254 board.transform = tf::Transform::getIdentity();
00255 boards_map.insert(std::make_pair(board.name, board));
00256 }
00257
00258 tf::StampedTransform stampedTransform;
00259 tf::transformStampedMsgToTF(transformMsg, stampedTransform);
00260 if (cameras_map[transformMsg.header.frame_id].type == FLOATING && boards_map[transformMsg.child_frame_id].type == FIXED)
00261 {
00262 digital_filter(cameras_map[transformMsg.header.frame_id].transform, boards_map[transformMsg.child_frame_id].transform * stampedTransform.inverse());
00263 }
00264 tf::StampedTransform camStampedTransform (cameras_map[transformMsg.header.frame_id].transform, transformMsg.header.stamp, "world", transformMsg.header.frame_id);
00265 broadcaster.sendTransform(camStampedTransform);
00266
00267 stampedTransform.setData(boards_map[transformMsg.child_frame_id].type == FIXED ?
00268 boards_map[transformMsg.child_frame_id].transform :
00269 digital_filter(boards_map[transformMsg.child_frame_id].transform, cameras_map[transformMsg.header.frame_id].transform * stampedTransform));
00270 stampedTransform.frame_id_ = camStampedTransform.frame_id_;
00271 broadcaster.sendTransform(stampedTransform);
00272 if (boards_map[transformMsg.child_frame_id].type == RELATIVE)
00273 {
00274 std::string relativeName = boards_map[transformMsg.child_frame_id].relativeName;
00275
00276 digital_filter(relativeBoards_map[relativeName].board.transform, boards_map[transformMsg.child_frame_id].transform * relativeBoards_map[relativeName].transforms_map[transformMsg.child_frame_id]);
00277 tf::StampedTransform relativeStampedTransform(relativeBoards_map[relativeName].board.transform, transformMsg.header.stamp, "world", relativeName);
00278 broadcaster.sendTransform(relativeStampedTransform);
00279 }
00280
00281
00282 tf::Vector3 markerOrigin (0, 0, 0.1 * VISUAL_MARKER_SIZE);
00283 tf::Transform m (tf::Quaternion::getIdentity(), markerOrigin);
00284 tf::Transform markerPose = boards_map[transformMsg.child_frame_id].transform * m;
00285
00286 visualization_msgs::Marker visualMarker;
00287 tf::poseTFToMsg (markerPose, visualMarker.pose);
00288
00289 visualMarker.header.frame_id = stampedTransform.frame_id_;
00290 visualMarker.header.stamp = transformMsg.header.stamp;
00291 visualMarker.id = boards_map[transformMsg.child_frame_id].uid;
00292
00293 visualMarker.scale.x = 1.0 * VISUAL_MARKER_SIZE;
00294 visualMarker.scale.y = 1.0 * VISUAL_MARKER_SIZE;
00295 visualMarker.scale.z = 0.1 * VISUAL_MARKER_SIZE;
00296 visualMarker.ns = "basic_shapes";
00297 visualMarker.type = visualization_msgs::Marker::CUBE;
00298 visualMarker.action = visualization_msgs::Marker::ADD;
00299 visualMarker.color.r = (float)visualMarker.id / (boards_map.size() - 1);
00300 visualMarker.color.g = 1.0 - visualMarker.color.r;
00301 visualMarker.color.b = (float)boards_map[transformMsg.child_frame_id].type / (POSITION_NR_ITEMS - 1);
00302 visualMarker.color.a = 1.0;
00303 visualMarker.lifetime = ros::Duration (1.0);
00304
00305 rviz_marker_pub.publish(visualMarker);
00306 }
00307 };
00308
00309
00310 int main(int argc,char **argv)
00311 {
00312 ros::init(argc, argv, "ar_system_viewer");
00313
00314 ArSysViewer node;
00315
00316 ros::spin();
00317 }