ROS小车研究笔记3/11/2023:多点导航及其源码实现

这篇具有很好参考价值的文章主要介绍了ROS小车研究笔记3/11/2023:多点导航及其源码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

多点导航操作

打开导航launch文件

roslaunch turn_on_wheeltec_robot navigation.launch
rviz

在rviz里,选择publish point在地图上点击标记目标点。在标记多个目标点后小车会按标记顺序依次在各个目标点中往返

多点导航对于话题MarkerArray。需要在rviz中使markerArray订阅小车发布的path_point话题
ROS小车研究笔记3/11/2023:多点导航及其源码实现

多点导航源码分析

在导航节点 turn_on_wheeltec_robot navigation.launch文件中,启动了如下节点用于多点导航

 <!-- MarkerArray功能节点> -->
 <node name='send_mark' pkg="turn_on_wheeltec_robot" type="send_mark.py">
 </node>

找到turn_on_wheeltec_robot下的send_mark.py。该节点即为多点导航控制节点

1 主方法

def send_mark():
    global markerArray, markerArray_number, count, index, try_again, mark_pub, goal_pub
    markerArray = MarkerArray() #目标点标记数组
    markerArray_number = MarkerArray() #目标点标记数组
    count = 0
    index = 0
    try_again = 1
    sendflagPublisher = rospy.Publisher('/send_flag', Int8, queue_size =1)
    rospy.init_node('path_point_demo') #初始化节点
    mark_pub    = rospy.Publisher('/path_point', MarkerArray, queue_size = 100) #用于发布目标点标记
    navGoal_sub = rospy.Subscriber('/send_mark_goal', PoseStamped, navGoal_callback) #订阅rviz内标记按下的位置
    click_sub   = rospy.Subscriber('/clicked_point', PointStamped, click_callback) #订阅rviz内标记按下的位置
    goal_pub    = rospy.Publisher('/move_base_simple/goal', PoseStamped, queue_size = 1) #用于发布目标点
    send_flag=Int8()
    send_flag.data=1
    sendflagPublisher.publish(send_flag)
    rospy.sleep(1.)
    sendflagPublisher.publish(send_flag)
    rospy.loginfo('a=%d',send_flag.data)
    print("11111111111111111111111111")
    goal_status_sub = rospy.Subscriber('/move_base/result', MoveBaseActionResult, pose_callback) #用于订阅是否到达目标点状态


    while not rospy.is_shutdown():
        key = getKey() #获取键值
        if(key=='c'): #键值为c是清空目标点
            count = 0
            index = 0
            try_again = 1

            markerArray = MarkerArray() 
            marker = Marker()
            marker.header.frame_id = 'map' 
            marker.type = marker.TEXT_VIEW_FACING 
            marker.action = marker.DELETEALL 
            marker.text = '' 
            markerArray.markers.append(marker) 

            for m in markerArray_number.markers:    
                m.action = marker.DELETEALL

            mark_pub.publish(markerArray) 
            mark_pub.publish(markerArray_number) 
            markerArray = MarkerArray() 
            markerArray_number = MarkerArray() 

        elif (key == '\x03'): #ctrl+c退出
            break
def breakkey():
    fd = sys.stdin.fileno()
    new_settings = termios.tcgetattr(fd)
    new_settings[3]=new_settings[3] | termios.ECHO
    termios.tcsetattr(fd, termios.TCSADRAIN, new_settings)

if __name__ == '__main__':
    settings = termios.tcgetattr(sys.stdin) #获取键值初始化
    rospy.on_shutdown(breakkey)#退出前执行键值初始化
    send_mark()

对于创建的变量,markerArray是一个数组用于保存所有目标的。count为目标点总数,index为下一个要前往的目标点,try_again为在前往目标点失败后,在重新选择前往下一个目标点前尝试前往该目标点的次数。

后面定义了几个发布者和订阅者

mark_pub = rospy.Publisher(‘/path_point’, MarkerArray, queue_size = 100) #用于发布目标点标记
navGoal_sub = rospy.Subscriber(‘/send_mark_goal’, PoseStamped, navGoal_callback) #订阅rviz内标记按下的位置
click_sub = rospy.Subscriber(‘/clicked_point’, PointStamped, click_callback) #订阅rviz内标记按下的位置
goal_pub = rospy.Publisher(‘/move_base_simple/goal’, PoseStamped, queue_size = 1) #用于发布目标点
send_flag=Int8()

这里我们得到rviz里发布的clicked_point和send_mark_goal代表得到的目标点。并发布小车的目标点

click_sub的回调函数click_callback

#rviz内标记按下的回调函数,输入参数:按下的位置[x, y, z=0]
def click_callback(msg):           
    global index, count

    print('Add a new target point '+str(count)+':')
    print('x:'+str(msg.point.x)+
        ', y:'+str(msg.point.y)+
        ', z:0'+', w:1') 

    marker = Marker()      #创建marker对象
    marker.header.frame_id = 'map' #以哪一个TF坐标为原点
    marker.type = marker.ARROW #一直面向屏幕的字符格式
    marker.action = marker.ADD #添加marker
    marker.scale.x = 0.2 #marker大小
    marker.scale.y = 0.05 #marker大小
    marker.scale.z = 0.05 #marker大小,对于字符只有z起作用
    marker.color.a = 1 #字符透明度
    marker.color.r = 1 #字符颜色R(红色)通道
    marker.color.g = 0 #字符颜色G(绿色)通道
    marker.color.b = 0 #字符颜色B(蓝色)通道
    marker.pose.position.x = msg.point.x #字符位置
    marker.pose.position.y = msg.point.y #字符位置
    marker.pose.orientation.z = 0 #字符位置
    marker.pose.orientation.w = 1 #字符位置
    markerArray.markers.append(marker) #添加元素进数组

    marker_number = Marker()      #创建marker对象
    marker_number.header.frame_id = 'map' #以哪一个TF坐标为原点
    marker_number.type = marker_number.TEXT_VIEW_FACING #一直面向屏幕的字符格式
    marker_number.action = marker_number.ADD #添加marker
    marker_number.scale.x = 0.5 #marker大小
    marker_number.scale.y = 0.5 #marker大小
    marker_number.scale.z = 0.5 #marker大小,对于字符只有z起作用
    marker_number.color.a = 1 #字符透明度
    marker_number.color.r = 1 #字符颜色R(红色)通道
    marker_number.color.g = 0 #字符颜色G(绿色)通道
    marker_number.color.b = 0 #字符颜色B(蓝色)通道
    marker_number.pose.position.x = msg.point.x #字符位置
    marker_number.pose.position.y = msg.point.y #字符位置
    marker_number.pose.position.z = 0.1 #字符位置
    marker_number.pose.orientation.z = 0 #字符位置
    marker_number.pose.orientation.w = 1 #字符位置
    marker_number.text = str(count) #字符内容
    markerArray_number.markers.append(marker_number) #添加元素进数组

    #markers的id不能一样,否则rviz只会识别最后一个元素
    id = 0
    for m in markerArray.markers:    #遍历marker分别给id赋值
        m.id = id
        id += 1

    for m in markerArray_number.markers:    #遍历marker分别给id赋值
        m.id = id
        id += 1
    
    mark_pub.publish(markerArray) #发布markerArray,rviz订阅并进行可视化
    mark_pub.publish(markerArray_number) #发布markerArray,rviz订阅并进行可视化

    #第一次添加marker时直接发布目标点
    if count == 0:
        pose = PoseStamped() #创建目标点对象
        pose.header.frame_id = 'map' #以哪一个TF坐标为原点
        pose.header.stamp = rospy.Time.now()
        pose.pose.position.x = msg.point.x #目标点位置
        pose.pose.position.y = msg.point.y #目标点位置
        pose.pose.orientation.z = 0 #四元数,到达目标点后小车的方向,z=sin(angle/2)
        pose.pose.orientation.w = 1 #四元数,到达目标点后小车的方向,w=cos(angle/2)
        goal_pub.publish(pose)
        index += 1 #下一次要发布的目标点序号

    count += 1 #有几个目标点

click_callback实现了如下功能
1 在终端打出得到的目标点位置和编号

2 创建Marker对象(rviz上的标记点),并设置标记面向屏幕,大小,透明度,颜色,位置,方向

3 设置marker的id为标记的顺序值。默认情况下marker id都为0,这会导致当有多个id相同的marker时rviz只显示最后一个

4 发布markerArray,由rviz订阅以进行可视化

5 在第一次添加marker时会发布目标点消息,类型为PoseStamped。在之后会让count加一

疑点:这里我们创建了marker和marker_number,并对这两个对象进行了完全一样的操作,设置这一个完全相同的marker_number的目的是什么

navGoal_sub的回调函数pose_callback

#到达目标点成功或失败的回调函数,输入参数:[3:成功, 其它:失败](4:ABORTED)
def pose_callback(msg):
    global try_again, index, try_again, index
    if msg.status.status == 3 and count>0 :  #成功到达任意目标点,前往下一目标点
        try_again = 1 #允许再次尝试前往尚未抵达的该目标点
       
        #count表示当前目标点计数,index表示已完成的目标点计数
        if index == count:                   #当index等于count时,表示所有目标点完成,重新开始巡航
            print ('Reach the target point '+str(index-1)+':')
            print('x:'+str(markerArray.markers[index-1].pose.position.x)+
                ', y:'+str(markerArray.markers[index-1].pose.position.y)+
                ', z:'+str(markerArray.markers[index-1].pose.orientation.z)+
                ', w:'+str(markerArray.markers[index-1].pose.orientation.w))   

            if count > 1:
                print('Complete instructions!') #只有一个目标点不算巡航
                index = 0
            pose = PoseStamped()
            pose.header.frame_id = 'map'
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index].pose.position.x
            pose.pose.position.y = markerArray.markers[index].pose.position.y
            pose.pose.orientation.z = markerArray.markers[index].pose.orientation.z
            pose.pose.orientation.w = markerArray.markers[index].pose.orientation.w
            goal_pub.publish(pose)
            index += 1 #下一次要发布的目标点序号

        elif index < count:                   #当index小于count时,表示还未完成所有目标点,目标巡航未完成
            print ('Reach the target point '+str(index-1)+':')    
            print('x:'+str(markerArray.markers[index-1].pose.position.x)+
                ', y:'+str(markerArray.markers[index-1].pose.position.y)+
                ', z:'+str(markerArray.markers[index-1].pose.orientation.z)+
                ', w:'+str(markerArray.markers[index-1].pose.orientation.w)) 

            pose = PoseStamped()
            pose.header.frame_id = 'map'
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index].pose.position.x
            pose.pose.position.y = markerArray.markers[index].pose.position.y
            pose.pose.orientation.z = markerArray.markers[index].pose.orientation.z
            pose.pose.orientation.w = markerArray.markers[index].pose.orientation.w
            goal_pub.publish(pose)
            index += 1 #下一次要发布的目标点序号
        
    elif count > 0: #未抵达设定的目标点    
        rospy.logwarn('Can not reach the target point '+str(index-1)+':'+'\r\n'+
                      'x:'+str(markerArray.markers[index-1].pose.position.x)+
                    ', y:'+str(markerArray.markers[index-1].pose.position.y)+
                    ', z:'+str(markerArray.markers[index-1].pose.orientation.z)+
                    ', w:'+str(markerArray.markers[index-1].pose.orientation.w)) 

        #如果未尝试过前往尚未抵达的目标点,则尝试前往尚未抵达的目标点
        if try_again == 1:
            rospy.logwarn('trying reach the target point '+str(index-1)+' again!'+'\r\n'+
                          'x:'+str(markerArray.markers[index-1].pose.position.x)+
                        ', y:'+str(markerArray.markers[index-1].pose.position.y)+
                        ', z:'+str(markerArray.markers[index-1].pose.orientation.z)+
                        ', w:'+str(markerArray.markers[index-1].pose.orientation.w)) 

            pose = PoseStamped()
            pose.header.frame_id = 'map'
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index - 1].pose.position.x           
            pose.pose.position.y = markerArray.markers[index - 1].pose.position.y
            pose.pose.orientation.z = markerArray.markers[index-1].pose.orientation.z
            pose.pose.orientation.w = markerArray.markers[index-1].pose.orientation.w
            goal_pub.publish(pose)
            try_again = 0 #不允许再次尝试前往尚未抵达的该目标点

        #如果已经尝试过前往尚未抵达的目标点,则前往下一个目标点
        elif index < len(markerArray.markers):      #若还未完成目标点
            rospy.logwarn('try reach the target point '+str(index-1)+' failed! reach next point:'+'\r\n'+
                          'x:'+str(markerArray.markers[index-1].pose.position.x)+
                        ', y:'+str(markerArray.markers[index-1].pose.position.y)+
                        ', z:'+str(markerArray.markers[index-1].pose.orientation.z)+
                        ', w:'+str(markerArray.markers[index-1].pose.orientation.w)) 

            if index==count: index=0 #如果下一个目标点序号为count,说明当前目标点为最后一个目标点,下一个目标点序号应该设置为0
            pose = PoseStamped()
            pose.header.frame_id = 'map'
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index].pose.position.x      
            pose.pose.position.y = markerArray.markers[index].pose.position.y
            pose.pose.orientation.z = markerArray.markers[index].pose.orientation.z
            pose.pose.orientation.w = markerArray.markers[index].pose.orientation.w
            goal_pub.publish(pose)
            index += 1 #下一次要发布的目标点序号
            try_again = 1 #允许再次尝试前往尚未抵达的该目标点

函数内部执行的操作均为封装PoseStamped话题并通过goal_pub发布给小车运动控制节点进行执行。这里我们主要看该函数的导航逻辑

1

if msg.status.status == 3 and count>0 : #成功到达任意目标点,前往下一目标点

在我们受到的参数msg中,status为3代表成功到达目标点,4(或者任何其他值)代表失败。判断count > 0是为了确定小车处于多点导航模式。如果count为0代表小车只是执行了一次自主导航,而没有开启多点导航,故不执行后面程序

2

if index == count: #当index等于count时,表示所有目标点完成,重新开始巡航
print (‘Reach the target point ‘+str(index-1)+’:’)

index代表下一个目标点,count代表目标点总数。因此当两者相等时代表本轮巡航彻底完成,开始新一轮巡航。

这时我们将index重设为0,并发布话题让小车回到0点

3

elif index < count: #当index小于count时,表示还未完成所有目标点,目标巡航未完成

index小于count时代表还没有完成所有目标点,此时发布话题指挥小车前往下一个目标点并使index + 1。这里注意区分index - 1代表了当前小车所在目标点,而index 代表小车要去的下一个目标点

4

elif count > 0: #未抵达设定的目标点

此时代表小车处于多点导航状态,但是没有收到成功信息3,代表小车没有成功到达目标点。这时如果try_again为1,代表小车有一次再次尝试机会,控制小车再次前往目标点(前往当前目标点index - 1)。如果尝试后依然失败,则让小车前往下一个目标点(index)文章来源地址https://www.toymoban.com/news/detail-436122.html

到了这里,关于ROS小车研究笔记3/11/2023:多点导航及其源码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 树莓派+ROS+Arduino造一台导航小车(完整代码+硬件调试)

    目录 1、小车平台架构 1.1 实验概述 1.2 预期目标 2、硬件平台简介 2.1 执行机构 2.1.1 底盘结构 2.1.2 减速电机 2.2 下位驱动系统简介 2.2.1 驱动控制单元Arduino 2.2.2 电机驱动单元 L298P 2.3 上位控制系统简介 2.3.1 树莓派 2.3.2 摄像头型号 2.3.3 激光雷达型号 3、驱动系统开发 3.1 ardu

    2024年02月06日
    浏览(29)
  • ROS仿真机器人学习笔记二:创建4轮小车模型及相关xraco文件修改

    提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 跟着上一节博主的教程,可以把

    2024年02月07日
    浏览(24)
  • 基于旭日派的Ros系统小车的再开发——使用python脚本调用MIPI相机(学习笔记)

        这里我们导入了 cv2 、 time 、 ipywidgets 和 Mipi_Camera 这几个库。其中, cv2 是用于图像处理和计算机视觉的库; time 是用于计时和休眠的库; ipywidgets 是用于创建交互式窗口小部件的库; Mipi_Camera 则是用于控制和采集MIPI接口相机图像的库。当然除此之外,我们在代码中还添

    2024年01月21日
    浏览(35)
  • ROS自学笔记二十五:导航中目标点与路径规划消息

    在ROS导航中,目标点与路径规划消息通常使用 geometry_msgs/PoseStamped来描述目标点的位置以及使用 nav_msgs/Path 来描述规划路径。以下是这两个消息类型的详细介绍和示例: `geometry_msgs/PoseStamped` 用于表示一个带有时间戳的目标点位置,通常用于发送机器人需要前往的目标点。 以

    2024年02月06日
    浏览(32)
  • ROS学习笔记08、机器人导航仿真(slam、map_server、amcl、move_base与导航消息介绍)

    马上开学,目前学校很多实验室都是人工智能这块,大部分都是和机器人相关,然后软件这块就是和cv、ros相关,就打算开始学习一下。 本章节是虚拟机安装Ubuntu18.04以及安装ROS的环境。 学习教程:【Autolabor初级教程】ROS机器人入门,博客中一些知识点是来源于赵老师的笔记

    2023年04月12日
    浏览(33)
  • 【2023】Windows11安装Linux子系统(Ubuntu22.04LTS)+安装ROS

    目录 一、准备工作 二、安装Ubuntu 22.04.1 LTS 1. 下载Ubuntu 22.04.1 LTS 2. 移动到非系统盘 三、启动Ubuntu遇到的报错及解决方案 四、换源 五、安装ROS 1. 设置编码 2. 添加源 3. 安装ROS 4. 设置环境变量 5. 测试 控制面板——程序——程序和功能——启动或关闭 Windows 功能   开启如图所

    2024年02月10日
    浏览(59)
  • 微信小程序开发学习笔记——2.11navigator页面链接导航

    跟着b站up主“咸虾米_”学习微信小程序开发中,把学习记录存到这方便后续查找。 课程连接: https://www.bilibili.com/video/BV19G4y1K74d?p=14 https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html 属性之一          navigate可以记录上一个缓存页,点击左上角返回按钮可以跳转回

    2024年02月22日
    浏览(38)
  • 前端笔记(11) Vue3 Router 编程式导航 router.push router.replace

    在上篇博客Vue3 Router 监听路由参数变化中,我们使用 router-link 创建 a 标签来定义导航链接: 除了 router-link ,我们还可以借助 router 的实例方法,通过编写代码来实现: router.push 方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。

    2024年02月07日
    浏览(47)
  • 小车导航不能移动问题汇总

    rviz上: 问题1: Timed out waiting for transform from base_link to map to become available before running costmap, tf error: canTransform: target_frame map does not exist.. canTransform returned after 258.542 timeout was 0.1. 解决方法: 问题2 :global_costmap: Parameter \\\"plugins\\\" not provided, loading pre-Hydro parameters 问题3 :local_costm

    2024年02月10日
    浏览(60)
  • ROS寻迹小车

    1.自行导入某车型的mesh文件到URDF/Xacro模型(碰撞检测边框长度小数点位数保留三位:最后两位是学号最后两位),四轮驱动; 2.搭建一个具有城市或者越野行驶路面,不少于3处障碍的行驶环境; 3.给无人车装配摄像头、Kinect、激光雷达等传感器。 4.通过键盘控制无人车,采

    2024年02月06日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包