double ExploreFrontier::getOrientationChange(const Frontier& frontier, const tf::Stamped<tf::Pose>& robot_pose){ double robot_yaw = tf::getYaw(robot_pose.getRotation()); double robot_atan2 = atan2(robot_pose.getOrigin().y() + sin(robot_yaw), robot_pose.getOrigin().x() + cos(robot_yaw)); double frontier_atan2 = atan2(frontier.pose.position.x, frontier.pose.position.y); double orientation_change = robot_atan2 - frontier_atan2; ROS_DEBUG("Orientation change: %.3f", orientation_change * (180.0 / M_PI)); return orientation_change; }
/* * given the current state of the robot, find a good trajectory */ base_local_planner::Trajectory DWAPlanner::findBestPath( tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel, tf::Stamped<tf::Pose>& drive_velocities, std::vector<geometry_msgs::Point> footprint_spec) { obstacle_costs_.setFootprint(footprint_spec); //make sure that our configuration doesn't change mid-run boost::mutex::scoped_lock l(configuration_mutex_); Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation())); Eigen::Vector3f vel(global_vel.getOrigin().getX(), global_vel.getOrigin().getY(), tf::getYaw(global_vel.getRotation())); geometry_msgs::PoseStamped goal_pose = global_plan_.back(); Eigen::Vector3f goal(goal_pose.pose.position.x, goal_pose.pose.position.y, tf::getYaw(goal_pose.pose.orientation)); base_local_planner::LocalPlannerLimits limits = planner_util_->getCurrentLimits(); // prepare cost functions and generators for this run generator_.initialise(pos, vel, goal, &limits, vsamples_); result_traj_.cost_ = -7; // find best trajectory by sampling and scoring the samples scored_sampling_planner_.findBestTrajectory(result_traj_, NULL); // verbose publishing of point clouds if (publish_cost_grid_pc_) { //we'll publish the visualization of the costs to rviz before returning our best trajectory map_viz_.publishCostCloud(*(planner_util_->getCostmap())); } // debrief stateful scoring functions oscillation_costs_.updateOscillationFlags(pos, &result_traj_, planner_util_->getCurrentLimits().min_trans_vel); //if we don't have a legal trajectory, we'll just command zero if (result_traj_.cost_ < 0) { drive_velocities.setIdentity(); } else { tf::Vector3 start(result_traj_.xv_, result_traj_.yv_, 0); drive_velocities.setOrigin(start); tf::Matrix3x3 matrix; matrix.setRotation(tf::createQuaternionFromYaw(result_traj_.thetav_)); drive_velocities.setBasis(matrix); } return result_traj_; }
// compute nav fn (using wavefront assumption) void getNavFn(double* cost_map, tf::StampedTransform &robot_to_map_transform, double* nav_fn) { Point robot_pt(robot_to_map_transform.getOrigin().getX() / MAP_RESOLUTION,robot_to_map_transform.getOrigin().getY() / MAP_RESOLUTION); Point goal_pt(goal_pose.getOrigin().getX() / MAP_RESOLUTION, goal_pose.getOrigin().getY() / MAP_RESOLUTION); ROS_INFO("[getNavFn]\trobot_pt: (%d,%d), goal_pt(%d,%d)",robot_pt.x,robot_pt.y,goal_pt.x,goal_pt.y); // setup init map bool init_set_map[MAP_CELLS]; for (int i=0; i<MAP_CELLS;i++) { init_set_map[i] = false; } setVal(init_set_map,goal_pt.x,goal_pt.y,true); //updateMapDijkstra(nav_fn, init_set_map, goal_pt, cost_map, INT_MAX); LPN2(nav_fn, cost_map, goal_pt, robot_pt); }
void SlamGMapping::writeOdomMsgtoFile(tf::Stamped<tf::Transform>& odom_pose){ tf::Quaternion quat = odom_pose.getRotation(); fwrite(&quat,sizeof(tf::Quaternion),1,odomfile); fwrite(&odom_pose.getOrigin(),sizeof(tf::Vector3),1,odomfile); /* tfScalar x = odom_pose.getRotation().getX(); tfScalar y = odom_pose.getRotation().getY(); tfScalar z = odom_pose.getRotation().getZ(); tfScalar w = odom_pose.getRotation().getW(); fwrite(&x,sizeof(tfScalar),1,odomfile); fwrite(&y,sizeof(tfScalar),1,odomfile); fwrite(&z,sizeof(tfScalar),1,odomfile); fwrite(&w,sizeof(tfScalar),1,odomfile); x = odom_pose.getOrigin().getX(); y = odom_pose.getOrigin().getY(); z = odom_pose.getOrigin().getZ(); fwrite(&x,sizeof(tfScalar),1,odomfile); fwrite(&y,sizeof(tfScalar),1,odomfile); fwrite(&z,sizeof(tfScalar),1,odomfile);*/ }
bool AmclThread::get_odom_pose(tf::Stamped<tf::Pose>& odom_pose, double& x, double& y, double& yaw, const fawkes::Time* t, const std::string& f) { // Get the robot's pose tf::Stamped<tf::Pose> ident(tf::Transform(tf::Quaternion(0, 0, 0, 1), tf::Vector3(0, 0, 0)), t, f); try { tf_listener->transform_pose(odom_frame_id_, ident, odom_pose); } catch (Exception &e) { if (cfg_buffer_debug_) { logger->log_warn(name(), "Failed to compute odom pose (%s)", e.what_no_backtrace()); } return false; } x = odom_pose.getOrigin().x(); y = odom_pose.getOrigin().y(); double pitch, roll; odom_pose.getBasis().getEulerZYX(yaw, pitch, roll); //logger->log_info(name(), "Odom pose: (%f, %f, %f)", x, y, yaw); return true; }
void publishTransform(tf::Stamped<tf::Pose> _odom2map) { /* double x, y, th; x = odom2map.getOrigin()[0]; y = odom2map.getOrigin()[1]; th = tf::getYaw(odom2map.getRotation()); ROS_INFO("x = %f y = %f th = %f", (x), (y), (th)); * */ tf::Transform tfom = tf::Transform(tf::Quaternion(_odom2map.getRotation()), tf::Point(_odom2map.getOrigin())); tf::StampedTransform map_trans_stamped(tfom.inverse(), current_time, mapFrame, odomFrame); tf_broadcaster->sendTransform(map_trans_stamped); /* //first, we'll publish the transform over tf geometry_msgs::TransformStamped map_trans; mtx.lock(); map_trans.header.stamp = current_time; mtx.unlock(); map_trans.header.frame_id = mapFrame; map_trans.child_frame_id = odomFrame; map_trans.transform.translation.x = coords.x; map_trans.transform.translation.y = coords.y; map_trans.transform.translation.z = 0.0; geometry_msgs::Quaternion quat = tf::createQuaternionMsgFromYaw(coords.th); map_trans.transform.rotation = quat; //send the transform tf_broadcaster->sendTransform(map_trans); */ }
void EDWAPlanner::updatePlanAndLocalCosts( tf::Stamped<tf::Pose> global_pose, const std::vector<geometry_msgs::PoseStamped>& new_plan) { global_plan_.resize(new_plan.size()); for (unsigned int i = 0; i < new_plan.size(); ++i) { global_plan_[i] = new_plan[i]; } // costs for going away from path path_costs_.setTargetPoses(global_plan_); // costs for not going towards the local goal as much as possible goal_costs_.setTargetPoses(global_plan_); // alignment costs geometry_msgs::PoseStamped goal_pose = global_plan_.back(); Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation())); double sq_dist = (pos[0] - goal_pose.pose.position.x) * (pos[0] - goal_pose.pose.position.x) + (pos[1] - goal_pose.pose.position.y) * (pos[1] - goal_pose.pose.position.y); // we want the robot nose to be drawn to its final position // (before robot turns towards goal orientation), not the end of the // path for the robot center. Choosing the final position after // turning towards goal orientation causes instability when the // robot needs to make a 180 degree turn at the end std::vector<geometry_msgs::PoseStamped> front_global_plan = global_plan_; double angle_to_goal = atan2(goal_pose.pose.position.y - pos[1], goal_pose.pose.position.x - pos[0]); front_global_plan.back().pose.position.x = front_global_plan.back().pose.position.x + forward_point_distance_ * cos(angle_to_goal); front_global_plan.back().pose.position.y = front_global_plan.back().pose.position.y + forward_point_distance_ * sin(angle_to_goal); goal_front_costs_.setTargetPoses(front_global_plan); // keeping the nose on the path if (sq_dist > forward_point_distance_ * forward_point_distance_ * cheat_factor_) { double resolution = planner_util_->getCostmap()->getResolution(); alignment_costs_.setScale(resolution * pdist_scale_ * 0.5); // costs for robot being aligned with path (nose on path, not ju alignment_costs_.setTargetPoses(global_plan_); } else { // once we are close to goal, trying to keep the nose close to anything destabilizes behavior. alignment_costs_.setScale(0.0); } }
//given the current state of the robot, find a good trajectory base_local_planner::Trajectory DWAPlanner::findBestPath(tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel, tf::Stamped<tf::Pose>& drive_velocities){ //make sure that our configuration doesn't change mid-run boost::mutex::scoped_lock l(configuration_mutex_); //make sure to get an updated copy of the costmap before computing trajectories costmap_ros_->getCostmapCopy(costmap_); Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation())); Eigen::Vector3f vel(global_vel.getOrigin().getX(), global_vel.getOrigin().getY(), tf::getYaw(global_vel.getRotation())); //reset the map for new operations map_.resetPathDist(); front_map_.resetPathDist(); //make sure that we update our path based on the global plan and compute costs map_.setPathCells(costmap_, global_plan_); std::vector<geometry_msgs::PoseStamped> front_global_plan = global_plan_; front_global_plan.back().pose.position.x = front_global_plan.back().pose.position.x + forward_point_distance_ * cos(tf::getYaw(front_global_plan.back().pose.orientation)); front_global_plan.back().pose.position.y = front_global_plan.back().pose.position.y + forward_point_distance_ * sin(tf::getYaw(front_global_plan.back().pose.orientation)); front_map_.setPathCells(costmap_, front_global_plan); ROS_DEBUG_NAMED("dwa_local_planner", "Path/Goal distance computed"); //rollout trajectories and find the minimum cost one base_local_planner::Trajectory best = computeTrajectories(pos, vel); ROS_DEBUG_NAMED("dwa_local_planner", "Trajectories created"); //if we don't have a legal trajectory, we'll just command zero if(best.cost_ < 0){ drive_velocities.setIdentity(); } else{ tf::Vector3 start(best.xv_, best.yv_, 0); drive_velocities.setOrigin(start); tf::Matrix3x3 matrix; matrix.setRotation(tf::createQuaternionFromYaw(best.thetav_)); drive_velocities.setBasis(matrix); } //we'll publish the visualization of the costs to rviz before returning our best trajectory map_viz_.publishCostCloud(); return best; }
void prunePlan(const tf::Stamped<tf::Pose>& global_pose, std::vector<geometry_msgs::PoseStamped>& plan, std::vector<geometry_msgs::PoseStamped>& global_plan){ ROS_ASSERT(global_plan.size() >= plan.size()); std::vector<geometry_msgs::PoseStamped>::iterator it = plan.begin(); std::vector<geometry_msgs::PoseStamped>::iterator global_it = global_plan.begin(); while(it != plan.end()){ const geometry_msgs::PoseStamped& w = *it; // Fixed error bound of 2 meters for now. Can reduce to a portion of the map size or based on the resolution double x_diff = global_pose.getOrigin().x() - w.pose.position.x; double y_diff = global_pose.getOrigin().y() - w.pose.position.y; double distance_sq = x_diff * x_diff + y_diff * y_diff; if(distance_sq < 1){ ROS_DEBUG("Nearest waypoint to <%f, %f> is <%f, %f>\n", global_pose.getOrigin().x(), global_pose.getOrigin().y(), w.pose.position.x, w.pose.position.y); break; } it = plan.erase(it); global_it = global_plan.erase(global_it); } }
void SlamGMapping::writePoseStamped(tf::Stamped<tf::Pose> & pose_stamped){ //fwrite(&pose_stamped.frame_id_,sizeof(); tf::Quaternion quat = pose_stamped.getRotation(); fwrite(&quat,sizeof(tf::Quaternion),1,posestampedfile); fwrite(&pose_stamped.getOrigin(),sizeof(tf::Vector3),1,posestampedfile); }
void publishMap(double* map) { assn2::NavGrid ng; ng.width = (uint32_t) MAP_SIZE_X; ng.height = (uint32_t) MAP_SIZE_Y; ng.resolution = MAP_RESOLUTION; //convert the map to a vector std::vector<double> costs(ng.width*ng.height); for(uint32_t i = 0; i < ng.width*ng.height; i++) { costs[i] = map[i]; } ng.costs = costs; ng.goalX = goal_pose.getOrigin().getX(); ng.goalY = goal_pose.getOrigin().getY(); //publish map_pub.publish(ng); }
bool AmclNode::getOdomPose(tf::Stamped<tf::Pose>& odom_pose, double& x, double& y, double& yaw, const ros::Time& t, const std::string& f) { // Get the robot's pose tf::Stamped<tf::Pose> ident (tf::Transform(tf::createIdentityQuaternion(), tf::Vector3(0,0,0)), t, f); try { this->tf_->transformPose(odom_frame_id_, ident, odom_pose); } catch(tf::TransformException e) { ROS_WARN("Failed to compute odom pose, skipping scan (%s)", e.what()); return false; } x = odom_pose.getOrigin().x(); y = odom_pose.getOrigin().y(); double pitch,roll; odom_pose.getBasis().getEulerYPR(yaw, pitch, roll); return true; }
double getGoalPositionDistance(const tf::Stamped<tf::Pose>& global_pose, double goal_x, double goal_y) { return hypot(goal_x - global_pose.getOrigin().x(), goal_y - global_pose.getOrigin().y()); }
bool isGoalReached (const tf::TransformListener& tf, const std::vector<geometry_msgs::PoseStamped>& global_plan, const costmap_2d::Costmap2D& costmap __attribute__ ( (unused)), const std::string& global_frame, tf::Stamped<tf::Pose>& global_pose, const nav_msgs::Odometry& base_odom, double rot_stopped_vel, double trans_stopped_vel, double xy_goal_tolerance, double yaw_goal_tolerance) { //we assume the global goal is the last point in the global plan tf::Stamped<tf::Pose> goal_pose; getGoalPose (tf, global_plan, global_frame, goal_pose); double goal_x = goal_pose.getOrigin().getX(); double goal_y = goal_pose.getOrigin().getY(); double goal_th = tf::getYaw (goal_pose.getRotation()); //check to see if we've reached the goal position if (getGoalPositionDistance (global_pose, goal_x, goal_y) <= xy_goal_tolerance) { //check to see if the goal orientation has been reached if (fabs (getGoalOrientationAngleDifference (global_pose, goal_th)) <= yaw_goal_tolerance) { //make sure that we're actually stopped before returning success if (stopped (base_odom, rot_stopped_vel, trans_stopped_vel)) return true; } }
/* * given the current state of the robot, find a good trajectory */ base_local_planner::Trajectory EDWAPlanner::findBestPath( tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel, tf::Stamped<tf::Pose>& drive_velocities, std::vector<geometry_msgs::Point> footprint_spec) { obstacle_costs_.setFootprint(footprint_spec); //make sure that our configuration doesn't change mid-run boost::mutex::scoped_lock l(configuration_mutex_); Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation())); Eigen::Vector3f vel(global_vel.getOrigin().getX(), global_vel.getOrigin().getY(), tf::getYaw(global_vel.getRotation())); geometry_msgs::PoseStamped goal_pose = global_plan_.back(); Eigen::Vector3f goal(goal_pose.pose.position.x, goal_pose.pose.position.y, tf::getYaw(goal_pose.pose.orientation)); base_local_planner::LocalPlannerLimits limits = planner_util_->getCurrentLimits(); // prepare cost functions and generators for this run generator_.initialise(pos, vel, goal, &limits, vsamples_); energy_costs_.setLastSpeeds(global_vel.getOrigin().getX(), global_vel.getOrigin().getY(), tf::getYaw(global_vel.getRotation())); result_traj_.cost_ = -7; // find best trajectory by sampling and scoring the samples std::vector<base_local_planner::Trajectory> all_explored; scored_sampling_planner_.findBestTrajectory(result_traj_, &all_explored); if(publish_traj_pc_) { base_local_planner::MapGridCostPoint pt; traj_cloud_->points.clear(); traj_cloud_->width = 0; traj_cloud_->height = 0; std_msgs::Header header; pcl_conversions::fromPCL(traj_cloud_->header, header); header.stamp = ros::Time::now(); traj_cloud_->header = pcl_conversions::toPCL(header); for(std::vector<base_local_planner::Trajectory>::iterator t=all_explored.begin(); t != all_explored.end(); ++t) { if(t->cost_<0) continue; // Fill out the plan for(unsigned int i = 0; i < t->getPointsSize(); ++i) { double p_x, p_y, p_th; t->getPoint(i, p_x, p_y, p_th); pt.x=p_x; pt.y=p_y; pt.z=0; pt.path_cost=p_th; pt.total_cost=t->cost_; traj_cloud_->push_back(pt); } } traj_cloud_pub_.publish(*traj_cloud_); } // verbose publishing of point clouds if (publish_cost_grid_pc_) { //we'll publish the visualization of the costs to rviz before returning our best trajectory map_viz_.publishCostCloud(planner_util_->getCostmap()); } // debrief stateful scoring functions oscillation_costs_.updateOscillationFlags(pos, &result_traj_, planner_util_->getCurrentLimits().min_trans_vel); //if we don't have a legal trajectory, we'll just command zero if (result_traj_.cost_ < 0) { drive_velocities.setIdentity(); } else { tf::Vector3 start(result_traj_.xv_, result_traj_.yv_, 0); drive_velocities.setOrigin(start); tf::Matrix3x3 matrix; matrix.setRotation(tf::createQuaternionFromYaw(result_traj_.thetav_)); drive_velocities.setBasis(matrix); } return result_traj_; }
//given the current state of the robot, find a good trajectory Trajectory TrajectoryPlanner::findBestPath(tf::Stamped<tf::Pose> global_pose, tf::Stamped<tf::Pose> global_vel, tf::Stamped<tf::Pose>& drive_velocities){ Eigen::Vector3f pos(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), tf::getYaw(global_pose.getRotation())); Eigen::Vector3f vel(global_vel.getOrigin().getX(), global_vel.getOrigin().getY(), tf::getYaw(global_vel.getRotation())); //reset the map for new operations path_map_.resetPathDist(); goal_map_.resetPathDist(); //temporarily remove obstacles that are within the footprint of the robot std::vector<base_local_planner::Position2DInt> footprint_list = footprint_helper_.getFootprintCells( pos, footprint_spec_, costmap_, true); //mark cells within the initial footprint of the robot for (unsigned int i = 0; i < footprint_list.size(); ++i) { path_map_(footprint_list[i].x, footprint_list[i].y).within_robot = true; } //make sure that we update our path based on the global plan and compute costs path_map_.setTargetCells(costmap_, global_plan_); goal_map_.setLocalGoal(costmap_, global_plan_); ROS_DEBUG("Path/Goal distance computed"); //rollout trajectories and find the minimum cost one Trajectory best = createTrajectories(pos[0], pos[1], pos[2], vel[0], vel[1], vel[2], acc_lim_x_, acc_lim_y_, acc_lim_theta_); ROS_DEBUG("Trajectories created"); /* //If we want to print a ppm file to draw goal dist char buf[4096]; sprintf(buf, "base_local_planner.ppm"); FILE *fp = fopen(buf, "w"); if(fp){ fprintf(fp, "P3\n"); fprintf(fp, "%d %d\n", map_.size_x_, map_.size_y_); fprintf(fp, "255\n"); for(int j = map_.size_y_ - 1; j >= 0; --j){ for(unsigned int i = 0; i < map_.size_x_; ++i){ int g_dist = 255 - int(map_(i, j).goal_dist); int p_dist = 255 - int(map_(i, j).path_dist); if(g_dist < 0) g_dist = 0; if(p_dist < 0) p_dist = 0; fprintf(fp, "%d 0 %d ", g_dist, 0); } fprintf(fp, "\n"); } fclose(fp); } */ if(best.cost_ < 0){ drive_velocities.setIdentity(); } else{ tf::Vector3 start(best.xv_, best.yv_, 0); drive_velocities.setOrigin(start); tf::Matrix3x3 matrix; matrix.setRotation(tf::createQuaternionFromYaw(best.thetav_)); drive_velocities.setBasis(matrix); } return best; }
bool goalPositionReached(const tf::Stamped<tf::Pose>& global_pose, double goal_x, double goal_y, double xy_goal_tolerance) { double dist = distance(global_pose.getOrigin().x(), global_pose.getOrigin().y(), goal_x, goal_y); return fabs(dist) <= xy_goal_tolerance; }
bool ExploreFrontier::getExplorationGoals( tf::Stamped<tf::Pose> robot_pose, std::vector<geometry_msgs::Pose>& goals, double potential_scale, double orientation_scale, double gain_scale) { findFrontiers(); if (frontiers_.size() == 0) { ROS_DEBUG("no frontiers found"); return false; } geometry_msgs::Point start; start.x = robot_pose.getOrigin().x(); start.y = robot_pose.getOrigin().y(); start.z = robot_pose.getOrigin().z(); planner_->computePotential(start); //we'll make sure that we set goals for the frontier at least the circumscribed //radius away from unknown space // 2015: this may not be necessary // float step = -1.0 * costmap_resolution; // int c = ceil(costmap.getCircumscribedRadius() / costmap_resolution); // WeightedFrontier goal; std::vector<WeightedFrontier> weightedFrontiers; weightedFrontiers.reserve(frontiers_.size()); for (auto& frontier: frontiers_) { WeightedFrontier weightedFrontier; weightedFrontier.frontier = frontier; tf::Point p(frontier.pose.position.x, frontier.pose.position.y, frontier.pose.position.z); tf::Quaternion bt; tf::quaternionMsgToTF(frontier.pose.orientation, bt); tf::Vector3 v(cos(bt.getAngle()), sin(bt.getAngle()), 0.0); // for (int j=0; j <= c; j++) { // tf::Vector3 check_point = p + (v * (step * j)); // weightedFrontier.frontier.pose.position.x = check_point.x(); // weightedFrontier.frontier.pose.position.y = check_point.y(); // weightedFrontier.frontier.pose.position.z = check_point.z(); // weightedFrontier.cost = potential_scale * getFrontierCost(weightedFrontier.frontier) + orientation_scale * getOrientationChange(weightedFrontier.frontier, robot_pose) - gain_scale * getFrontierGain(weightedFrontier.frontier, costmapResolution_); // // weightedFrontier.cost = getFrontierCost(weightedFrontier.frontier) - getFrontierGain(weightedFrontier.frontier, costmapResolution_); // // ROS_DEBUG("cost: %f (%f * %f + %f * %f - %f * %f)", // // weightedFrontier.cost, // // potential_scale, // // getFrontierCost(weightedFrontier.frontier), // // orientation_scale, // // getOrientationChange(weightedFrontier.frontier, robot_pose), // // gain_scale, // // getFrontierGain(weightedFrontier.frontier, costmapResolution_) ); // weightedFrontiers.push_back(weightedFrontier); // } weightedFrontier.cost = potential_scale * getFrontierCost(weightedFrontier.frontier) + orientation_scale * getOrientationChange(weightedFrontier.frontier, robot_pose) - gain_scale * getFrontierGain(weightedFrontier.frontier); weightedFrontiers.push_back(std::move(weightedFrontier)); } goals.clear(); goals.reserve(weightedFrontiers.size()); std::sort(weightedFrontiers.begin(), weightedFrontiers.end()); for (uint i = 0; i < weightedFrontiers.size(); i++) { goals.push_back(weightedFrontiers[i].frontier.pose); } return (goals.size() > 0); }
void SlamGMapping::writeLaserPoseStamped(tf::Stamped<tf::Transform>& laser_pose){ tf::Quaternion quat = laser_pose.getRotation(); fwrite(&quat,sizeof(tf::Quaternion),1,laserposefile); fwrite(&laser_pose.getOrigin(),sizeof(tf::Vector3),1,laserposefile); }