基于ROS通过外设控制仿真机械臂运动

前言

最近要实现手柄控制机械臂的运动,苦于经费不足,手柄目前还用不上,不得已采用鼠标代替,不过原理是一样的,其实笔者早些时间学过一点ROS,不过已经忘的差不多了,趁此机会好好恶补一下,学习资料参考《ROS机器人开发实践》

鼠标部分

安装功能包

为了能够让系统检测到外设的接入同时正常使用,我们需要下载一些功能包

sudo apt-get install ros-noetic-joystick-drivers

有时候会出现安装版本不同导致异常的情况,这个时候用aptitude辅助安装,他会智能检索要安装的包

sudo apt-get install aptitude
sudo aptitude install <package name>

检测外设

我们需要查看Ubuntu中的硬件驱动层目录dev/input,在终端中输入

ls /dev/input/

我们会看到如下输出

ls /dev/input/
by-id  by-path  event0  event1  event2  event3  event4  event5  event6  js0  js1  mice  mouse0  mouse1  mouse2

创建的端口是js0,我们通过jstest来测试其是否工作

jstest /dev/input/js0

输出的结果应该为

输出的信息很清晰地告诉我们鼠标X&Y轴的状态,到时候换成手柄也就是多几个键的事情,原理是一样的,至此外设测试完成,现在我们来梳理一下控制逻辑

控制逻辑

用口头讲可能有点晦涩,直接上思维导图来解释,我们先启动joy_node手柄节点来发布外设的X&Y轴数据,然后通过简单的转换成机械臂能接收到的数据,再发布到joint_state上,move_group订阅到这些数据后对机械臂进行运动学规划,这个下次我打算从原理开始好好总结一下

 

 因此我们首先要做的第一步是启动joy_node节点,在这里我把它集成到了launch文件中,在第二个node标签中,当节点死掉了就重新生成,包名为joy,节点类型&名称:“joy_node”

<?xml version="1.0"?>
<launch>
    <!--create a node named mouse_joy to sub&pub datas,and set axis parameters about device-->
    <node pkg="joystick" type="mouse_joy" name="mouse_joy"/>
    <param name="axis_linear" value="1" type="int"/>
    <param name="axis_angular" value="0" type="int"/>
    <!--create a joy node and set some parameters about device-->
    <node respawn="true" pkg="joy" type="joy_node" name="joy_node">
        <param name="dev" value="/dev/input/js0" type="string"/>
        <param name="deadzone" value="0.12"/>
    </node>
</launch>

接下来第二步就是创建订阅者发布者来处理数据

类的创建

class TeleopJoy{
    public:
    TeleopJoy();    //define a constructor
    private:
    void callBack(const sensor_msgs::Joy::ConstPtr& joy);   //define a callback function,param is the data adress which sub recieve
    ros::NodeHandle n;
    ros::Publisher pub;
    ros::Subscriber sub;
    int i_velLinear,i_velAngular;   //device's axis input value
};

构造函数

TeleopJoy::TeleopJoy()
{
    i_velLinear = 1;
    i_velAngular = 0;
    n.param("axis_linear",i_velLinear,i_velLinear); //set vaule from param
    n.param("axis_angular",i_velAngular,i_velAngular);
    /*
        pub advertise meassage to topic named /joint_states,maximum quene:100
        meassage type is ensor_msgs::JointState    
    */
    pub = n.advertise<sensor_msgs::JointState>("/joint_states",100); 
    /*
        sub subscribe from topic named 'joy' and after receive using the callback function
        meassage type is sensor_msgs::Joy
    */
    sub = n.subscribe<sensor_msgs::Joy>("joy",100,
    &TeleopJoy::callBack,this);
}

回调函数

/*
    every time sub node receive messages will recall callback function
    it will create a new value named vel and publish it 
*/
void TeleopJoy::callBack(const sensor_msgs::Joy::ConstPtr& joy)
{
    sensor_msgs::JointState joint_state;
    joint_state.header.stamp = ros::Time::now();

    joint_state.name.resize(6); //指定name数组长度
    joint_state.position.resize(6);//指定position数组长度
    joint_state.velocity.resize(1);//指定velocity数组长度
    joint_state.effort.resize(1);//指定effort数组长度
    joint_state.name ={"joint1","joint2","joint3","joint4","joint5","joint6"};
    joint_state.position = {20.0*joy->axes[0],10.0*joy->axes[0],25.0*joy->axes[0],15.0*joy->axes[0],20.0*joy->axes[0],20.0*joy->axes[0]};//position数组的元素赋值
    joint_state.velocity[0] = 0.1*joy->axes[1];
    joint_state.effort[0] = 20.0*joy->axes[1];

    pub.publish(joint_state);   //publish the meassage
}

主函数入口

int main(int argc,char** argv)
{
    ros::init(argc,argv,"mouse_joy");
    TeleopJoy teleop_joy;   //create an object 
    ros::spin();
}

逻辑梳理

订阅者和发布者直接的逻辑都比较清晰,个人认为实现程序的关键是数据类型是否能对的上,因此在通讯之前了解话题消息类型很重要,我们要用到rostopic echo <topic name>

这是前面看到过的鼠标信息

---
header: 
  seq: 1582
  stamp: 
    secs: 1669302437
    nsecs: 962512510
  frame_id: "/dev/input/js0"
axes: [-0.31968000531196594, -0.8116175532341003]
buttons: [0]

这是joint_state消息信息

---
header: 
  seq: 4126
  stamp: 
    secs: 1669302509
    nsecs: 743610368
  frame_id: ''
name: 
  - joint1
  - joint2
  - joint3
  - joint4
  - joint5
  - joint6
position: [-6.393600106239319, -3.1968000531196594, -7.992000132799149, -4.795200079679489, -6.393600106239319, -6.393600106239319]
velocity: [-0.03451005220413208]
effort: [-6.902010440826416]

因此我们要要将接收到的两个鼠标的数据映射到至少八个(position velocity effort)数据再发布到joint_states话题上,这个时候就需要指定每个数组的长度以发送对应长度的数据,否则会报错,ps:这里的映射关系非常地不严谨,只是为了验证消息能够成功传递而设置的

sensor_msgs::JointState joint_state;
    joint_state.header.stamp = ros::Time::now();

    joint_state.name.resize(6); //指定name数组长度
    joint_state.position.resize(6);//指定position数组长度
    joint_state.velocity.resize(1);//指定velocity数组长度
    joint_state.effort.resize(1);//指定effort数组长度
    joint_state.name ={"joint1","joint2","joint3","joint4","joint5","joint6"};
    joint_state.position = {20.0*joy->axes[0],10.0*joy->axes[0],25.0*joy->axes[0],15.0*joy->axes[0],20.0*joy->axes[0],20.0*joy->axes[0]};//position数组的元素赋值
    joint_state.velocity[0] = 0.1*joy->axes[1];
    joint_state.effort[0] = 20.0*joy->axes[1];

机械臂部分

算法实现方面不是本篇的重点,这里就通过moveit_setup_assistant简单配置一下

URDF部分

首先我们要有一个描述机械臂的urdf文件,可以通过solidwroks插件导出,这里为了图方便我就用古月的了,学习资料可以在GitHub上找到

https://github.com/huchunxu/ros_exploring

配置部分

如果没有Moveit setup assistant的话要下载一个

sudo apt install ros-noetic-moveit
roslaunch moveit_setup_assistant setup_assistant.launch

接下来开始配置

 

 

 

 

 

 

 

 

 

 

 

至此机械臂的功能包就创建好了

机械臂测试

在终端输入

roslaunch arm_joystick demo.launch 

 不出意外就能在rviz里面看到机械臂模型了

鼠标控制

此时我们再启动先前写好的launch文件就可以实现鼠标控制机械臂了

roslaunch joystick mouse_joy.launch 

 效果演示

鼠标移动一下机械臂也跟着移动了

 源码部分

其实前面已经差不多贴完了,不过再贴一次吧

CPP部分

/*
    joy node publish joystick meassage,than sub acall the callback function 
    to publish vel which caculate from parameters named i_velLinear,i_velAngular
    to the topic named /turtle1/cmd_vel,turtle node receieve the meassage and 
    control turtle to move
*/

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

using namespace std;

class TeleopJoy{
    public:
    TeleopJoy();    //define a constructor
    private:
    void callBack(const sensor_msgs::Joy::ConstPtr& joy);   //define a callback function,param is the data adress which sub recieve
    ros::NodeHandle n;
    ros::Publisher pub;
    ros::Subscriber sub;
    int i_velLinear,i_velAngular;   //device's axis input value
};

TeleopJoy::TeleopJoy()
{
    i_velLinear = 1;
    i_velAngular = 0;
    n.param("axis_linear",i_velLinear,i_velLinear); //set vaule from param
    n.param("axis_angular",i_velAngular,i_velAngular);
    /*
        pub advertise meassage to topic named /joint_states,maximum quene:100
        meassage type is ensor_msgs::JointState    
    */
    pub = n.advertise<sensor_msgs::JointState>("/joint_states",100); 
    /*
        sub subscribe from topic named 'joy' and after receive using the callback function
        meassage type is sensor_msgs::Joy
    */
    sub = n.subscribe<sensor_msgs::Joy>("joy",100,
    &TeleopJoy::callBack,this);
}
/*
    every time sub node receive messages will recall callback function
    it will create a new value named vel and publish it 
*/
void TeleopJoy::callBack(const sensor_msgs::Joy::ConstPtr& joy)
{
    sensor_msgs::JointState joint_state;
    joint_state.header.stamp = ros::Time::now();

    joint_state.name.resize(6); //指定name数组长度
    joint_state.position.resize(6);//指定position数组长度
    joint_state.velocity.resize(1);//指定velocity数组长度
    joint_state.effort.resize(1);//指定effort数组长度
    joint_state.name ={"joint1","joint2","joint3","joint4","joint5","joint6"};
    joint_state.position = {20.0*joy->axes[0],10.0*joy->axes[0],25.0*joy->axes[0],15.0*joy->axes[0],20.0*joy->axes[0],20.0*joy->axes[0]};//position数组的元素赋值
    joint_state.velocity[0] = 0.1*joy->axes[1];
    joint_state.effort[0] = 20.0*joy->axes[1];

    pub.publish(joint_state);   //publish the meassage
}
int main(int argc,char** argv)
{
    ros::init(argc,argv,"mouse_joy");
    TeleopJoy teleop_joy;   //create an object 
    ros::spin();
}

Launch部分

<?xml version="1.0"?>
<launch>
    <!--create a node named mouse_joy to sub&pub datas,and set axis parameters about device-->
    <node pkg="joystick" type="mouse_joy" name="mouse_joy"/>
    <param name="axis_linear" value="1" type="int"/>
    <param name="axis_angular" value="0" type="int"/>
    <!--create a joy node and set some parameters about device-->
    <node respawn="true" pkg="joy" type="joy_node" name="joy_node">
        <param name="dev" value="/dev/input/js0" type="string"/>
        <param name="deadzone" value="0.12"/>
    </node>
</launch>

  • 0
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ROS(机器人操作系统)是一种开源框架,可以帮助我们更方便地开发和控制机器人。在ROS中,可以利用其仿真功能来模拟机械运动。 自适应控制是一种能够自动调整控制策略以适应不确定性环境的控制方法。在机械控制中,自适应控制可以在面对运动或负载参数未知或变化的情况下,使机械保持稳定的运动。 在ROS中,我们可以使用Gazebo仿真环境来模拟机械运动。首先,我们需要安装Gazebo仿真器和相应的ROS包。然后,根据我们所使用的机械模型,我们可以配置仿真环境并加载机械的URDF文件。 接下来,我们需要编写自适应控制算法。这可能涉及到传感器数据的读取、控制器的设计以及自适应更新规则的实现。在ROS中,我们可以通过创建一个控制器节点和相应的订阅和发布节点来实现这些功能。 在控制器节点中,我们可以通过订阅机械当前状态的话题来获取传感器数据,并使用自适应控制算法进行计算。然后,我们可以将所得到的控制指令通过发布话题发送给机械。 通过Gazebo仿真器的运行,我们可以观察机械运动,并实时调整自适应控制算法以优化运动轨迹和稳定性。 总之,利用ROS和Gazebo仿真器,我们可以实现机械的自适应控制运动。这种方法可以让我们更加灵活地开发和测试机械控制算法,以应对不确定性环境中的挑战。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值