ROS python 实现键盘控制 底盘移动

需求:

1.解决手柄偶尔失灵问题, 例如:

  1. 底盘移动震动导致接收断开,2-3s重连
  2. 手柄没电问题

2.用键盘 替代 手柄控制.
在这里插入图片描述

功能实现:

方法1: 小乌龟控制键盘重映射

sim_move_ctrl.launch

<launch>
    <!--键盘控制-->
    <node pkg = "turtlesim" type = "turtle_teleop_key" name = "move_teleop_key" output = "screen">
        <remap from="/turtle1/cmd_vel" to="/cmd_vel"/>
    </node>

</launch>

查看话题 rostopic list

/cmd_vel

此方法缺点:

  1. 线速度,角速度值固定
  2. 其它按键,不能做更多的功能定制,如:
    加速,减速,任务开始,任务停止。

方法2: 自己实现,定制按键功能

按键功能


w 前进
a 右转 d 左转
s 后退

空格: 立即停止
Esc: 退出
h 帮助

注意:
长按 w\a\s\d 方向键移动
松开 按键停止


#!/usr/bin/env python3
#coding=utf-8

''' 
功能:
    实现输入w,s,a,d命令控制底盘移动
'''

import sys
import tty
import termios
import select
import time

# ROS
import rospy
from geometry_msgs.msg import Twist

class Noblock_terminal:
    def __init__(self):
        fd = sys.stdin.fileno()
        self.old_settings = termios.tcgetattr(fd)
        tty.setraw(sys.stdin.fileno(), termios.TCSANOW)

    def __exit__(self):
        if self.old_settings:
            self.stop_no_block()

    def get_char(self):
        ch = sys.stdin.read(1)
        # sys.stdout.write(ch)
        return ch

    def select_cmd(self):
        read_list = [sys.stdin]
        cmd = '0'
        read_ret,write_ret,err_ret = select.select(read_list,[],[],0.2)
        if read_ret:
            for fd in read_ret:
                if fd == sys.stdin:
                    cmd = sys.stdin.read(1)
                else:
                    print("unknow fd")
        else:
            # print("read timeout")
            pass

        # print("cmd:%s hex=%x"%(cmd,ord(cmd)))

        return cmd

    def stop_no_block(self):
        fd = sys.stdin.fileno()
        termios.tcsetattr(fd, termios.TCSADRAIN, self.old_settings)
        self.old_settings = None

class Sim_ctrl_move:
    def __init__(self):
        rospy.init_node('sim_ctrl_move', anonymous=True,disable_signals=True)
        self.pub_twist = rospy.Publisher('/move/cmd_vel', Twist, queue_size=10)
        self.help()
        self.last_show_help_time = time.time()

    def help(self):
        info = \
'''
\033[80D     w 前进
\033[80D a 右转      d 左转
\033[80D     s 后退 \n

\033[80D 空格: 立马停止
\033[80D Esc: 退出
\033[80D h 帮助
'''
        print(info)

    def timing_show_help(self):
        if time.time() - self.last_show_help_time > 10.0:
            self.last_show_help_time = time.time()
            self.help()

    def publisher_cmdvel(self,x:float,z:float):
        var = Twist()
        var.linear.x = x
        var.angular.z = z
        # 平面移动机器人常常 linear.y和linear.z为0, linear.x 表示前方
        #           angular.z代表平面机器人的角速度,因为此时z轴为旋转轴
        self.pub_twist.publish(var)
        
    def loop_run(self):
        nterm = Noblock_terminal()
        key_flag = True
        while True:
            # cmd = nterm.get_char()
            x:float = 0
            z:float = 0
            cmd = nterm.select_cmd()
            if cmd == 'w':
                print("前进")
                x= 0.3
            elif cmd == 's':
                print("后退")
                x= -0.3
            # elif cmd == 'q':
            #     print("右前")
            # elif cmd == 'e':
            #     print('左前')
            elif cmd == 'a':
                print('左转')
                z= 0.2
            elif cmd == 'd':
                print('右转')
                z= -0.2
            elif cmd == ' ':
                print('立即停止')
                x = 0
                z = 0
            elif cmd == 'h':
                self.help()
            elif ord(cmd) == 0x1b:   # Esc 16进制
                print('退出')
                break

            if key_flag == True and cmd == '0':
                key_flag = False
                self.publisher_cmdvel(0,0)
            elif cmd != '0':
                key_flag = True
                self.publisher_cmdvel(x,z)
            # 回到行首
            sys.stdout.write("\033[80D")
            self.timing_show_help()
        nterm.stop_no_block()

if __name__ == "__main__":
    sim_ctrl = Sim_ctrl_move()
    sim_ctrl.loop_run()

注意事项:

  1. 将/move/cmd_vel 修改为自己的话题节点:
  2. 空格键 -立即停止说明:
    松开方向按键,需要0.2s, 才会发速度0,设备才会停止移动。
    如果你对控制灵敏度高,可以修改select超时数值, 或按 空格 立即停止
  3. 功能定制
    我们的项目有加速,减速,任务开始\暂停\继续\停止 功能,其它功能实现.
    小伙伴根据自己项目定制,实现.

我是一名ROS机器人, 嵌入式/中间件开发工程师.

以下是一个简单的ROS键盘控制小车底盘运动的C++代码示例: ```cpp #include <ros/ros.h> #include <geometry_msgs/Twist.h> #include <stdio.h> #include <stdlib.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> #define KEYCODE_W 0x77 #define KEYCODE_S 0x73 #define KEYCODE_A 0x61 #define KEYCODE_D 0x64 #define KEYCODE_Q 0x71 #define KEYCODE_E 0x65 int kfd = 0; struct termios cooked, raw; void quit(int sig) { tcsetattr(kfd, TCSANOW, &cooked); ros::shutdown(); exit(0); } int main(int argc, char** argv) { ros::init(argc, argv, "teleop_twist_keyboard"); ros::NodeHandle nh; ros::Publisher twist_pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 1); signal(SIGINT,quit); char c; bool dirty=false; // get the console in raw mode tcgetattr(kfd, &cooked); memcpy(&raw, &cooked, sizeof(struct termios)); raw.c_lflag &=~ (ICANON | ECHO); // Setting a new line, then end of file raw.c_cc[VEOL] = 1; raw.c_cc[VEOF] = 2; tcsetattr(kfd, TCSANOW, &raw); puts("Reading from keyboard"); puts("---------------------------"); puts("Use arrow keys to move the robot."); for(;;) { // get the next event from the keyboard if(read(kfd, &c, 1) < 0) { perror("read():"); exit(-1); } geometry_msgs::Twist twist; switch(c) { case KEYCODE_W: twist.linear.x = 1.0; dirty = true; break; case KEYCODE_S: twist.linear.x = -1.0; dirty = true; break; case KEYCODE_A: twist.angular.z = 1.0; dirty = true; break; case KEYCODE_D: twist.angular.z = -1.0; dirty = true; break; case KEYCODE_Q: twist.linear.y = 1.0; dirty = true; break; case KEYCODE_E: twist.linear.y = -1.0; dirty = true; break; } if(dirty ==true) { twist_pub.publish(twist); dirty=false; } } return(0); } ``` 这个代码将读取键盘输入并将运动控制命令发布到ROS话题/cmd_vel上。可以通过订阅该话题的节点来控制小车底盘的运动。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值