使用Baxter仿真器学习一下机械臂的控制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxflamy/article/details/79608080

Baxter simulator由ReThink Robotics公司提供,是一个合理可靠的机器人模型。仿真器和实体机器人模型都有相同的ROS接口,所以在仿真器下开发的程序都可以在相应的实体机器人上快速部署。

我准备使用Baxter模型和仿真器来练习正逆运动学、角空间规划、笛卡尔规划、运动伺服和抓取的执行。

运行Baxter simulator

使用以下命令开始仿真界面:

roslaunch baxter_gazebo baxter_world.launch

启动文件如下

<?xml version="1.0" encoding="utf-8"?>
<launch>

  <!-- 这是一些控制选项, for example paused:=true -->
  <arg name="paused" default="false"/>
  <arg name="use_sim_time" default="true"/>
  <arg name="gui" default="true"/>
  <arg name="headless" default="false"/>
  <arg name="debug" default="false"/>

  <!-- 这部分内容加载电子抓手, for example left_electric_gripper:=true -->
  <arg name="left_electric_gripper" default="true"/>
  <arg name="right_electric_gripper" default="true"/>

  <!-- 向ROS参数服务器中加载URDF模型文件 -->
  <!-- This xacro will pull in baxter_base.urdf.xacro, left_end_effector.urdf.xacro,
                                           and right_end_effector.urdf.xacro
       Note: if you set this to false, you MUST have set the robot_description prior
             to launching baxter_world -->
  <arg name="load_robot_description" default="true"/>
  <param if="$(arg load_robot_description)" name="robot_description"
      command="$(find xacro)/xacro.py --inorder $(find baxter_description)/urdf/baxter.urdf.xacro gazebo:=true"/>

  <!--加载启动的仿真环境 We resume the logic in empty_world.launch, changing the name of the world to be launched -->
  <include file="$(find gazebo_ros)/launch/empty_world.launch">
    <arg name="world_name" value="$(find baxter_gazebo)/worlds/baxter.world"/>
    <arg name="debug" value="$(arg debug)" />
    <arg name="gui" value="$(arg gui)" />
    <arg name="paused" value="$(arg paused)"/>
    <arg name="use_sim_time" value="$(arg use_sim_time)"/>
    <arg name="headless" value="$(arg headless)"/>
  </include>

  <!-- 在ROS参数服务器中加载软件版本 Load the software version into the ROS Parameter Server -->
  <param name="rethink/software_version" value="1.2.0" />

  <!-- 发布世界坐标系与机器人基座之间的静态变换 Publish a static transform between the world and the base of the robot -->
  <node pkg="tf2_ros" type="static_transform_publisher" name="base_to_world" args="0 0 0 0 0 0 1 world base" />

  <!--运行一个python脚本,发送服务启动urdf机器人 Run a python script to the send a service call to gazebo_ros to spawn a URDF robot -->
   <node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" respawn="false" output="screen"
    args="-param robot_description -urdf -z 0.93 -model baxter
          -J baxter::right_s0 -0.272659
          -J baxter::right_s1 1.04701
          -J baxter::right_e0 -0.00123203
          -J baxter::right_e1 0.49262
          -J baxter::right_w0 -0.0806423
          -J baxter::right_w1 -0.0620532
          -J baxter::right_w2 0.0265941
          -J baxter::left_s0 0.192483
          -J baxter::left_s1 1.047
          -J baxter::left_e0 0.000806359
          -J baxter::left_e1 0.491094
          -J baxter::left_w0 -0.178079
          -J baxter::left_w1 -0.0610333
          -J baxter::left_w2 -0.0124707" />

  <!-- ros_control baxter launch file -->
  <include file="$(find baxter_sim_hardware)/launch/baxter_sdk_control.launch">
      <arg name="right_electric_gripper" value="$(arg right_electric_gripper)"/>
      <arg name="left_electric_gripper" value="$(arg left_electric_gripper)"/>
  </include>

</launch>

这个过程启动了带有Baxter机器人的Gazebo环境。启动过程有些慢。仿真过程取消了重力补偿的影响。
这里写图片描述
使用以下命令打开关节使能,监听运动命令

rosrun baxter_tools enable_robot.py -e

使用以下命令将机器人的手臂移动到便于运输的姿势,合起来

rosrun baxter_tools tuck_arms.py -t

这里写图片描述
使用以下命令可以把他拆开

rosrun baxter_tools tuck_arms.py -u

这里写图片描述
另一个有趣的例子是

rosrun baxter_examples joint_velocity_wobbler.py

使机器人到达一个初始命令后进行小幅度的正弦运动。

Baxter的关节和话题topic

Baxter机器人 有15个伺服自由度,包括七个左手自由度和七个右手自由度和一个脖子左右运动的自由度。头部也可以进行点头运动,但是是通过二进制命令控制的。Baxter机器人和仿真器包含三个摄像机:一个在头部,另外两个分别在左右手腕部。其它传感器包括顶点周围的声呐、每个工具法兰的短程红外线距离传感器、伺服关节的角度传感器和关节力矩传感器。

启动rviz可以让我们观察到更多的机器人信息。

在数学上,为了控制六个自由度的末端抓手的姿态,需要至少六个独立的关节自由度。然而,一旦关节施加了限制,就很难通过六个关节达到六个自由度的目标姿态了。使用七个自由度就戏剧性的提高了可操控性。同时,这引入了另一项挑战,那就是运动学求解,因为手臂是运动学冗余的。越来越多的工业机器人提供了七个自由度可控关节的机器人,因此运动学冗余求解也越来越重要。

Baxter的另一项运动学挑战是机器人没有球形腕部关节,即末端的三个关节轴不是相交于一点的。球形腕部关节求解运动学逆解的解析解时比较方便。而Baxter机器人最后两个旋转轴相交于一点,但是前臂旋转轴并不与他们相交,有一定的偏移。由于偏差很小,有时可以忽略,近似成球形关节,计算运动学逆解,可以快速地得到一个运动学逆解。

rostopic list可以查看话题

Baxter的抓手

Baxter仿真模型中的抓手是电子的,平口钳抓手。与ROS进行通信是采用发布和订阅消息的方式。抓手的状态发布在/robot/endeffector/rightgripper/state/robot/endeffector/leftgripper/state话题上,使用的消息类型是baxtercoremsgs/EndeffectorState。该消息定义定义了多个助记符和16个字段。这样,描述抓手状态的值有位置和力,用来检测一个物体是否被抓住或者抓手是空的。

为了控制抓手,需要向话题/robot/endeffector/rightgripper/command and /robot/endeffector/leftgripper/command发布命令,发布消息的类型是baxtercoremsgs/EndEffectorCommand。这个消息包含了12个助记字符串用来与抓手和命令消息的五个作用域沟通。

就目前而言,简单地命令夹具处于位置模式并且命令完全打开(100)或完全关闭(0)的位置就足够了,这对应于44mm的抛光。 如果夹爪之间夹有可抓物体(既不太宽也不太窄),指挥完全关闭的运动将导致夹爪在达到完全关闭位置之前失速。 这可以通过检查夹具状态来检测。

为了简化抓取器接口,在同名包中定义了一个simple_baxter_gripper_interface库。 该库定义了一个类BaxterGripper,它为左右夹具设置发布者和订阅者。 夹具命令消息定义并填充:

// baxter_gripper:   a library to simplify gripper I/O
// wsn, August, 2016
#include<ros/ros.h>
#include<simple_baxter_gripper_interface/simple_baxter_gripper_interface.h>

BaxterGripper::BaxterGripper(ros::NodeHandle* nodehandle): nh_(*nodehandle) {
    gripper_cmd_open.id = 65538;
    gripper_cmd_open.command ="go";
    //gripper_cmd_open.args = "{'position': 100.0}'"; //oops
    gripper_cmd_open.args = "{\"position\": 100.0}";
    gripper_cmd_open.sender = "gripper_publisher";
    gripper_cmd_open.sequence = 2;

    gripper_cmd_close.id = 65538;
    gripper_cmd_close.command ="go";
    //gripper_cmd_close.args = "{'position': 0.0}'"; //oops
    gripper_cmd_close.args = "{\"position\": 0.0}";
    gripper_cmd_close.sender = "gripper_publisher"; 
    gripper_cmd_close.sequence = 3;

    gripper_pos_filter_val_ = 0.2;
    right_gripper_pos_ = -0.2;
    left_gripper_pos_ = -10.2;
    initializeSubscribers(); 
    initializePublishers();
}
void BaxterGripper::initializeSubscribers()
{
    ROS_INFO("Initializing Subscribers");
    gripper_subscriber_right_ = nh_.subscribe("/robot/end_effector/right_gripper/state", 1, &BaxterGripper::right_gripper_CB,this); 
    gripper_subscriber_left_ = nh_.subscribe("/robot/end_effector/left_gripper/state", 1, &BaxterGripper::left_gripper_CB,this);     
}

void BaxterGripper::initializePublishers()
{
    ROS_INFO("Initializing Publishers");
    gripper_publisher_right_ = nh_.advertise<baxter_core_msgs::EndEffectorCommand>("/robot/end_effector/right_gripper/command", 1, true); 
    gripper_publisher_left_ = nh_.advertise<baxter_core_msgs::EndEffectorCommand>("/robot/end_effector/left_gripper/command", 1, true); 
}
void BaxterGripper::right_gripper_CB(const baxter_core_msgs::EndEffectorState& gripper_state) {
     //low-pass filter the gripper position for more reliable threshold tests
    right_gripper_pos_ = (1.0- gripper_pos_filter_val_)*right_gripper_pos_ + gripper_pos_filter_val_*gripper_state.position; 
} 
void BaxterGripper::left_gripper_CB(const baxter_core_msgs::EndEffectorState& gripper_state) {
     //low-pass filter the gripper position for more reliable threshold tests
    left_gripper_pos_ = (1.0- gripper_pos_filter_val_)*left_gripper_pos_ + gripper_pos_filter_val_*gripper_state.position; 
} 

位置反馈可能会出现噪声,所以在回调函数中使用低通滤波器。
控制抓手的例子如下:

// baxter_gripper_lib_test_main: 
// wsn, August, 2016
// illustrates use of library/class BaxterGripper for simplified Baxter gripper I/O

#include<ros/ros.h>
#include<simple_baxter_gripper_interface/simple_baxter_gripper_interface.h>
//using namespace std;

int main(int argc, char** argv) {
    ros::init(argc, argv, "baxter_gripper_test_main"); // name this node 
    ros::NodeHandle nh; //standard ros node handle   

    //instantiate a BaxterGripper object to do gripper I/O
    BaxterGripper baxterGripper(&nh);
    //wait for filter warm-up on right-gripper position
    while (baxterGripper.get_right_gripper_pos()<-0.5) {
        ros::spinOnce();
        ros::Duration(0.01).sleep();
        ROS_INFO("waiting for right gripper position filter to settle; pos = %f", baxterGripper.get_right_gripper_pos());
    }

    ROS_INFO("closing right gripper");
    baxterGripper.right_gripper_close();
    ros::Duration(1.0).sleep();
    ROS_INFO("opening right gripper");
    baxterGripper.right_gripper_open();
    ros::spinOnce();
    ROS_INFO("right gripper pos = %f; waiting for pos>95", baxterGripper.get_right_gripper_pos());
    while (baxterGripper.get_right_gripper_pos() < 95.0) {
        baxterGripper.right_gripper_open();
        ros::spinOnce();
        ROS_INFO("gripper pos = %f", baxterGripper.get_right_gripper_pos());
        ros::Duration(0.01).sleep();
    }

    ROS_INFO("closing left gripper");
    baxterGripper.left_gripper_close();
    ros::Duration(1.0).sleep();
    ROS_INFO("opening left gripper");
    baxterGripper.left_gripper_open();

    ROS_INFO("closing right gripper");
    baxterGripper.right_gripper_close();
    ros::spinOnce();
    ROS_INFO("right gripper pos = %f; waiting for pos<90", baxterGripper.get_right_gripper_pos());
    while (baxterGripper.get_right_gripper_pos() > 90.0) {
        baxterGripper.right_gripper_close();
        ros::spinOnce();
        ROS_INFO("gripper pos = %f", baxterGripper.get_right_gripper_pos());
        ros::Duration(0.01).sleep();
    }

    return 0;
}

可以使用

rosrun simple_baxter_gripper_interfacbaxter_gripper_lib_test_main

查看效果。

头部控制

只需要发布一个头部角度命令:

#include <ros/ros.h>
#include <baxter_core_msgs/HeadPanCommand.h>
using namespace std;

int main(int argc, char **argv) {
    ros::init(argc, argv, "baxter_head_pan"); 
    ros::NodeHandle n; 
    //create a publisher to send commands to Baxter's head pan
    ros::Publisher head_pan_pub = n.advertise<baxter_core_msgs::HeadPanCommand>("/robot/head/command_head_pan", 1);

    baxter_core_msgs::HeadPanCommand headPanCommand; //message type for head-pan control
    headPanCommand.target = 0.0;
    headPanCommand.enable_pan_request=1;
    //prompt user for amplitude and frequency of oscillating head pan
    double amp,freq;
    cout<<"enter pan amplitude (rad): ";
    cin>>amp;
    cout<<"enter pan freq (Hz): ";
    cin>>freq;
    double dt = 0.01;
    ros::Rate timer(1/dt);
    double phase=0.0;
    double theta;

    // oscillate head pan indefinitely
    while (ros::ok()) 
    {
        phase+= M_PI*2.0*freq*dt;
        if (phase>2.0*M_PI) phase-= 2.0*M_PI;
        theta = amp*sin(phase);
        headPanCommand.target = theta;
        head_pan_pub.publish(headPanCommand);
        timer.sleep();
    }
}

可以使用

rosrun baxter_head_pan baxter_head_pan

观察效果

关节控制命令

Baxter仿真器订阅话题/robot/limb/right/jointcommand/robot/limb/left/jointcommand来接收关节位置命令控制左右手臂。消息类型是/baxter_core_msgs/JointCommand。使用以下命令可以查看消息类型

rosmsg show baxter_core_msgs/JointCommand

结果是

int32 POSITION_MODE=1
int32 VELOCITY_MODE=2
int32 TORQUE_MODE=3
int32 RAW_POSITION_MODE=4
int32 mode
float64[] command
string[] names

位置模式下,关节角度控制命令的发布方式如图
这里写图片描述

为了灵活的插入和执行轨迹,需要使用action server。

启动轨迹插值动作服务器(左右手):

rosrun baxter_trajectory_streamer rt_arm_as
rosrun baxter_trajectory_streamer left_arm_as

服务器接收并执行轨迹,等待从action客户端接收目标位置。
使用以下命令可以发送一个姿态命令

rosrun baxter_trajectory_streamer pre_pose

使用关节轨迹控制器

……

猜你喜欢

转载自blog.csdn.net/wxflamy/article/details/79608080