ROS中使用游戏手柄操控turtle

在ROS中,使用键盘控制turtle运动比较简单,下面主要对游戏手柄操控turtle进行代码说明和演示。

 手柄如下:

上图中手柄上有两个操作杆。后面内容分为两个部分,一部分是单个操作杆(单轴)控制,另一部分是双操作杆(双轴)控制。但是这两部分内容主要不同在于轴的配置不同,体现在之后的.cpp代码有差异,其他并无差异。

一、基础的准备工作:

(1)创建工作空间
$ mkdir -p ~/catkin_workspace/src
$ cd ~/catkin_workspace/src
$ catkin_init_workspace

运行后在catkin_workspace--->src中会产生CMakeLists.txt文件,结果如下:

(2)编译工作空间
$ cd ~/catkin_workspace/
$ catkin_make

 在终端中运行结果为:

在工作区间catkin_workspace中会产生build、devel文件夹和 .catkin_workspace文件,如下图所示:

 (3)设置环境变量
$ source devel/setup.bash

运行结果为:

 (4)检查环境变量
$ echo $ROS_PACKAGE_PATH

运行结果:

 以上就是准备工作,在这个基础上,就可以在这个workspace上继续后续的代码编写了。

二、手柄连接测试

系统是Ubuntu18.04,在终端输入:

$ lsusb

运行结果:

 红色框显示的正好是我的手柄的型号,说明手柄连接成功。

另一种测试是否连接成功的方法是,在终端输入:

$ ls /dev/input

运行结果为:

 结果中出现了js0,也可能出现的是js1,不管是哪个,都说明手柄连接成功。

接下来,检验手柄上各个轴和键的对应关系,运行:

$ sudo jstest /dev/input/js0

运行结果为:

 sudo 命令可以提高用户权限,因此要先输入密码。输入密码后,回车,就可以看到很多个Axes(轴)和Buttons(按钮),可以按手柄上的按钮或者摇动操作杆,就会看到终端上对应位置的数字的改变。

或者使用命令jstest-gtk,可以从可视化图上看到轴和按钮的个数以及对应关系。

 运行结果为:

三、安装joy相关的包

需要订阅/joy话题,获取手柄上的信息,因此需要安装joy相关的包。

终端输入:

sudo apt-get install ros-melodic-joy
sudo apt-get install ros-melodic-joystick-drivers

注意要安装Ubuntu版本对应的Ros版本。本文中使用的Ubuntu18.04对应的Ros版本是melodic,可以在网上查询一下自己安装的Ubuntu对应的Ros版本,然后将其替换上述命令行中的“melodic”。

运行结果为:(因为我之前已经安装过,所以显示的是<ros-melodic-joy 已经是最新版>、<ros-melodic-joystick-drivers 已经是最新版> )

 接下来,运行代码验证以下joy包是否安装成功。

运行命令:

$ roscore

启动Ros Master,也就是启动节点管理器,这是必要的,启动Master之后节点才可以在Master上注册节点信息、设置话题类型等。

启动Ros Master的界面如下:

设定joy节点所读取的手柄设备:

rosparam set joy_node/dev "/dev/input/js0"

之后,运行joy_node命令:

$ rosrun joy joy_node

四、(单操作杆)手柄控制海龟

在catkin_workspace的src目录下创建control_turtle功能包,使用命令为:

$ catkin_create_pkg control_turtle roscpp rospy std_msgs geometry_msgs turtlesim

roscpp rospy std_msgs geometry_msgs turtlesim均为所需的依赖包。

运行结果为:(successfully出现即创建成功)

单个遥杆控制的.cpp代码为:

Single_teleop_turtle.cpp代码:

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/Joy.h>

class TeleopTurtle
{
public:
    TeleopTurtle();

private:
    // 处理手柄发送过来的信息
    void callback(const sensor_msgs::Joy::ConstPtr &joy);
    // 实例化ROS句柄
    ros::NodeHandle nh;
    // 定义订阅者对象,用来订阅手柄发送的数据
    ros::Subscriber sub;
    // 定义发布者对象,用来将手柄数据发布到乌龟控制话题上
    ros::Publisher pub;
    // 用来接收launch文件中设置的参数,绑定手柄摇杆、轴的映射
    int axis_linear, axis_angular;
};

TeleopTurtle::TeleopTurtle()
{
    // 从参数服务器读取的参数
    nh.param<int>("axis_linear", axis_linear, 1);
    nh.param<int>("axis_angular", axis_angular, 2);

    pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1);
    sub = nh.subscribe<sensor_msgs::Joy>("joy", 10, &TeleopTurtle::callback, this);
}

void TeleopTurtle::callback(const sensor_msgs::Joy::ConstPtr &joy)
{
    geometry_msgs::Twist vel;
    // 将手柄摇杆轴拨动时值的输出赋值给乌龟的线速度和角速度
    vel.linear.x = joy->axes[axis_linear];
    vel.angular.z = joy->axes[axis_angular];
    ROS_INFO("当前线速度为:%.3lf ; 角速度为:%.3lf", vel.linear.x, vel.angular.z);
    pub.publish(vel);
}

int main(int argc, char **argv)
{
    // 设置编码
    setlocale(LC_ALL, "");
    // 初始化ROS节点
    ros::init(argc, argv, "teleop_turtle");
    TeleopTurtle teleopTurtle;
    ros::spin();
    return 0;
}

双摇杆控制的.cpp代码为:

Double_teleop_turtle.cpp代码:

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <sensor_msgs/Joy.h>
 
class TeleopTurtle
{
public:
    TeleopTurtle();
 
private:
    // 处理手柄发送过来的信息
    void callback(const sensor_msgs::Joy::ConstPtr &joy);
    // 实例化ROS句柄
    ros::NodeHandle nh;
    // 定义订阅者对象,用来订阅手柄发送的数据
    ros::Subscriber sub;
    // 定义发布者对象,用来将手柄数据发布到乌龟控制话题上
    ros::Publisher pub;
    // 用来接收launch文件中设置的参数,绑定手柄摇杆、轴的映射
    int axis_linear, axis_angular;
    int sticks_left, sticks_right;
};
 
TeleopTurtle::TeleopTurtle()
{
    // 从参数服务器读取的参数
    // 按手柄摇杆分配
    nh.param<int>("sticks_left", sticks_left, 1);
    nh.param<int>("sticks_right", sticks_right, 3);
    // 按键分配
    nh.param<int>("axis_linear", axis_linear, 1);
    nh.param<int>("axis_angular", axis_angular, 2);
  // Axes:  0:     0  1:     0  2: 0   3:     0  4:     0  5: 0   6:     0  7:     0 
    // 对应:0: 左摇杆轴左右
    //    1: 左摇杆轴前后
    //    2: 默认全不开放
    //    3: 右摇杆轴左右
    //    4: 右摇杆轴前后
    //    5: 默认全不开放
    //    6: 方向按键左+右
    //    7: 方向按键前+后 

    pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
    sub = nh.subscribe<sensor_msgs::Joy>("joy", 10, &TeleopTurtle::callback, this);
}
 
void TeleopTurtle::callback(const sensor_msgs::Joy::ConstPtr &joy)
{
    geometry_msgs::Twist vel;
    // 将手柄摇杆轴拨动时值的输出赋值给乌龟的线速度和角速度
   if(joy->axes[axis_linear] || joy->axes[axis_angular])
    {
        vel.linear.x = joy->axes[axis_linear];
        vel.angular.z = joy->axes[axis_angular];
    }
    else if(joy->axes[sticks_left] ||  joy->axes[sticks_right])
    {
        vel.linear.x = joy->axes[sticks_left];
        vel.angular.z = joy->axes[sticks_right];
    }
    // // 将手柄摇杆轴拨动时值的输出赋值给乌龟的线速度和角速度
    // vel.linear.x = joy->axes[axis_linear];
    // vel.angular.z = joy->axes[axis_angular];
    // // 按键按动时也可以输出乌龟的线速度和角速度
    // vel.linear.x = joy->axes[sticks_left];
    // vel.angular.z = joy->axes[sticks_right];
    ROS_INFO("当前线速度为:%.3lf ; 角速度为:%.3lf", vel.linear.x, vel.angular.z);
    pub.publish(vel);
}
 
int main(int argc, char **argv)
{
    // 设置编码
    setlocale(LC_ALL, "");
    // 初始化ROS节点
    ros::init(argc, argv, "teleop_turtle");
    TeleopTurtle teleopTurtle;
    ros::spin();
    return 0;
}

之后,在control_turtle--->src下创建Single_teleop_turtle.cpp / Double_teleop_turtle.cpp,命令为:

$ touch Single_teleop_turtle.cpp

结果为:

 

在catkin_workspace的src目录下创建launch_turtle功能包, 

$ catkin_create_pkg launch_turtle

运行结果为:

 看到 successfully ,则创建成功!

接着,在launch_turtle功能包下,右键创建launch文件夹(一般默认创建的文件夹为launch,其他当然也可以)

 最后在launch文件夹下创建turtlelaunch.launch,命令为:

$ touch turtlelaunch.launch

 turtlelaunch.launch中的代码为:

<launch>
    <!-- 启动乌龟节点 -->
    <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node"/>
    
    <!-- 启动我们创建的手柄控制乌龟节点 -->
    <node pkg="teleop" type="teleop_turtle" name="teleop_turtle" output="screen"/> 
    
    <!-- 向参数服务器写入参数 -->
    <param name="axis_linear" value="1" type="int"/>
    <param name="axis_angular" value="3" type="int"/>
    
    <!-- 启动手柄节点,respawn="true"表示节点挂掉时会自动重启 -->
    <node respawn="true" pkg="joy" type="joy_node" name="joystick" />
</launch>

修改CMakeLists.txt配置文件,将下面代码添加到该文件中:

# 节点构建选项,配置可执行文件
add_executable(Single_teleop_turtle src/Single_teleop_turtle.cpp)
# 节点构建选项,配置目标链接库
target_link_libraries(Single_teleop_turtle ${catkin_LIBRARIES}
)

五、结果

手柄单遥感控制turtle运动

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_52765390

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值