ros 问题:No transform from [base_link] to [bottom_link]

本文针对在使用ROS(机器人操作系统)过程中遇到的“Notransformfrom[base_link]to[bottom_link]”错误进行深入探讨。该问题通常发生在机器人定位与导航模块中,涉及TF(Transform)树的同步与配置。文章提供了详细的解决方案,包括检查TF发布者是否正常运行、确保所有节点正确启动以及可能的参数调整。对于ROS开发者和机器人技术爱好者而言,这是一份实用的故障排查指南。

ros 问题:No transform from [base_link] to [bottom_link]

 

sudo apt-get install unicode 

 

#include <ros/ros.h> #include <nav_msgs/OccupancyGrid.h> #include <sensor_msgs/Image.h> #include <sensor_msgs/RegionOfInterest.h> #include <sensor_msgs/LaserScan.h> #include <tf2/LinearMath/Quaternion.h> #include <tf2_ros/transform_broadcaster.h> #include <tf2_ros/transform_listener.h> #include <tf2_geometry_msgs/tf2_geometry_msgs.h> #include <tf2/LinearMath/Matrix3x3.h> #include <geometry_msgs/TransformStamped.h> #include <geometry_msgs/PoseWithCovarianceStamped.h> #include <cv_bridge/cv_bridge.h> #include <opencv2/opencv.hpp> #include <std_msgs/String.h> #include <std_srvs/Empty.h> #include <vector> #include <cmath> #include <tf2/LinearMath/Matrix3x3.h> #include <deque> #include <nav_msgs/Odometry.h> // 添加Odometry消息 nav_msgs::OccupancyGrid map_msg; cv::Mat map_cropped; cv::Mat map_temp; cv::Mat map_match; sensor_msgs::RegionOfInterest map_roi_info; std::vector<cv::Point2f> scan_points; std::vector<cv::Point2f> best_transform; ros::ServiceClient clear_costmaps_client; std::string base_frame; std::string odom_frame; std::string laser_frame; std::string laser_topic; float lidar_x = 250, lidar_y = 250, lidar_yaw = 0; float deg_to_rad = M_PI / 180.0; int cur_sum = 0; int clear_countdown = -1; int scan_count = 0; // 全局:保存上一次滤波后的状态 double s_x = 0.0, s_y = 0.0, s_yaw = 0.0; bool s_init = false; double alpha; // 在 main 里通过 param 读取 // 添加全局发布器 ros::Publisher robot_pose_pub; // 用于发布机器人位姿 // 初始姿态回调函数 void initialPoseCallback(const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg) { try { static tf2_ros::Buffer tfBuffer; static tf2_ros::TransformListener tfListener(tfBuffer); // 1. 查询从 base_frame 到 laser_frame 的转换 geometry_msgs::TransformStamped transformStamped = tfBuffer.lookupTransform(base_frame, laser_frame, ros::Time(0), ros::Duration(1.0)); // 2. 创建一个 stamped pose 用于转换 geometry_msgs::PoseStamped base_pose, laser_pose; base_pose.header = msg->header; base_pose.pose = msg->pose.pose; // 3. 将 base_frame 的位姿转换为 laser_frame 的位姿 tf2::doTransform(base_pose, laser_pose, transformStamped); // 4. 从转换后的消息中提取位置和方向信息 double x = msg->pose.pose.position.x; double y = msg->pose.pose.position.y; tf2::Quaternion q( laser_pose.pose.orientation.x, laser_pose.pose.orientation.y, laser_pose.pose.orientation.z, laser_pose.pose.orientation.w); // 5. 将四元数转换为yaw角度 tf2::Matrix3x3 m(q); double roll, pitch, yaw; m.getRPY(roll, pitch, yaw); // 6. 将地图坐标转换为裁切后的地图坐标 lidar_x = (x - map_msg.info.origin.position.x) / map_msg.info.resolution - map_roi_info.x_offset; lidar_y = (y - map_msg.info.origin.position.y) / map_msg.info.resolution - map_roi_info.y_offset; // 7. 设置yaw角度 lidar_yaw = -yaw; clear_countdown = 30; } catch (tf2::TransformException &ex) { ROS_WARN("无法获取从 %s 到 %s 的转换: %s", base_frame.c_str(), laser_frame.c_str(), ex.what()); } } void crop_map(); void processMap(); void mapCallback(const nav_msgs::OccupancyGrid::ConstPtr& msg) { map_msg = *msg; crop_map(); processMap(); } void crop_map() { // 显示地图信息 std_msgs::Header header = map_msg.header; nav_msgs::MapMetaData info = map_msg.info; //用来统计地图有效区域的变量 int xMax,xMin,yMax,yMin ; xMax=xMin= info.width/2; yMax=yMin= info.height/2; bool bFirstPoint = true; // 把地图数据转换成图片 cv::Mat map_raw(info.height, info.width, CV_8UC1, cv::Scalar(128)); // 灰色背景 for(int y = 0; y < info.height; y++) { for(int x = 0; x < info.width; x++) { int index = y * info.width + x; // 直接使用map_msg.data中的值 map_raw.at<uchar>(y, x) = static_cast<uchar>(map_msg.data[index]); // 统计有效区域 if(map_msg.data[index] == 100) { if(bFirstPoint) { xMax = xMin = x; yMax = yMin = y; bFirstPoint = false; continue; } xMin = std::min(xMin, x); xMax = std::max(xMax, x); yMin = std::min(yMin, y); yMax = std::max(yMax, y); } } } // 计算有效区域的中心点坐标 int cen_x = (xMin + xMax)/2; int cen_y = (yMin + yMax)/2; // 按照有效区域对地图进行裁剪 int new_half_width = abs(xMax - xMin)/2 + 50; int new_half_height = abs(yMax - yMin)/2 + 50; int new_origin_x = cen_x - new_half_width; int new_origin_y = cen_y - new_half_height; int new_width = new_half_width*2; int new_height = new_half_height*2; if(new_origin_x < 0) new_origin_x = 0; if((new_origin_x + new_width) > info.width) new_width = info.width - new_origin_x; if(new_origin_y < 0) new_origin_y = 0; if((new_origin_y + new_height) > info.height) new_height = info.height - new_origin_y; cv::Rect roi(new_origin_x, new_origin_y, new_width, new_height); cv::Mat roi_map = map_raw(roi).clone(); map_cropped = roi_map; // 地图的裁减信息 map_roi_info.x_offset = new_origin_x; map_roi_info.y_offset = new_origin_y; map_roi_info.width = new_width; map_roi_info.height = new_height; geometry_msgs::PoseWithCovarianceStamped init_pose; init_pose.pose.pose.position.x = 0.0; init_pose.pose.pose.position.y = 0.0; init_pose.pose.pose.position.y = 0.0; init_pose.pose.pose.orientation.x = 0.0; init_pose.pose.pose.orientation.y = 0.0; init_pose.pose.pose.orientation.z = 0.0; init_pose.pose.pose.orientation.w = 1.0; geometry_msgs::PoseWithCovarianceStamped::ConstPtr init_pose_ptr(new geometry_msgs::PoseWithCovarianceStamped(init_pose)); initialPoseCallback(init_pose_ptr); } bool check(float x, float y, float yaw); void scanCallback(const sensor_msgs::LaserScan::ConstPtr& msg) { scan_points.clear(); double angle = msg->angle_min; for (size_t i = 0; i < msg->ranges.size(); ++i) { if (msg->ranges[i] >= msg->range_min && msg->ranges[i] <= msg->range_max) { float x = msg->ranges[i] * cos(angle) / map_msg.info.resolution; float y = -msg->ranges[i] * sin(angle) / map_msg.info.resolution; scan_points.push_back(cv::Point2f(x, y)); } angle += msg->angle_increment; } if(scan_count == 0) scan_count ++; while (ros::ok()) { if (!map_cropped.empty()) { // 计算三种情况下的雷达点坐标数组 std::vector<cv::Point2f> transform_points, clockwise_points, counter_points; int max_sum = 0; float best_dx = 0, best_dy = 0, best_dyaw = 0; for (const auto& point : scan_points) { // 情况一:原始角度 float rotated_x = point.x * cos(lidar_yaw) - point.y * sin(lidar_yaw); float rotated_y = point.x * sin(lidar_yaw) + point.y * cos(lidar_yaw); transform_points.push_back(cv::Point2f(rotated_x + lidar_x, lidar_y - rotated_y)); // 情况二:顺时针旋转1度 float clockwise_yaw = lidar_yaw + deg_to_rad; rotated_x = point.x * cos(clockwise_yaw) - point.y * sin(clockwise_yaw); rotated_y = point.x * sin(clockwise_yaw) + point.y * cos(clockwise_yaw); clockwise_points.push_back(cv::Point2f(rotated_x + lidar_x, lidar_y - rotated_y)); // 情况三:逆时针旋转1度 float counter_yaw = lidar_yaw - deg_to_rad; rotated_x = point.x * cos(counter_yaw) - point.y * sin(counter_yaw); rotated_y = point.x * sin(counter_yaw) + point.y * cos(counter_yaw); counter_points.push_back(cv::Point2f(rotated_x + lidar_x, lidar_y - rotated_y)); } // 计算15种变换方式的匹配值 std::vector<cv::Point2f> offsets = {{0,0}, {1,0}, {-1,0}, {0,1}, {0,-1}}; std::vector<std::vector<cv::Point2f>> point_sets = {transform_points, clockwise_points, counter_points}; std::vector<float> yaw_offsets = {0, deg_to_rad, -deg_to_rad}; for (int i = 0; i < offsets.size(); ++i) { for (int j = 0; j < point_sets.size(); ++j) { int sum = 0; for (const auto& point : point_sets[j]) { float px = point.x + offsets[i].x; float py = point.y + offsets[i].y; if (px >= 0 && px < map_temp.cols && py >= 0 && py < map_temp.rows) { sum += map_temp.at<uchar>(py, px); } } if (sum > max_sum) { max_sum = sum; best_dx = offsets[i].x; best_dy = offsets[i].y; best_dyaw = yaw_offsets[j]; } } } // 更新雷达位置和角度 lidar_x += best_dx; lidar_y += best_dy; lidar_yaw += best_dyaw; // 判断匹配循环是否可以终止 if(check(lidar_x , lidar_y , lidar_yaw)) { break; } } } if(clear_countdown > -1) clear_countdown --; if(clear_countdown == 0) { std_srvs::Empty srv; clear_costmaps_client.call(srv); } } std::deque<std::tuple<float, float, float>> data_queue; const size_t max_size = 10; bool check(float x, float y, float yaw) { if(x == 0 && y == 0 && yaw == 0) { data_queue.clear(); return true; } // 添加新数据 data_queue.push_back(std::make_tuple(x, y, yaw)); // 如果队列超过最大大小,移除最旧的数据 if (data_queue.size() > max_size) { data_queue.pop_front(); } // 如果队列已满,检查第一个和最后一个元素 if (data_queue.size() == max_size) { auto& first = data_queue.front(); auto& last = data_queue.back(); float dx = std::abs(std::get<0>(last) - std::get<0>(first)); float dy = std::abs(std::get<1>(last) - std::get<1>(first)); float dyaw = std::abs(std::get<2>(last) - std::get<2>(first)); // 如果所有差值的绝对值都小于5,清空队列退出循环 if (dx < 5 && dy < 5 && dyaw < 5*deg_to_rad) { data_queue.clear(); return true; } } return false; } cv::Mat createGradientMask(int size) { cv::Mat mask(size, size, CV_8UC1); int center = size / 2; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { double distance = std::hypot(x - center, y - center); int value = cv::saturate_cast<uchar>(255 * std::max(0.0, 1.0 - distance / center)); mask.at<uchar>(y, x) = value; } } return mask; } void processMap() { if (map_cropped.empty()) return; map_temp = cv::Mat::zeros(map_cropped.size(), CV_8UC1); cv::Mat gradient_mask = createGradientMask(101); // 创建一个101x101的渐变掩模 for (int y = 0; y < map_cropped.rows; y++) { for (int x = 0; x < map_cropped.cols; x++) { if (map_cropped.at<uchar>(y, x) == 100) // 障碍物 { int left = std::max(0, x - 50); int top = std::max(0, y - 50); int right = std::min(map_cropped.cols - 1, x + 50); int bottom = std::min(map_cropped.rows - 1, y + 50); cv::Rect roi(left, top, right - left + 1, bottom - top + 1); cv::Mat region = map_temp(roi); int mask_left = 50 - (x - left); int mask_top = 50 - (y - top); cv::Rect mask_roi(mask_left, mask_top, roi.width, roi.height); cv::Mat mask = gradient_mask(mask_roi); cv::max(region, mask, region); } } } } void pose_tf() { if (scan_count == 0) return; if (map_cropped.empty() || map_msg.data.empty()) return; // 一阶低通滤波状态 static bool s_init = false; static double s_x = 0.0, s_y = 0.0, s_yaw = 0.0; static tf2_ros::Buffer tfBuffer; static tf2_ros::TransformListener tfListener(tfBuffer); // 1. 计算原始位姿 double raw_x = (lidar_x + map_roi_info.x_offset) * map_msg.info.resolution + map_msg.info.origin.position.x; double raw_y = (lidar_y + map_roi_info.y_offset) * map_msg.info.resolution + map_msg.info.origin.position.y; double raw_yaw = -lidar_yaw; // 2. 低通滤波 if (!s_init) { s_x = raw_x; s_y = raw_y; s_yaw = raw_yaw; s_init = true; } else { double dy = raw_yaw - s_yaw; while (dy > M_PI) dy -= 2.0 * M_PI; while (dy < -M_PI) dy += 2.0 * M_PI; s_x = alpha * raw_x + (1.0 - alpha) * s_x; s_y = alpha * raw_y + (1.0 - alpha) * s_y; s_yaw = s_yaw + alpha * dy; } // 3. 构造 map -> base_link 变换 tf2::Transform map_to_base; tf2::Quaternion q; // ← 把 q 提到此处,使后续都能访问 q.setRPY(0, 0, s_yaw); map_to_base.setOrigin(tf2::Vector3(s_x, s_y, 0.0)); map_to_base.setRotation(q); // 发布 map -> base_link geometry_msgs::TransformStamped map_to_base_msg; map_to_base_msg.header.stamp = ros::Time::now(); map_to_base_msg.header.frame_id = "map"; map_to_base_msg.child_frame_id = base_frame; map_to_base_msg.transform.translation.x = s_x; map_to_base_msg.transform.translation.y = s_y; map_to_base_msg.transform.translation.z = 0.0; map_to_base_msg.transform.rotation = tf2::toMsg(q); // 现在 q 可见 static tf2_ros::TransformBroadcaster br; br.sendTransform(map_to_base_msg); // 发布机器人里程计 nav_msgs::Odometry robot_odom; robot_odom.header.stamp = ros::Time::now(); robot_odom.header.frame_id = "map"; robot_odom.child_frame_id = base_frame; robot_odom.pose.pose.position.x = s_x; robot_odom.pose.pose.position.y = s_y; robot_odom.pose.pose.position.z = 0.0; robot_odom.pose.pose.orientation = tf2::toMsg(q); robot_pose_pub.publish(robot_odom); // 7. 查询 odom -> laser_frame geometry_msgs::TransformStamped odom_to_laser; try { odom_to_laser = tfBuffer.lookupTransform(odom_frame, laser_frame, ros::Time(0)); } catch (tf2::TransformException &ex) { ROS_WARN("%s", ex.what()); return; } // 8. 计算 map -> odom tf2::Transform odom_to_laser_tf2, map_to_laser; tf2::fromMsg(odom_to_laser.transform, odom_to_laser_tf2); // 注意此处用 s_y 而不是 x_y map_to_laser.setOrigin(tf2::Vector3(s_x, s_y, 0.0)); map_to_laser.setRotation(q); tf2::Transform map_to_odom = map_to_laser * odom_to_laser_tf2.inverse(); // 9. 发布 map -> odom geometry_msgs::TransformStamped map_to_odom_msg; map_to_odom_msg.header.stamp = ros::Time::now(); map_to_odom_msg.header.frame_id = "map"; map_to_odom_msg.child_frame_id = odom_frame; map_to_odom_msg.transform = tf2::toMsg(map_to_odom); br.sendTransform(map_to_odom_msg); } int main(int argc, char** argv) { setlocale(LC_ALL,""); ros::init(argc, argv, "lidar_loc"); // 读取参数 ros::NodeHandle private_nh("~"); private_nh.param<std::string>("base_frame", base_frame, "base_footprint"); private_nh.param<std::string>("odom_frame", odom_frame, "odom"); private_nh.param<std::string>("laser_frame", laser_frame, "scan"); private_nh.param<std::string>("laser_topic", laser_topic, "base_scan"); private_nh.param("filter_alpha", alpha, 0.1); ros::NodeHandle nh; ros::Duration(1).sleep(); // 初始化发布器 - 用于机器人位姿 robot_pose_pub = nh.advertise<nav_msgs::Odometry>("lidar_odom", 10); ros::Subscriber map_sub = nh.subscribe("map", 1, mapCallback); ros::Subscriber scan_sub = nh.subscribe(laser_topic, 1, scanCallback); ros::Subscriber initial_pose_sub = nh.subscribe("initialpose", 1, initialPoseCallback); clear_costmaps_client = nh.serviceClient<std_srvs::Empty>("move_base/clear_costmaps"); ros::Rate rate(30); // tf发送频率 while (ros::ok()) { pose_tf(); ros::spinOnce(); rate.sleep(); } return 0; }为什么我使用这个激光定位算法并且加入滤波后,机器人轨迹还是会有跳变或者起伏,请你帮我全面分析一下
最新发布
08-03
#include "PoseAdjust.h" namespace rei_ar_pose { ArPoseAdjust::ArPoseAdjust() : getTargetFlag_(false), trackFinished_(false), startFlag_(false), targetId_(-1), getMarkerFromTopic_(true), roll_(0.0), pitch_(0.0), yaw_(0.0) {} ArPoseAdjust::~ArPoseAdjust() { // SetFinishedFlag(true); // if (listenTfThread_.joinable()) listenTfThread_.join(); } int8_t ArPoseAdjust::Init(ros::NodeHandle& nh, bool getMarkerFromTopic, double targetRoll, double targetPitch, double targetYaw) { nh_ = nh; getMarkerFromTopic_ = getMarkerFromTopic; trackServer_ = nh_.advertiseService("ar_track", &ArPoseAdjust::TrackCb, this); relativeMoveClient_ = nh_.serviceClient<relative_move::SetRelativeMove>("relative_move"); tfBuffer_ = std::make_unique<tf2_ros::Buffer>(); tfListener_ = std::make_shared<tf2_ros::TransformListener>(*tfBuffer_); expectXErr_ = 0.01; expectYErr_ = 0.01; expectThetaErr_ = 0.01; roll_ = targetRoll; pitch_ = targetPitch; yaw_ = targetYaw; return 0; } // void ArPoseAdjust::SetXPid(int p, int i, int d) { // xPid_->setP(p); // xPid_->setI(i); // xPid_->setD(d); // } // void ArPoseAdjust::SetYPid(int p, int i, int d) { // yPid_->setP(p); // yPid_->setI(i); // yPid_->setD(d); // } // void ArPoseAdjust::SetThetaPid(int p, int i, int d) { // thetaPid_->setP(p); // thetaPid_->setI(i); // thetaPid_->setD(d); // } int8_t ArPoseAdjust::GetMarkerPoseFromTopic() { ar_track_alvar_msgs::AlvarMarkers::ConstPtr markersPtr = ros::topic::waitForMessage<ar_track_alvar_msgs::AlvarMarkers>( "bottom_camera/ar_pose_marker", ros::Duration(1.0)); if (markersPtr != NULL) { int idx = 0; for (auto marker : markersPtr->markers) { if (marker.id == targetId_) { geometry_msgs::Transform pose; pose.translation.x = marker.pose.pose.position.x; pose.translation.y = marker.pose.pose.position.y; pose.translation.z = marker.pose.pose.position.z; pose.rotation = marker.pose.pose.orientation; SetTfPose(pose); if (!GetTargetFlag()) { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = true; } break; } idx++; } if (idx == markersPtr->markers.size()) { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = false; return -1; } return 0; } return -1; } int8_t ArPoseAdjust::GetMarkerPoseFromTf(std::string frameId, std::string childFrameId) { geometry_msgs::TransformStamped transform; try { transform = tfBuffer_->lookupTransform(frameId, childFrameId, ros::Time(0), ros::Duration(1.0)); if (!GetTargetFlag()) { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = true; } SetTfPose(transform.transform); } catch (tf2::TransformException& ex) { ROS_WARN("%s", ex.what()); { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = false; } return -1; } return 0; } int8_t ArPoseAdjust::GetMarkerPose() { if (getMarkerFromTopic_) return GetMarkerPoseFromTopic(); else { std::string childFrameId = "ar_marker_" + std::to_string(targetId_); return GetMarkerPoseFromTf("base_link", childFrameId); } } void ArPoseAdjust::ListenTf(std::string frameId, std::string childFrameId) { geometry_msgs::TransformStamped transform; std::string errMsg; if (!tfBuffer_->canTransform(frameId, childFrameId, ros::Time(0), ros::Duration(2.0), &errMsg)) { ROS_ERROR("Unable to get pose from TF: %s", errMsg.c_str()); return; } { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = true; } ros::Rate rate(10.0); while (nh_.ok() && (!GetFinishedFlag())) { try { transform = tfBuffer_->lookupTransform(frameId, childFrameId, ros::Time(0)); SetTfPose(transform.transform); } catch (tf2::TransformException& ex) { ROS_WARN("%s", ex.what()); ros::Duration(0.1).sleep(); { std::unique_lock<std::mutex> lock(flagMutex_); getTargetFlag_ = false; } continue; } rate.sleep(); } } int8_t ArPoseAdjust::RelativeMove(double x, double y, double theta) { relative_move::SetRelativeMove cmd; cmd.request.global_frame = "odom"; cmd.request.goal.x = x; cmd.request.goal.y = y; cmd.request.goal.theta = theta; relativeMoveClient_.call(cmd); if (!cmd.response.success) { ROS_ERROR("RelativeMove error"); return -1; } return 0; } int8_t ArPoseAdjust::FindTarget(){ if (RelativeMove(0, 0, 0.25) < 0) { ROS_ERROR("RelativeMove error"); return -2; } sleep(1); if (GetMarkerPose() == 0) { ROS_DEBUG("Find"); return 0; } if (RelativeMove(0, 0, -0.5) < 0) { ROS_ERROR("RelativeMove error"); return -2; } sleep(1); if (GetMarkerPose() == 0) { ROS_DEBUG("Find"); return 0; } return -1; } // int8_t ArPoseAdjust::FindTarget(std::string frameId, std::string childFrameId) { // if (tfBuffer_->canTransform(frameId, childFrameId, ros::Time(0), // ros::Duration(2.0))) { // ROS_DEBUG("Find"); // return 0; // } // if (RelativeMove(0, 0, 0.35) < 0) { // ROS_ERROR("RelativeMove error"); // return -2; // } // if (tfBuffer_->canTransform(frameId, childFrameId, ros::Time(0), // ros::Duration(2.0))) { // ROS_DEBUG("Find"); // return 0; // } // if (RelativeMove(0, 0, -0.7) < 0) { // ROS_ERROR("RelativeMove error"); // return -2; // } // if (tfBuffer_->canTransform(frameId, childFrameId, ros::Time(0), // ros::Duration(2.0))) { // ROS_DEBUG("Find"); // return 0; // } // return -1; // } geometry_msgs::Twist ArPoseAdjust::GetTargetAheadPose( geometry_msgs::Transform& inTransform) { geometry_msgs::Transform baseToTargte = GetTfPose(); tf2::Transform baseToTargteTrans, targetToAheadTrans, baseToAheadTrans; tf2::fromMsg(baseToTargte, baseToTargteTrans); tf2::fromMsg(inTransform, targetToAheadTrans); baseToAheadTrans = baseToTargteTrans * targetToAheadTrans; geometry_msgs::Twist outPose; outPose.linear.x = baseToAheadTrans.getOrigin().x(); outPose.linear.y = baseToAheadTrans.getOrigin().y(); tf2::Matrix3x3 mat(baseToAheadTrans.getRotation()); double roll, pitch; mat.getRPY(roll, pitch, outPose.angular.z); ROS_INFO("OutPose: %lf, %lf,, %lf, %lf, %lf, %lf, %lf", baseToAheadTrans.getOrigin().x(), baseToAheadTrans.getOrigin().y(), baseToAheadTrans.getOrigin().z(), baseToAheadTrans.getRotation().x(), baseToAheadTrans.getRotation().y(), baseToAheadTrans.getRotation().z(), baseToAheadTrans.getRotation().w()); return outPose; } bool ArPoseAdjust::TrackCb(ar_pose::Track::Request& req, ar_pose::Track::Response& res) { geometry_msgs::Transform targetTrans; targetTrans.translation.z = req.goal_dist; // if (listenTfThread_.joinable()) { // res.message = "last move task still run"; // return false; // } trackFinished_ = false; getTargetFlag_ = false; targetId_ = req.ar_id; ros::Rate loop(2); int step = 1; geometry_msgs::Twist targetPose; // std::string childFrameId = "ar_marker_" + std::to_string(req.ar_id); // if (FindTarget("base_link", childFrameId) < 0) return true; // SetStartFlag(true); // listenTfThread_ = // std::thread(&ArPoseAdjust::ListenTf, this, "base_link", childFrameId); // double lastTime = ros::Time::now().toSec(); // while (ros::ok() && (!GetTargetFlag())) { // if ((ros::Time::now().toSec() - lastTime) > 2) return true; // loop.sleep(); // } // geometry_msgs::Twist velCmd; // xPid_->reset_integral(); // yPid_->reset_integral(); // thetaPid_->reset_integral(); tf2::Quaternion tmpQuat; tmpQuat.setRPY(roll_, pitch_, yaw_); while (nh_.ok()) { if (GetMarkerPose()<0) { step = 0; } else { targetTrans.rotation.x = tmpQuat.x(); targetTrans.rotation.y = tmpQuat.y(); targetTrans.rotation.z = tmpQuat.z(); targetTrans.rotation.w = tmpQuat.w(); targetPose = GetTargetAheadPose(targetTrans); } ROS_WARN("---------step:%d,err:%f",step,targetPose.angular.z); switch (step) { case 0: if (FindTarget() < 0) { res.message = "failed to find target"; return true; } step++; break; case 1: if ((fabs(targetPose.linear.x) > (2.0 * req.goal_dist)) || (fabs(targetPose.linear.y) > 0.1) || (fabs(targetPose.angular.z) > 0.1)) { if (RelativeMove(targetPose.linear.x, targetPose.linear.y, targetPose.angular.z) < 0) { res.message = "RelativeMove error"; return true; } } step++; break; case 2: if (fabs(targetPose.angular.z) > 0.05) step = 4; else if ((fabs(targetPose.linear.x) > 0.01) || (fabs(targetPose.linear.y) > 0.01)) step = 3; else step = 5; break; case 3: // velCmd.linear.x = xPid_->compute(0.0, targetPose.linear.x); // velCmd.linear.y = yPid_->compute(0.0, targetPose.linear.y); // velCmd.angular.z = 0.0; // velPub_.publish(velCmd); if (RelativeMove(targetPose.linear.x, targetPose.linear.y, 0) < 0) { res.message = "RelativeMove error"; return true; } step = 2; break; case 4: // velCmd.linear.x = 0; // velCmd.linear.y = 0; // velCmd.angular.z = thetaPid_->compute(0.0, targetPose.angular.z); // velPub_.publish(velCmd); if (RelativeMove(0, 0, targetPose.angular.z) < 0) { res.message = "RelativeMove error"; return true; } step = 2; break; case 5: res.success = true; SetFinishedFlag(true); // if (listenTfThread_.joinable()) listenTfThread_.join(); return true; break; } loop.sleep(); } return true; } } // namespace rei_ar_pose翻译该代码并解释其作用
06-29
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值