一起做ROS-DEMO系列(1):控制移动机器人自主导航并停到标签(AR Marker)之前

在观看某机器人的视频时,我们看到了这样一个场景:
在这里插入图片描述

1. 通过AR Tracker识别标签。

在这里插入图片描述
ar_track_alvar官方说明:http://wiki.ros.org/ar_track_alvar
主要步骤如下:

  • 安装ar-track-alvar功能包,$ sudo apt-get install ros-kinectic-ar-track-alvar
  • 配置launch启动文件:
<launch>
	<arg name="marker_size" default="5" />  <!--定义marker最外框的尺寸,注意单位是厘米-->
	<arg name="max_new_marker_error" default="0.01" /> 
	<arg name="max_track_error" default="0.2" />
	<arg name="cam_image_topic" default="/camera/color/image_raw" /> <!--修改为自己发布的图像话题-->
	<arg name="cam_info_topic" default="/camera/color/camera_info" /> <!--修改为自己发布的标定参数话题-->
	<arg name="output_frame" default="/camera_color_optical_frame" /> <!--修改为图片所在的坐标系,关系到后续的坐标系自动转换-->

	<node name="ar_track_alvar" pkg="ar_track_alvar" type="individualMarkersNoKinect" respawn="false" output="screen"
	 args="$(arg marker_size) $(arg max_new_marker_error) $(arg max_track_error) $(arg cam_image_topic) $(arg cam_info_topic) $(arg output_frame)" />
</launch>
  • 打印一张标签:可以通过此代码生成 rosrun ar_track_alvar createMarker
  • 补充下:标签的生成可以包含一些信息,相关帮助说明如下。
  • 在这里插入图片描述
  • 启动你的摄像头,启动标签检测节点,就可以看到有话题发布出来了,观察标签话题:rostopic echo /visualization_marker
  • 也可以在rviz中查看,将/visualization_marker话题可视化:
    +

2. 将标签的坐标转换到地图(Map)坐标系下,并加入偏移。

得益于ros中强大的TF树功能,我们只需要将机器人的模型配置好就可以使用其中的TF转换,自动将某个想要的坐标从一个坐标系转换到另一个坐标系下:

try{    //采用try-catch的方式可以防止一些意外的崩溃
    listener.transformPose("/map",target_odom_point_tmp,target_odom_point);//将视觉坐标系下的target_odom_point_tmp坐标点转换到/map坐标系
    getflagsuccess = 1;
  }
  catch(tf::TransformException &ex){
    // who care the fuck!
    ros::Duration(0.5).sleep();
    getflagsuccess = 0;
  }
  if(getflagsuccess)//成功转换判断
  {
    tf::Quaternion quat;
    double roll, pitch, yaw;//定义存储r\p\y的容器
    tf::quaternionMsgToTF(target_odom_point.pose.orientation, quat);
    tf::Matrix3x3(quat).getRPY(roll, pitch, yaw);//将四元数姿态表示转换到易于理解的RPY坐标系表示
    yaw +=1.5708;//旋转90
    target_odom_point.pose.position.x -=keep_distance*cos(yaw);//keep_distance表示移动的目标点距离标签的垂直距离,即将当前的x值进行一下偏移
    target_odom_point.pose.position.y -=keep_distance*sin(yaw);
     target_odom_point.pose.position.z = 0;
    target_odom_point.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);//将rpy表示转换为四元数表示
   
 
  odom_point_pub.publish(target_odom_point);//发布一个可视化的目标坐标点,用于debug

3.发送坐标,控制机器人自主导航至目标位置点。

调用 actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;动作服务器移动机器人,实现自主导航。

if(global_flag)//判断是否进行移动操作
  {
      global_flag = 0;
      goal.target_pose.header.frame_id = "map";
    goal.target_pose.header.stamp = ros::Time::now();
    goal.target_pose.pose.position = target_odom_point.pose.position;
    goal.target_pose.pose.orientation = target_odom_point.pose.orientation;//坐标赋值
    ROS_INFO("Sending goal");
     ac.sendGoal(goal);
     // 等待动作服务器完成
    ac.waitForResult();
    if (ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
    {
        ROS_INFO("You have reached the goal1!");
        std_msgs::Bool flag_pub_tmp;
        flag_pub_tmp.data = true;

        int pubcout1=0;
        while(pubcout1 < 100)//在到达指定位置后,发送100次下一段任务指令
        {
           flag_pub.publish(flag_pub_tmp);//发布下一步指令
          pubcout1++;
          ros::Duration(0.01).sleep();
        }
    }
    else
    ROS_INFO("The base move failed for some reason");
  }

4. 记录一下最终的代码:

  • 接收了两个话题/visualization_marke(标签坐标) /lets_move(开始移动flag)
  • 发布了两个话题/odom_target_point(根据标签计算出的最终移动目标点) /lets_move_finished(移动完成flag)
  • 调用了一个动作服务器MoveBaseClient,通过movebase包控制机器人自主导航(成熟的机器人ros产品都会配置好)。
/*
 * go_to_the_marker.cpp
 *
 *  Created on: May 8, 2019
 *      Author: Wxw
 */
#include <ros/ros.h>

#include <move_base_msgs/MoveBaseAction.h>
#include <actionlib/client/simple_action_client.h>
#include <visualization_msgs/Marker.h>
#include <tf/transform_listener.h>
#include <geometry_msgs/PoseStamped.h>
#include <std_msgs/Bool.h>
#include "tf/transform_datatypes.h"
#include <math.h>

const float PI = 3.14159
const float keep_distance = 1.2;//与目标物体沿其轴向方向的距离

typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>  MoveBaseClient;
move_base_msgs::MoveBaseGoal goal;
geometry_msgs::PoseStamped target_odom_point_tmp,target_odom_point;

bool global_flag = 0;//是否开始移动的flag
int cout = 0;//执行记数,即只执行一次移动,在置1后对后续的指示忽略掉


void marker_sub_CB(const visualization_msgs::Marker &marker_tmp)
{
target_odom_point_tmp.header=marker_tmp.header;
target_odom_point_tmp.pose.position=marker_tmp.pose.position;
target_odom_point_tmp.pose.orientation=marker_tmp.pose.orientation;
}
void flag_sub_CB(const std_msgs::Bool &flag_tmp)
{
  if(cout == 0)
  {
    global_flag = flag_tmp.data;
    cout = 1;
  }    
}
    
int main (int argc, char **argv)
{
    ros::init(argc, argv, "go_to_the_marker");
    ros::NodeHandle n;
    MoveBaseClient ac("move_base", true);
    tf::TransformListener listener;
    ros::Rate rate(10);
    ros::Subscriber marker_sub=n.subscribe("/visualization_marker",10,marker_sub_CB);
    ros::Subscriber flag_sub=n.subscribe("/lets_move",1,flag_sub_CB);

    ros::Publisher odom_point_pub = n.advertise<geometry_msgs::PoseStamped>("/odom_target_point",10);
    ros::Publisher flag_pub = n.advertise<std_msgs::Bool>("/lets_move_finished",1);

    // Wait 60 seconds for the action server to become available
    ROS_INFO("Waiting for the move_base action server");
    ac.waitForServer(ros::Duration(60));
    ROS_INFO("Connected to move base server");
    // Send a goal to move_base1
    //目标的属性设置
    bool getflagsuccess = 1;
    ros::Rate r(10);
    
while(ros::ok())
{
  ros::spinOnce();
  try{
    listener.transformPose("/map",target_odom_point_tmp,target_odom_point);
    getflagsuccess = 1;
  }
  catch(tf::TransformException &ex){
    // who care the fuck!
    ros::Duration(0.5).sleep();
    getflagsuccess = 0;
    std::cout<<getflagsuccess<<std::endl;
  }
  if(getflagsuccess)
  {
    tf::Quaternion quat;
    double roll, pitch, yaw;//定义存储r\p\y的容器
    target_odom_point.pose.orientation.x=0;
    target_odom_point.pose.orientation.y=0;

    tf::quaternionMsgToTF(target_odom_point.pose.orientation, quat);
    tf::Matrix3x3(quat).getRPY(roll, pitch, yaw);//进行转换
    yaw +=1.5708;//旋转90
    target_odom_point.pose.position.x -=keep_distance*cos(yaw);
    target_odom_point.pose.position.y -=keep_distance*sin(yaw);

    target_odom_point.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
    target_odom_point.pose.position.z = 0;
 
  odom_point_pub.publish(target_odom_point);//发布一个可视化的目标坐标点

  if(global_flag)//lets go!
  {
      global_flag = 0;
      goal.target_pose.header.frame_id = "map";
    goal.target_pose.header.stamp = ros::Time::now();
    goal.target_pose.pose.position = target_odom_point.pose.position;
    goal.target_pose.pose.orientation = target_odom_point.pose.orientation;
    ROS_INFO("Sending goal");
     ac.sendGoal(goal);
     // 等待自主导航完成
    ac.waitForResult();
    if (ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)
    {
        ROS_INFO("You have reached the goal1!");
        std_msgs::Bool flag_pub_tmp;
        flag_pub_tmp.data = true;

        int pubcout1=0;
        while(pubcout1<100)
        {
           flag_pub.publish(flag_pub_tmp);//发布下一步指令
          pubcout1++;
          ros::Duration(0.01).sleep();
        }
    }
    else
    ROS_INFO("The base failed for some reason");
  }

 
        
  r.sleep();
  }
      
}
    
  return 0;
}




  • 10
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
 介绍如何为机器人整合导航包,实现有效控制自主导航等功能 目录:  ROS 与 navigation 教程-目录  ROS 与 navigation 教程-设置机器人使用 TF  ROS 与 navigation 教程-基本导航调试指南  ROS 与 navigation 教程-安装和配置导航包  ROS 与 navigation 教程-结合 RVIZ 与导航包  ROS 与 navigation 教程-发布里程计消息  ROS 与 navigation 教程-发布传感器数据  ROS 与 navigation 教程-编写自定义全局路径规划  ROS 与 navigation 教程-stage 仿真  ROS 与 navigation 教程-示例-激光发布(C++)  ROS 与 navigation 教程-示例-里程发布(C++)  ROS 与 navigation 教程-示例-点云发布(C++)  ROS 与 navigation 教程-示例-机器人 TF 设置(C++)  ROS 与 navigation 教程-示例-导航目标设置(C++)  ROS 与 navigation 教程-turtlebot-整合导航包简明指南  ROS 与 navigation 教程-turtlebot-SLAM 地图构建  ROS 与 navigation 教程-turtlebot-现有地图的自主导航ROS 与 navigation 教程-map_server 介绍  ROS 与 navigation 教程-move_base 介绍  ROS 与 navigation 教程-move_base_msgs 介绍  ROS 与 navigation 教程-fake_localization 介绍  ROS 与 navigation 教程-voel_grid 介绍  ROS 与 navigation 教程-global_planner 介绍  ROS 与 navigation 教程-base_local_planner 介绍2  ROS 与 navigation 教程-carrot_planner 介绍  ROS 与 navigation 教程-teb_local_planner 介绍  ROS 与 navigation 教程-dwa_local_planner(DWA)介绍  ROS 与 navigation 教程-nav_core 介绍  ROS 与 navigation 教程-robot_pose_ekf 介绍  ROS 与 navigation 教程-amcl 介绍  ROS 与 navigation 教程-move_slow_and_clear 介绍  ROS 与 navigation 教程-clear_costmap_recovery 介绍  ROS 与 navigation 教程-rotate_recovery 介绍  ROS 与 navigation 教程-costmap_2d 介绍  ROS 与 navigation 教程-costmap_2d-range_sensor_layer 介绍  ROS 与 navigation 教程-costmap_2d-social_navigation_layers 介绍  ROS 与 navigation 教程-costmap_2d-staticmap 介绍  ROS 与 navigation 教程-costmap_2d-inflation 介绍  ROS 与 navigation 教程-obstacle 层介绍  ROS 与 navigation 教程-Configuring Layered Costmaps

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值