ROS小车研究笔记1/31/2023 小车硬件结构及键盘移动控制节点

news2024/7/4 5:50:56

1 小车硬件结构
在这里插入图片描述
1 中控设备
在这里插入图片描述
上方的单片机用于控制电机运动,搭载wifi模块和电量显示屏。下方为树莓派,安装了ROS系统和Ubuntu系统,用于整个小车控制。显示屏和树莓派相连

2 传感器系统
在这里插入图片描述
在这里插入图片描述
激光雷达及转换器。激光雷达和转换器相连,再由转换器连接树莓派以控制激光雷达

在这里插入图片描述
摄像头系统,搭载深度摄像头和彩色摄像头

4 遥控系统
在这里插入图片描述
在这里插入图片描述
使用PS2遥控器,车身搭载PS2接收端
5 在这里插入图片描述
12V电池盒。小车只有在电压大于10V时才能工作

2 键盘控制移动
键盘控制节点:

roslaunch wheeltec_robot_rc keyboard_teleop.launch

控制说明:
U I O
J L
M .
控制各方向

k键和空格键为急停,立刻停止电机,按其他键为缓慢减速停止

Q/Z 增加/减少10%线速度和角速度
W/X 增加/减少10%线速度
E/C 增加/减少10%角速度
B 开关全向模式

键盘控制节点(turtlebot_teleop_key)
1

Omni = 0 #全向移动模式

#键值对应移动/转向方向
moveBindings = {
        'i':( 1, 0),
        'o':( 1,-1),
        'j':( 0, 1),
        'l':( 0,-1),
        'u':( 1, 1),
        ',':(-1, 0),
        '.':(-1, 1),
        'm':(-1,-1),
           }

#键值对应速度增量
speedBindings={
        'q':(1.1,1.1),
        'z':(0.9,0.9),
        'w':(1.1,1),
        'x':(0.9,1),
        'e':(1,  1.1),
        'c':(1,  0.9),
          }
          
speed = 0.2 #默认移动速度 m/s
turn  = 0.5   #默认转向速度 rad/s

移动键和速度控制键对应的值。最终速度为 (speed X 方向)和(turn X 方向)。在修改速度时为(speed X 修改幅度)和(turn X 修改幅度)

2

    settings = termios.tcgetattr(sys.stdin) #获取键值初始化,读取终端相关属性
    
    rospy.init_node('turtlebot_teleop') #创建ROS节点
    pub = rospy.Publisher('~cmd_vel', Twist, queue_size=5) #创建速度话题发布者,'~cmd_vel'='节点名/cmd_vel'

    x      = 0   #前进后退方向
    th     = 0   #转向/横向移动方向
    count  = 0   #键值不再范围计数
    target_speed = 0 #前进后退目标速度
    target_turn  = 0 #转向目标速度
    target_HorizonMove = 0 #横向移动目标速度
    control_speed = 0 #前进后退实际控制速度
    control_turn  = 0 #转向实际控制速度
    control_HorizonMove = 0 #横向移动实际控制速度

创建ros节点和Twist消息发布者pub。pub的消息被wheeltec_robot类订阅。wheeltec类会通过串口通信将速度控制指令发给下位机。

这里速度变化由于都是平滑变化。方向控制指令只会直接影响目标速度target_turn和target_speed。真实速度会渐进到目标速度(见下方代码)

3 读取控制键信息

while(1):
            key = getKey() #获取键值

            #切换是否为全向移动模式,全向轮/麦轮小车可以加入全向移动模式
            if key=='b':               
                Omni=~Omni
                if Omni: 
                    print("Switch to OmniMode")
                    moveBindings['.']=[-1,-1]
                    moveBindings['m']=[-1, 1]
                else:
                    print("Switch to CommonMode")
                    moveBindings['.']=[-1, 1]
                    moveBindings['m']=[-1,-1]
            
            #判断键值是否在移动/转向方向键值内
            if key in moveBindings.keys():
                x  = moveBindings[key][0]
                th = moveBindings[key][1]
                count = 0

            #判断键值是否在速度增量键值内
            elif key in speedBindings.keys():
                speed = speed * speedBindings[key][0]
                turn  = turn  * speedBindings[key][1]
                count = 0
                print(vels(speed,turn)) #速度发生变化,打印出来

            #空键值/'k',相关变量置0
            elif key == ' ' or key == 'k' :
                x  = 0
                th = 0
                control_speed = 0
                control_turn  = 0
                HorizonMove   = 0

            #长期识别到不明键值,相关变量置0
            else:
                count = count + 1
                if count > 4:
                    x  = 0
                    th = 0
                if (key == '\x03'):
                    break

这里可以看到一点。对于k和空格键按下一次即可急停,而对于按其他键停止需要按至少5次

4 根据速度方向和大小计算最终速度值

            #根据速度与方向计算目标速度
            target_speed = speed * x
            target_turn  = turn * th
            target_HorizonMove = speed*th

            #平滑控制,计算前进后退实际控制速度
            if target_speed > control_speed:
                control_speed = min( target_speed, control_speed + 0.1 )
            elif target_speed < control_speed:
                control_speed = max( target_speed, control_speed - 0.1 )
            else:
                control_speed = target_speed

            #平滑控制,计算转向实际控制速度
            if target_turn > control_turn:
                control_turn = min( target_turn, control_turn + 0.5 )
            elif target_turn < control_turn:
                control_turn = max( target_turn, control_turn - 0.5 )
            else:
                control_turn = target_turn

            #平滑控制,计算横向移动实际控制速度
            if target_HorizonMove > control_HorizonMove:
                control_HorizonMove = min( target_HorizonMove, control_HorizonMove + 0.1 )
            elif target_HorizonMove < control_HorizonMove:
                control_HorizonMove = max( target_HorizonMove, control_HorizonMove - 0.1 )
            else:
                control_HorizonMove = target_HorizonMove

这里可以看到方向键只会立刻改变target_speed和target_turn。而真实速度和方向control_speed和control_turn会在每一轮循环中向目标速度改变0.1,实现平滑变速

5 创建并发布话题

            #根据是否全向移动模式,给速度话题变量赋值
            if Omni==0:
                twist.linear.x  = control_speed; twist.linear.y = 0;  twist.linear.z = 0
                twist.angular.x = 0;             twist.angular.y = 0; twist.angular.z = control_turn
            else:
                twist.linear.x  = control_speed; twist.linear.y = control_HorizonMove; twist.linear.z = 0
                twist.angular.x = 0;             twist.angular.y = 0;                  twist.angular.z = 0

            pub.publish(twist) #ROS发布速度话题

判断当前状态是否为全向运动而选择不同话题。消息类型使用了ROS标准定义的geometry_msgs.msg/Twist接口,其中包含值:

linear.x
linear.y
linear.z
angular.x
angular.y
angular.z

代表三轴线速度和角速度

键盘控制节点完整代码:

import rospy

from geometry_msgs.msg import Twist

import sys, select, termios, tty

msg = """
Control Your Turtlebot!
---------------------------
Moving around:
   u    i    o
   j    k    l
   m    ,    .

q/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%
space key, k : force stop
anything else : stop smoothly
b : switch to OmniMode/CommonMode
CTRL-C to quit
"""
Omni = 0 #全向移动模式

#键值对应移动/转向方向
moveBindings = {
        'i':( 1, 0),
        'o':( 1,-1),
        'j':( 0, 1),
        'l':( 0,-1),
        'u':( 1, 1),
        ',':(-1, 0),
        '.':(-1, 1),
        'm':(-1,-1),
           }

#键值对应速度增量
speedBindings={
        'q':(1.1,1.1),
        'z':(0.9,0.9),
        'w':(1.1,1),
        'x':(0.9,1),
        'e':(1,  1.1),
        'c':(1,  0.9),
          }

#获取键值函数
def getKey():
    tty.setraw(sys.stdin.fileno())
    rlist, _, _ = select.select([sys.stdin], [], [], 0.1)
    if rlist:
        key = sys.stdin.read(1)
    else:
        key = ''

    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
    return key


speed = 0.2 #默认移动速度 m/s
turn  = 0.5   #默认转向速度 rad/s
#以字符串格式返回当前速度
def vels(speed,turn):
    return "currently:\tspeed %s\tturn %s " % (speed,turn)

#主函数
if __name__=="__main__":
    settings = termios.tcgetattr(sys.stdin) #获取键值初始化,读取终端相关属性
    
    rospy.init_node('turtlebot_teleop') #创建ROS节点
    pub = rospy.Publisher('~cmd_vel', Twist, queue_size=5) #创建速度话题发布者,'~cmd_vel'='节点名/cmd_vel'

    x      = 0   #前进后退方向
    th     = 0   #转向/横向移动方向
    count  = 0   #键值不再范围计数
    target_speed = 0 #前进后退目标速度
    target_turn  = 0 #转向目标速度
    target_HorizonMove = 0 #横向移动目标速度
    control_speed = 0 #前进后退实际控制速度
    control_turn  = 0 #转向实际控制速度
    control_HorizonMove = 0 #横向移动实际控制速度
    try:
        print(msg) #打印控制说明
        print(vels(speed,turn)) #打印当前速度
        while(1):
            key = getKey() #获取键值

            #切换是否为全向移动模式,全向轮/麦轮小车可以加入全向移动模式
            if key=='b':               
                Omni=~Omni
                if Omni: 
                    print("Switch to OmniMode")
                    moveBindings['.']=[-1,-1]
                    moveBindings['m']=[-1, 1]
                else:
                    print("Switch to CommonMode")
                    moveBindings['.']=[-1, 1]
                    moveBindings['m']=[-1,-1]
            
            #判断键值是否在移动/转向方向键值内
            if key in moveBindings.keys():
                x  = moveBindings[key][0]
                th = moveBindings[key][1]
                count = 0

            #判断键值是否在速度增量键值内
            elif key in speedBindings.keys():
                speed = speed * speedBindings[key][0]
                turn  = turn  * speedBindings[key][1]
                count = 0
                print(vels(speed,turn)) #速度发生变化,打印出来

            #空键值/'k',相关变量置0
            elif key == ' ' or key == 'k' :
                x  = 0
                th = 0
                control_speed = 0
                control_turn  = 0
                HorizonMove   = 0

            #长期识别到不明键值,相关变量置0
            else:
                count = count + 1
                if count > 4:
                    x  = 0
                    th = 0
                if (key == '\x03'):
                    break

            #根据速度与方向计算目标速度
            target_speed = speed * x
            target_turn  = turn * th
            target_HorizonMove = speed*th

            #平滑控制,计算前进后退实际控制速度
            if target_speed > control_speed:
                control_speed = min( target_speed, control_speed + 0.1 )
            elif target_speed < control_speed:
                control_speed = max( target_speed, control_speed - 0.1 )
            else:
                control_speed = target_speed

            #平滑控制,计算转向实际控制速度
            if target_turn > control_turn:
                control_turn = min( target_turn, control_turn + 0.5 )
            elif target_turn < control_turn:
                control_turn = max( target_turn, control_turn - 0.5 )
            else:
                control_turn = target_turn

            #平滑控制,计算横向移动实际控制速度
            if target_HorizonMove > control_HorizonMove:
                control_HorizonMove = min( target_HorizonMove, control_HorizonMove + 0.1 )
            elif target_HorizonMove < control_HorizonMove:
                control_HorizonMove = max( target_HorizonMove, control_HorizonMove - 0.1 )
            else:
                control_HorizonMove = target_HorizonMove
         
            twist = Twist() #创建ROS速度话题变量
            #根据是否全向移动模式,给速度话题变量赋值
            if Omni==0:
                twist.linear.x  = control_speed; twist.linear.y = 0;  twist.linear.z = 0
                twist.angular.x = 0;             twist.angular.y = 0; twist.angular.z = control_turn
            else:
                twist.linear.x  = control_speed; twist.linear.y = control_HorizonMove; twist.linear.z = 0
                twist.angular.x = 0;             twist.angular.y = 0;                  twist.angular.z = 0

            pub.publish(twist) #ROS发布速度话题

    #运行出现问题则程序终止并打印相关错误信息
    except Exception as e:
        print(e)

    #程序结束前发布速度为0的速度话题
    finally:
        twist = Twist()
        twist.linear.x = 0;  twist.linear.y = 0;  twist.linear.z = 0
        twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = 0
        pub.publish(twist)

    #程序结束前设置终端相关属性
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/189489.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Rust】7. 枚举和模式匹配

7.1 枚举&#xff08;可存储不同类型的值&#xff09; 7.1.1 基本概念 7.1.2 枚举的简洁用法&#xff1a;构造函数 7.1.3 枚举的优势&#xff1a;处理不同类型和数量的数据 枚举成员的类型&#xff1a;字符串、数字类型、结构体、枚举注意&#xff1a;在未将标准库枚举引入当…

Java——两两交换链表中的节点

题目链接 leetcode在线oj题——两两交换链表中的节点 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 题目示例 …

Vue中的$children与$parent讲解

$children与$parent直接演示代码父组件&#xff1a;<template><div><h2>BABA有存款: {{ money }}</h2><button>找小明借钱100</button><br /><button>找小红借钱150</button><br /><button>找所有孩子借钱2…

Day875.怎么给字符串字段加索引 -MySQL实战

怎么给字符串字段加索引 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于怎么给字符串字段加索引的内容。 现在&#xff0c;几乎所有的系统都支持邮箱登录&#xff0c;如何在邮箱这样的字段上建立合理的索引。 假设&#xff0c;现在维护一个支持邮箱登录的系统&…

【计算机图形学(译)】 一、介绍

【计算机图形学(译&#xff09;】 一、介绍1 介绍 Introduction1.1 图形领域 (Graphics Areas)1.2 主要应用 (Major Applications)1.3 图形APls (Graphics APIs)1.4 图形管线 (Graphics Pinpline)1.5 数值问题 (Numerical Issues)1.6 效率 (Efficiency)1.7 设计和编写图形程序 …

Detectron2部署教程,着重ONNX(从官网翻译)

本教程翻译至这里 https://detectron2.readthedocs.io/en/latest/tutorials/deployment.html detectron2模型训练以后如果想要部署&#xff0c;就需要导出专门的模型才可以。 三种模型导出方式 detectron2支持的模型导出方式有&#xff1a; tracing 该方式导出的格式是Torch…

常量池/String常见面试题

目录 常量池与运行时常量池 字符串常量池String_Table 字符串变量拼接 字符串常量拼接 字符串延迟加载 字符串intern方法 总结StringTable的特点 常量池与运行时常量池 二进制字节码包括 类的基本信息,常量池,类方法定义(包含虚拟机指令) class文件中除了有类的版本,字…

新突破:科学家发现全新的量子纠缠效应

布鲁克海文国家实验室&#xff08;图片来源&#xff1a;网络&#xff09;布鲁克海文国家实验室的科学家发现了一种全新的量子纠缠效应&#xff0c;即使宇宙距离相隔广阔&#xff0c;量子纠缠也会使粒子奇迹般地联系在一起。这一发现使他们能够捕捉到原子内部的奇特世界。这项研…

【算法自由之路】二叉树的递归套路

【算法自由之路】二叉树的递归套路 预热&#xff0c;二叉树的后继节点 话不多说&#xff0c;首先是一道练手题&#xff0c;寻找二叉树任意给定节点的后继节点&#xff0c;此二叉树具备一个指向父节点的指针。 后继节点&#xff1a;在中序遍历中于给定节点后一个打印的节点 p…

SpringBoot实现配置文件的加密和解密

一、项目搭建 1.新建一个springBoot项目 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocatio…

DAMO-YOLO : A Report on Real-Time Object Detection Design

DAMO-YOLO:实时目标检测设计报告在本报告中&#xff0c;我们提出了一种被称为DAMO-YOLO的快速准确的物体检测方法&#xff0c;该方法比最先进的YOLO系列具有更高的性能。DAMO-YOLO是由YOLO扩展而来的&#xff0c;它采用了一些新技术&#xff0c;包括神经结构搜索(NAS)、高效的重…

LeetCode——1669. 合并两个链表

一、题目 给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中下标从 a 到 b 的全部节点都删除&#xff0c;并将list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请你返回结果链表的头指针。 来…

【Qt】3.菜单栏、工具栏、状态栏、铆接部件、核心部件、资源文件

目录 菜单栏 工具栏 代码 mainwindow.cpp 结果 状态栏 铆接部件 核心部件 代码 mainwindow.cpp 结果 资源文件 代码 mainwindow.cpp 结果 菜单栏 只能有一个 menuBar()返回一个QMenuBar *bar 将bar放入到窗口中setMenuBar(bar) 添加菜单addMenu("文件&…

三年了,回村了

今年回老家了&#xff0c;因为工作和疫情等原因已经三年多没回了&#xff0c;思乡之情已经压不住了。 老家是一个五线小城市&#xff0c;属于南方典型的鱼米之乡&#xff1a;依山傍水、山清水秀。同时还有一个知名白酒厂&#xff1a;白云边&#xff0c;经济发展还不错。 老家…

从“语义网”到“去中心化”,Web3.0到底是个啥?

什么是Web3.0&#xff0c;为什么近两年这个概念又再一次火出了圈&#xff0c;但凡A股上市公司正在做或者准备做的业务与它沾上边&#xff0c;总会有那么几次异动。 这个概念到底是金融市场布下的骗局&#xff0c;还是未来互联网发展的趋势&#xff0c;在大家的眼里都是褒贬不一…

Redis 核心原理串讲(下),架构演进之高扩展

文章目录Redis 核心原理总览&#xff08;全局篇&#xff09;前言一、数据分片1、集群&#xff1f;2、分片&#xff1f;3、分片固定&#xff1f;4、元数据二、集群1、代理集群2、分片集群3、代理 分片集群三、生产实践总结Redis 核心原理总览&#xff08;全局篇&#xff09; 正…

新的一年,如何打开超级APP发展格局

本文开始我们先来明确一个概念&#xff1a;超级APP是什么&#xff1f;百度百科的定义是——那些拥有庞大的用户数&#xff0c;成为用户手机上的"装机必备”的基础应用。实际上各大互联网平台也给出了不同的解释&#xff0c;但相同点是他们都认为超级APP就应该超级个性化&a…

简单手写后门Safedog检测绕过

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是简单手写后门Safedog检测绕过。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁…

最长上升子序列、最长公共子序列、最长公共上升子序列(LIS、LCS、LCIS)

LIS、LCS、LCIS最长上升子序列LIS最长公共子序列LCS最长公共上升子序列LCIS最长上升子序列LIS 题目链接&#xff1a;AcWing895. 最长上升子序列 这里只说明O(n2)O(n^2)O(n2)的解法&#xff0c;O(nlogn)O(nlogn)O(nlogn)解法之前的博客有介绍 O(n2)O(n^2)O(n2)的解法较为容易理…

MMCV - browse_dataset.py 可视化config文件数据预处理部分

无论是mmdetection、mmtracking、mmdetection3D等框架&#xff0c;在\tools\analysis_tools中均有一个名为browse_dataset.py的文件。该文件能够帮助用户直接可视化 config 文件中的数据处理部分&#xff0c;查看标注文件是否正确&#xff0c;同时可以选择保存可视化图片到指定…