kinetic下键盘控制机器人(python实现)

完整的代码我会放到文章末尾

我们的代码分为三个部分:

1,键盘事件监控

2,速度反馈

3,主函数(主要实现控制)

首先我们创建了两个字典,一个用于改变机器人运动方向,一个用于机器人速度控制
MoveBindings = {
    'w':(1, 0),
    's':(-1, 0),
    'a':(0, 1),
    'd':(0, -1),
    'q':(1, 1),
    'e':(1, -1),
    'z':(-1, 1),
    'c':(-1, 1)
}

SpeedBindings = {
    '+':(1.1, 1.1),
    '-':(0.9, 0.9),
    '1':(1.1, 1),
    '2':(0.9, 1),
    '3':(1, 1.1),
    '4':(1, 0.9)

}


然后我们来看第一部分,监听键盘事件

这里我们使用了select模块,termios模块和tty模块

select模块主要用于socket通信,见识文件描述的变化,完成非阻塞方式工作

termios模块为tty提供了一个IO控制的POSIX调用的接口

tty模块主要用于更改文件描述符fd的模式

首先我们要把输入文件描述符模式改为raw,然后直接调用操作系的IO接口,监控所有带fileno()方法的文件句柄

在这里,我们只需要读取一个字节的输入流

最后我们从属性设置文件描述符fd的tty属性,返回键值

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


第二部分我们写了一个返回速度和旋转量的函数,非常简单

def vels(speed, turn):

    return "currently:\t speed %s\t turn %s" % (speed, turn)


最后是我们的主要的控制和逻辑函数

首先我们需要得带文件描述符fd的tty属性

其次就是发布速度

在后面就是对速度的一些控制代码

if __name__ == '__main__':
    settings = termios.tcgetattr(sys.stdin)

    rospy.init_node('teleop')
    pub = rospy.Publisher('/cmd_vel', Twist, queue_size = 10)

    x = 0
    th = 0
    status = 0
    count = 0
    acc = 0.1

    target_speed = 0
    target_turn = 0

    control_speed = 0
    control_turn = 0

    try:
        print msg
        print vels(speed, turn)

        while(1):
            key = GetKey()

            if (key in MoveBindings.keys()):
                x  = MoveBindings[key][0]
                th = MoveBindings[key][1]
                rospy.loginfo("speed is : %s \t turn is : %s " %(speed, turn))
                count = 0
            elif (key in SpeedBindings.keys()):
                speed = speed*SpeedBindings[key][0]
                turn  = turn*SpeedBindings[key][1]
                count = 0

                print vels(speed, turn)

                status  = (status+1)%15

            elif (key == ' ' or key == 'x'):
                x = 0
                th = 0
                control_speed = 0
                control_turn = 0
                rospy.loginfo("pause the robot...")
            else:
                count += 1

                if count > 4:
                    x = 0
                    th = 0
                if key == '\x03':
                    break

            target_speed = speed*x
            target_turn = turn*th

            if target_speed > control_speed:
                control_speed = min(target_speed, control_speed+0.02)
            elif target_speed < control_speed:
                control_speed = max(target_speed, control_speed-0.02)
            else:
                control_speed = target_speed

            if target_turn > control_turn:
                control_turn = min(target_turn, control_turn+0.1)
            elif target_turn < control_turn:
                control_turn = max(target_turn, control_turn-0.1)
            else:
                control_turn  = target_turn

            twist = Twist()
            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

            pub.publish(twist)

    except:
        rospy.logerr("some code error, please check!!!")
    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)



现在就是整个代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
from geometry_msgs.msg import Twist
import sys, select, termios, tty

msg = """
Control mrobot!
---------------------------
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

CTRL-C to quit
"""

moveBindings = {
        'w':(1,0),
        'e':(1,-1),
        'a':(0,1),
        'd':(0,-1),
        'q':(1,1),
        's':(-1,0),
        'x':(-1,1),
        'z':(-1,-1),
           }

speedBindings={
        '+':(1.1,1.1),
        '-':(.9,.9),
        '3':(1.1,1),
        '4':(.9,1),
        '5':(1,1.1),
        '6':(1,.9),
          }

def getKey():
    # tty.setraw():将文件描述符fd模式更改为raw
    # fileno():返回一个整形的文件描述符(fd)
    tty.setraw(sys.stdin.fileno())
    # select():直接调用操作系统的IO接口,它监控所有带fileon()方法的文件句柄
    rlist, _, _ = select.select([sys.stdin], [], [], 0.1)
    if rlist:
        key = sys.stdin.read(1) # 只读取一个字节
    else:
        key = ''
    # termios该模块提供了一个用于tty I / O控制的POSIX调用的接口
    # tcsetattr:从属性设置文件描述符fd的tty属性
    # 参数二when: 参数确定属性何时发生更改:TCSANOW立即更改,TCSADRAIN在传输所有排队输出后更改,
    # 或TCSAFLUSH在传输所有排队输出并丢弃所有排队输入后更改
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
    return key

speed = .2 # 线速度
turn = 1   # 角速度

def vels(speed,turn):
    return "currently:\tspeed %s\tturn %s " % (speed,turn)

if __name__=="__main__":
    # tcgetattr():返回包含文件描述符fd的tty属性的列表
    settings = termios.tcgetattr(sys.stdin)
    
    rospy.init_node('mrobot_teleop')
    pub = rospy.Publisher('/cmd_vel', Twist, queue_size=5)

    x = 0
    th = 0
    status = 0
    count = 0
    acc = 0.1
    target_speed = 0 # target:目标 目标线速度
    target_turn = 0  # 目标角速度
    control_speed = 0
    control_turn = 0
    try:
        print msg
        print vels(speed,turn)
        while(1):
            key = getKey()
            # 运动控制方向键(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]  # 线速度增加0.1倍
                turn = turn * speedBindings[key][1]    # 角速度增加0.1倍
                count = 0

                print vels(speed,turn)
                #if (status == 14):
                    #print msg
                status = (status + 1) % 15
            # 停止键
            elif key == ' ' or key == 'k' :
                x = 0
                th = 0
                control_speed = 0
                control_turn = 0
            else:
                count = count + 1
                if count > 4:
                    x = 0
                    th = 0
                if (key == '\x03'):
                    break

            # 目标速度=速度值*方向值
            target_speed = speed * x
            target_turn = turn * th

            # 速度限位,防止速度增减过快
            if target_speed > control_speed:
                control_speed = min( target_speed, control_speed + 0.02 )
            elif target_speed < control_speed:
                control_speed = max( target_speed, control_speed - 0.02 )
            else:
                control_speed = target_speed

            if target_turn > control_turn:
                control_turn = min( target_turn, control_turn + 0.1 )
            elif target_turn < control_turn:
                control_turn = max( target_turn, control_turn - 0.1 )
            else:
                control_turn = target_turn

            # 创建并发布twist消息
            twist = Twist()
            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
            pub.publish(twist)

    except:
        print e

    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)


猜你喜欢

转载自blog.csdn.net/dzhongjie/article/details/80719760
今日推荐