ROS学习笔记16 —— 控制真实机械臂的action(实例大集合)


MoveIt! Setup Assistant 配置完的文件修改,参考:传送门

1. 了解整体概况

在这里插入图片描述

  • Driver:包括Action ServerJoint_state publisher,接收Moveit下发的数据,反馈机器人状态

  • Moveit:ActionClient与Driver的Action Server对接,Joint_state subscriber接收Joint_state publisher反馈信息,MoveIT function负责任务操作

    为了实现客户端和服务器进行通信,ROS定义了一些标准的通信消息,用于规范两者的工作,包括目标(Goal),反馈(Feedback)和结果(Result)。

  1. Goal:目标是由ActionClient发送到ActionServer的一种通讯消息,其包含的信息为控制对象需要完成的动作
  2. Feedback:反馈的作用在于提供给ActionServer一种用于传递任务执行状况给ActionClient的方法
  3. Result:在完成任务的执行后,ActionServer会发送将结果信息到ActionClient,其与反馈不同的地方在于,在整个任务的执行过程中只发送一次

ros wiki案例

   1 #include <ros/ros.h>
   2 #include <actionlib/server/simple_action_server.h>
   3 #include <actionlib_tutorials/FibonacciAction.h>
   4 
   5 class FibonacciAction
   6 {
   7 protected:
   8 
   9   ros::NodeHandle nh_;
  10   actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs.
  11   std::string action_name_;
  12   // create messages that are used to published feedback/result
  13   actionlib_tutorials::FibonacciFeedback feedback_;
  14   actionlib_tutorials::FibonacciResult result_;
  15 
  16 public:
  17 
  18   FibonacciAction(std::string name) :
  19     as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false),
  20     action_name_(name)
  21   {
  22     as_.start();
  23   }
  24 
  25   ~FibonacciAction(void)
  26   {
  27   }
  28 
  29   void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal)
  30   {
  31     // helper variables
  32     ros::Rate r(1);
  33     bool success = true;
  34 
  35     // push_back the seeds for the fibonacci sequence
  36     feedback_.sequence.clear();
  37     feedback_.sequence.push_back(0);
  38     feedback_.sequence.push_back(1);
  39 
  40     // publish info to the console for the user
  41     ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
  42 
  43     // start executing the action
  44     for(int i=1; i<=goal->order; i++)
  45     {
  46       // check that preempt has not been requested by the client
  47       if (as_.isPreemptRequested() || !ros::ok())
  48       {
  49         ROS_INFO("%s: Preempted", action_name_.c_str());
  50         // set the action state to preempted
  51         as_.setPreempted();
  52         success = false;
  53         break;
  54       }
  55       feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
  56       // publish the feedback
  57       as_.publishFeedback(feedback_);
  58       // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes
  59       r.sleep();
  60     }
  61 
  62     if(success)
  63     {
  64       result_.sequence = feedback_.sequence;
  65       ROS_INFO("%s: Succeeded", action_name_.c_str());
  66       // set the action state to succeeded
  67       as_.setSucceeded(result_);
  68     }
  69   }
  70 
  71 
  72 };
  73 
  74 
  75 int main(int argc, char** argv)
  76 {
  77   ros::init(argc, argv, "fibonacci");
  78 
  79   FibonacciAction fibonacci("fibonacci");
  80   ros::spin();
  81 
  82   return 0;
  83 }

前提:

  1. 底层驱动已完成
  2. 机械臂可正常执行

假设:

  1. 添加路径点函数:add_wayPoint()
  2. 按轨迹移动函数:trackMove()

改造驱动:

  • 使用ROS封装驱动
  • 加入action服务端代码
    1. CMakeLists.exepackage.xml中添加相关以来

      find_package(catkin REQUIRED COMPONENTS
      
        actionlib    
       #action的本质是基于消息的,因此,还需要添加moveit的相关消息
      moveit_msgs
      )
      
      catkin_package(
        INCLUDE_DIRS include
      
        CATKIN_DEPENDS   actionlib  moveit_msgs
      )
      
      <build_depend>actionlib</build_depend>
      <build_depend>moveit_msgs</build_depend>
      
      <exec_depend>actionlib</exec_depend>
      <exec_depend>moveit_msgs</exec_depend>
      
    2. 添加action server头文件

      //action服务端的相关定义,请加入到驱动节点的头文件中
      #include "actionlib/server/action_server.h"    
      
      //action服务端的目标控制句柄定义,与接收的目标相关联后,可以用来实现action的信息反馈等操作       
      #include "actionlib/server/server_goal_handle.h" 
      
    3. 定义server对象

      //定义action服务端
      actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>  as_;    
      
      //定义action服务端目标控制句柄
      actionlib::ServerGoalHandle<control_msgs::FollowJointTrajectoryAction> goal_handle_; 
      
       //用来反馈action目标的执行情况,客户端由此可以得知服务端是否执行成功了
      control_msgs::FollowJointTrajectoryResult result_;         
      
    4. 初始化服务端对象

      LwrDriver::LwrDriver():
        as_(nh, "lwr/follow_joint_trajectory",
            boost::bind(&LwrDriver::goalCB, this, _1),
            false)
      {
        as_.start();       //action服务端启动
      
      }
      // nh:action所在ros节点的节点句柄
      // controllers.yaml中的name和action_ns共同决定了客户端action的名字
      // boost::bind(&LwrDriver::goalCB, this,_1)固定用法,不再深究,绑定了LwrDriver::goalCB函数,goalCB()是LwrDriver类成员函数,此处表示其是一个接受不action目标的回调函数。当action客户端请求一个动作时,这个动作被认为是一个目标,传递给action服务端,此时就moveit的action客户端而言,这个目标就是机械臂运动轨迹,服务端接收到目标后,会自动回调goalCB这个函数,而目标(轨迹)会作为参数传递进来。
      
    5. 回调函数goalCB()

//转自:https://blog.csdn.net/lingchen2348/article/details/80379166
void LwrDriver::goalCB( actionlib::ServerGoalHandle<control_msgs::FollowJointTrajectoryAction> gh)
{

// 复制一个副本,防止破坏原数据
  actionlib::ActionServer<control_msgs::FollowJointTrajectoryAction>::Goal goal = *gh.getGoal();    //make a copy that we can modify

 //将之前定义的句柄与传入的action目标绑定在一起,
 goal_handle_ = gh;   


//提取正确数据,重新进行映射
  reorder_traj_joints(goal.trajectory);

	//添加路点函数
  Add_waypoint(goal.trajectory);


	 //执行轨迹函数
	ifTrackMove()//假设轨迹成功后返回值为1,失败时返回值为0
	{
	 //告诉客户端成功了
	  goal_handle_.setAccepted();    
	  result_.error_code = result_.SUCCESSFUL;
	
	  goal_handle_.setSucceeded(result_);
	}

}

2.实例

直接转我伟哥的,他的就是我的/手动滑稽

框架

MyRobot类:

/*
1.主要实现使控制器管理器controller manager(以及控制器管理器内的控制器)能够访问机器人的关节状态以及机器人的命令;当控制器管理器运行时,控制器将读取机器人中的pos,vel和eff变量,并将所需的命令写入cmd变量。
2.确保pos,vel和eff变量始终具有最新的关节状态joint states是你的工作,你还需要确保写入cmd变量的内容由机器人执行。 为此,你可以向机器人类添加read()和write()函数
*/
#include <hardware_interface/joint_command_interface.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/robot_hw.h>

class MyRobot : public hardware_interface::RobotHW//继承hardware_interface::RobotHW类
{
public:
  MyRobot() 
 { 
   // connect and register the joint state interface
   hardware_interface::JointStateHandle state_handle_a("A", &pos[0], &vel[0], &eff[0]);
   jnt_state_interface.registerHandle(state_handle_a);//读状态

   hardware_interface::JointStateHandle state_handle_b("B", &pos[1], &vel[1], &eff[1]);
   jnt_state_interface.registerHandle(state_handle_b);

   registerInterface(&jnt_state_interface);

   // connect and register the joint position interface
   hardware_interface::JointHandle pos_handle_a(jnt_state_interface.getHandle("A"), &cmd[0]);//写命令
   jnt_pos_interface.registerHandle(pos_handle_a);

   hardware_interface::JointHandle pos_handle_b(jnt_state_interface.getHandle("B"), &cmd[1]);
   jnt_pos_interface.registerHandle(pos_handle_b);

   registerInterface(&jnt_pos_interface);
  }

private:
  hardware_interface::JointStateInterface jnt_state_interface;
  hardware_interface::PositionJointInterface jnt_pos_interface;
  double cmd[2];
  double pos[2];
  double vel[2];
  double eff[2];
};

main函数

main()
{
  MyRobot robot;
  controller_manager::ControllerManager cm(&robot);

  while (true)
  {
     robot.read();
     cm.update(robot.get_time(), robot.get_period());
     robot.write();
     sleep();
  }
}

controllers.yaml

controller_list:
  - name: /dh_arm_controller 
    action_ns: "follow_joint_trajectory"
    type: FollowJointTrajectory
    default: true
    joints:
      - arm_joint_1
      - arm_joint_2
      - arm_joint_3
      - arm_joint_4


joints:
      - arm_joint_1
      - arm_joint_2
      - arm_joint_3
      - arm_joint_4


实例1

  • 文件级:
    ├── CMakeLists.txt
    ├── config
    │ └── dh_arm_control.yaml
    ├── include
    │ └── dhrobot_controller
    │ └── arm_hardware_interface.h
    ├── launch
    │ └── arm_ros_control.launch
    ├── package.xml
    └── src
    └── arm_hardware_interface.cpp

  • dh_arm_control.yaml

controller_list:
  - name: /dh_arm_controller 
    action_ns: "follow_joint_trajectory"
    type: FollowJointTrajectory
    default: true
    joints:
      - arm_joint_1
      - arm_joint_2
      - arm_joint_3
      - arm_joint_4


joints:
      - arm_joint_1
      - arm_joint_2
      - arm_joint_3
      - arm_joint_4


  • arm_hardware_interface.h


#ifndef ARM_HW_INTERFACE
#define ARM_HW_INTERFACE

#include <ros/ros.h>
#include <urdf/model.h>
#include <pthread.h>
#include <time.h>

#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>

#include <std_msgs/Float64.h>
#include <sensor_msgs/JointState.h>
#include <dynamixel_msgs/JointState.h>

#include <hardware_interface/joint_command_interface.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/robot_hw.h>

#include <controller_manager/controller_manager.h>
#include <controller_manager_msgs/ListControllers.h>

class ArmHWInterface : public hardware_interface::RobotHW
{
public:
    ArmHWInterface();
    void read(const dynamixel_msgs::JointStateConstPtr &msg);
    void publishCmd();
    ros::NodeHandle getnode();

private:
    hardware_interface::JointStateInterface jnt_state_interface;
    hardware_interface::PositionJointInterface jnt_cmd_interface;
    double cmd[5];
    double pos[5];
    double vel[5];
    double eff[5];

    controller_manager_msgs::ListControllersRequest list_req;
    controller_manager_msgs::ListControllersResponse list_resp;

    bool loaded_flag;

    ros::NodeHandle _n;
    ros::Publisher pub_cmd[5];
    std_msgs::Float64 cmd_msg[5];
    ros::Time start_time_;
    ros::Duration start_dur_;

    ros::Subscriber sub_js[5];
    ros::ServiceClient client_controller_list;

};

#endif


  • arm_hardware_interface.cpp


#include "dhrobot_controller/arm_hardware_interface.h"

boost::mutex Arm_io_mutex;

ArmHWInterface::ArmHWInterface()
{
    for(int i=0; i<4; i++)
    {
        std::string joint_cmd_name="arm_joint_";
        std::string joint_state_name="arm_joint_";
        std::string joint_num=boost::lexical_cast<std::string>(i+1);
        joint_cmd_name.append(joint_num);
        joint_state_name.append(joint_num);
        joint_cmd_name.append("_controller/command");
        joint_state_name.append("_controller/state");
        pub_cmd[i]=_n.advertise<std_msgs::Float64>(joint_cmd_name, 1);
        sub_js[i]=_n.subscribe(joint_state_name, 1, &ArmHWInterface::read, this);
        client_controller_list=_n.serviceClient<controller_manager_msgs::ListControllers>("/controller_manager/list_controllers");
        loaded_flag=false;
    }

    for(int i=0; i<4; i++)
    {
        std::string joint_name="arm_joint_";
        std::string joint_num=boost::lexical_cast<std::string>(i+1);
        joint_name.append(joint_num);
        hardware_interface::JointStateHandle jnt_state_handle_tmp(joint_name, &pos[i], &vel[i], &eff[i]);
        jnt_state_interface.registerHandle(jnt_state_handle_tmp);
    }

    registerInterface(&jnt_state_interface);

    for(int i=0; i<4; i++)
    {
        std::string joint_name="arm_joint_";
        std::string joint_num=boost::lexical_cast<std::string>(i+1);
        joint_name.append(joint_num);
        hardware_interface::JointHandle jnt_handle_tmp(jnt_state_interface.getHandle(joint_name), &cmd[i]);
        jnt_cmd_interface.registerHandle(jnt_handle_tmp);
    }

    registerInterface(&jnt_cmd_interface);

    start_time_=ros::Time::now();
    start_dur_.operator +=(ros::Duration(3));
}

void ArmHWInterface::publishCmd()
{
    if(ros::Time::now()-start_time_<start_dur_)
        return;
    for(int i=0; i<4; i++)
    {
        cmd_msg[i].data=cmd[i];
        pub_cmd[i].publish(cmd_msg[i]);
    }
}

void ArmHWInterface::read(const dynamixel_msgs::JointStateConstPtr &msg)
{
    if(msg->motor_ids.size()<=0)
    {
        return;
    }
    if(msg->motor_ids[0]>6 || msg->motor_ids[0]<0)
    {
        return;
    }
    int msg_num=msg->motor_ids[0];
    double bm=msg->current_pos-pos[msg_num];
    boost::mutex::scoped_lock lock(Arm_io_mutex);
    pos[msg_num]=msg->current_pos;
    if(ros::Time::now()-start_time_>start_dur_)
    {
        if(bm>=0)
            vel[msg_num]=msg->velocity;
        else
            vel[msg_num]=-1*msg->velocity;
    }
    else
        vel[msg_num]=0;

    if(fabs(vel[msg_num])<1.2)
        vel[msg_num]=0;

    eff[msg_num]=msg->load;
}

ros::NodeHandle ArmHWInterface::getnode()
{
    return _n;
}

static void timespecInc(struct timespec &tick, int nsec)
{
  int SEC_2_NSEC = 1e+9;
  tick.tv_nsec += nsec;
  while (tick.tv_nsec >= SEC_2_NSEC)
  {
    tick.tv_nsec -= SEC_2_NSEC;
    ++tick.tv_sec;
  }
}

void* update_loop(void* threadarg)
{
    controller_manager::ControllerManager *c=(controller_manager::ControllerManager *)threadarg;
    ros::Rate r(50);
    ros::Duration d(0.02);

    while(ros::ok())
    {
        boost::mutex::scoped_lock lock(Arm_io_mutex);
        c->update(ros::Time::now(), d);
        lock.unlock();
        r.sleep();
    }
}

int main(int argc, char** argv)
{
    ros::init(argc,argv,"Dhrobot Arm_hardware_interface", ros::init_options::AnonymousName);
    ArmHWInterface c1;


    controller_manager::ControllerManager cm(&c1);
    pthread_t tid;
    pthread_create(&tid, NULL, update_loop, (void *)&cm);


    ROS_INFO("Arm bring up successfully");
    // loop
    ros::Rate r(50);
    while(ros::ok())
    {
        boost::mutex::scoped_lock lock(Arm_io_mutex);
        c1.publishCmd();
        lock.unlock();
        ros::spinOnce();
        r.sleep();
    }
    return 0;
}


  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(dhrobot_controller)


find_package(catkin REQUIRED COMPONENTS
  actionlib
  urdf
  cmake_modules
  control_msgs
  control_toolbox
  controller_manager
  hardware_interface
  joint_limits_interface
  roscpp
  sensor_msgs
  std_msgs
  trajectory_msgs
  transmission_interface
)

catkin_package(


)

include_directories(
  include/
  ${catkin_INCLUDE_DIRS}
)

add_executable(arm_hardware_interface src/arm_hardware_interface.cpp)
target_link_libraries(arm_hardware_interface ${catkin_LIBRARIES})
                      
  • package.xml
<?xml version="1.0"?>
<package>
  <name>dhrobot_controller</name>
  <version>1.0.0</version>
  <description>The dhrobot_controller package</description>


  <maintainer email="[email protected]">wxw</maintainer>
  <license>BSD</license>



  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>actionlib</build_depend>
  <build_depend>urdf</build_depend>
  <build_depend>cmake_modules</build_depend>
  <build_depend>control_msgs</build_depend>
  <build_depend>control_toolbox</build_depend>
  <build_depend>controller_manager</build_depend>
  <build_depend>hardware_interface</build_depend>
  <build_depend>joint_limits_interface</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>sensor_msgs</build_depend>
  <build_depend>std_msgs</build_depend>
  <build_depend>trajectory_msgs</build_depend>
  <build_depend>transmission_interface</build_depend>
  <run_depend>actionlib</run_depend>
  <run_depend>urdf</run_depend>
  <run_depend>cmake_modules</run_depend>
  <run_depend>control_msgs</run_depend>
  <run_depend>control_toolbox</run_depend>
  <run_depend>controller_manager</run_depend>
  <run_depend>hardware_interface</run_depend>
  <run_depend>joint_limits_interface</run_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>sensor_msgs</run_depend>
  <run_depend>std_msgs</run_depend>
  <run_depend>trajectory_msgs</run_depend>
  <run_depend>transmission_interface</run_depend>


  <!-- The export tag contains other, unspecified, tags -->
  <export>
    <!-- Other tools can request additional information be placed here -->

  </export>
</package>
  • arm_ros_control.launch
<launch>    
<param name="robot_description" command="$(find xacro)/xacro --inorder '$(find dhrobot_description)/urdf/dhrobot.urdf.xacro'" />

  <node name="arm_hardware_interface" pkg="dhrobot_controller" type="arm_hardware_interface" output="screen"/>
  
  <rosparam file="$(find dhrobot_controller)/config/dh_arm_control.yaml" command="load"/>
  <node name="dh_arm_controller_spawner" pkg="controller_manager" type="controller_manager" args="spawn dh_arm_controller" respawn="false" output="screen"/>
</launch>

实例2

server端:

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <control_msgs/FollowJointTrajectoryActionGoal.h>
#include <control_msgs/FollowJointTrajectoryActionResult.h>
#include <control_msgs/FollowJointTrajectoryAction.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
 
using namespace std;
 
class FollowJointTrajectoryAction
{
public:
 
 FollowJointTrajectoryAction(std::string name) :
   as_(nh_, name, false),
   action_name_(name)
 {
    as_.registerGoalCallback(boost::bind(&FollowJointTrajectoryAction::goalCB, this));
    as_.registerPreemptCallback(boost::bind(&FollowJointTrajectoryAction::preemptCB, this));
    as_.start();
    ROS_INFO("action start");
 }
   
 ~FollowJointTrajectoryAction(void)
  {
  }
  
 void goalCB()
 {
     ROS_INFO("goal is receive"); 
    if(as_.isNewGoalAvailable())
     {
	  
     }
    else
     {
       ROS_INFO("goal is not available"); 
     }
	control_msgs::FollowJointTrajectoryResult result;
	result.error_code = 0;
	as_.setSucceeded(result);
 } 
 
 void preemptCB()
 {
   ROS_INFO("%s: Preempted", action_name_.c_str());
   // set the action state to preempted
   as_.setPreempted();
 }
 
  protected: 
  ros::NodeHandle nh_;
  actionlib::SimpleActionServer<control_msgs::FollowJointTrajectoryAction> as_;
  std::string action_name_;
   
};

joint_state_publish:

    <!-- publish joint states -->
  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
    <param name="/use_gui" value="false"/>
    <rosparam param="/source_list">[<span style="color:#ff0000;">/move_group/robothand_controller_joint_states</span>]</rosparam>
  </node>

实例3

controller.yaml

controller_list:
  - name: left_arm_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    default: true
    joints:
      - left_shoulder_stevo_to_axis
      - left_shoulder_stevo_lift_to_axis
      - left_big_arm_up_to_axis
      - left_small_arm_up_to_axis
      - left_wrist_run_stevo_to_axis
  - name: rigth_arm_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    default: true
    joints:
      - right_shoulder_stevo_to_axis
      - right_shoulder_stevo_lift_to_axis
      - right_big_arm_up_to_axis
      - right_small_arm_up_to_axis
      - right_wrist_run_stevo_to_axis
  - name: right_gripper_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    default: true
    joints:
      - right_hand_run_stevo_to_right_hand_run_stevo_axis
  - name: left_gripper_controller
    action_ns: follow_joint_trajectory
    type: FollowJointTrajectory
    default: true
    joints:
      - left_hand_run_stevo_to_left_hand_run_stevo_axis

JointTrajectory msg结构的查看:rosmsg show JointTrajectory

joint.py

from ros_arduino_msgs.srv import *
class Joint:

    ## @brief Constructs a Joint instance.
    ##
    ## @param servoNum The servo number.
    ## 
    ## @param name The joint name.
    def __init__(self, name, servoNum, range):
        self.name = name #关节名称
        self.servoNum=servoNum #对应的舵机编号
        self.range=range #舵机的控制范围,这里是0~180度

        self.position = 0.0 
        self.velocity = 0.0
        self.last = rospy.Time.now()
        ## @brief Set the current position.
    def setCurrentPosition(self):
        rospy.wait_for_service('/arduino/servo_write')
        try:
            servo_write=rospy.ServiceProxy('/arduino/servo_write',ServoWrite)
            servo_write(self.servoNum,self.position)
        except rospy.ServiceException, e:
            print "Service call failed: %s"%e  

follow_controller.py 主要的驱动

初始化joints列表,同时启动action Server:

def __init__(self, name):
        self.name = name

        # rates
        self.rate = 20.0

        # left Arm jonits list
        self.left_shoulder_stevo_to_axis=Joint(left_shoulder_stevo_to_axis,6,PI)
        self.left_shoulder_stevo_lift_to_axis=Joint(left_shoulder_stevo_lift_to_axis,7,PI)
        self.left_big_arm_up_to_axis=Joint(left_big_arm_up_to_axis,8,PI)
        self.left_small_arm_up_to_axis=Joint(left_small_arm_up_to_axis,9,PI)
        self.left_wrist_run_stevo_to_axis=Joint(left_wrist_run_stevo_to_axis,10,PI)

        self.joints=list()
        self.joints.append(left_shoulder_stevo_to_axis)
        self.joints.append(left_shoulder_stevo_lift_to_axis)
        self.joints.append(left_big_arm_up_to_axis)
        self.joints.append(left_small_arm_up_to_axis)
        self.joints.append(left_wrist_run_stevo_to_axis)


        # left hand joint
        self.left_hand_run_stevo_to_left_hand_run_stevo_axis=Joint(left_hand_run_stevo_to_left_hand_run_stevo_axis,11,PI)
        self.joints.append(left_hand_run_stevo_to_left_hand_run_stevo_axis)

        # right Arm jonits
        self.right_shoulder_stevo_to_axis=Joint(right_shoulder_stevo_to_axis,0,PI)
        self.right_shoulder_stevo_lift_to_axis=Joint(right_shoulder_stevo_lift_to_axis,1,PI)
        self.right_big_arm_up_to_axis=Joint(right_big_arm_up_to_axis,2,PI)
        self.right_small_arm_up_to_axis=Joint(right_small_arm_up_to_axis,3,PI)
        self.right_wrist_run_stevo_to_axis=Joint(right_wrist_run_stevo_to_axis,4,PI)

        self.joints.append(right_shoulder_stevo_to_axis)
        self.joints.append(right_shoulder_stevo_lift_to_axis)
        self.joints.append(right_big_arm_up_to_axis)
        self.joints.append(right_small_arm_up_to_axis)
        self.joints.append(right_wrist_run_stevo_to_axis)

        # left hand joint
        self.right_hand_run_stevo_to_right_hand_run_stevo_axis=Joint(right_hand_run_stevo_to_right_hand_run_stevo_axis,5,PI)
        self.joints.append(right_hand_run_stevo_to_right_hand_run_stevo_axis)        

        # set the left arm back to the resting position
        rospy.loginfo("set the left arm back to the resting position")
        self.left_shoulder_stevo_to_axis.setCurrentPosition(PI/2)
        self.left_shoulder_stevo_lift_to_axis.setCurrentPosition(PI/2)
        self.left_big_arm_up_to_axis.setCurrentPosition(PI/2)
        self.left_small_arm_up_to_axis.setCurrentPosition(PI/2)
        self.left_wrist_run_stevo_to_axis.setCurrentPosition(PI/2)
        # set the right arm back t

actionCb函数(Action Service的回调函数,收到msg后就会调用该函数)

def actionCb(self, goal):
        rospy.loginfo(self.name + ": Action goal recieved.")
        traj = goal.trajectory 

        if not traj.points:#判断收到的消息是否为空
            msg = "Trajectory empy."
            rospy.logerr(msg)
            self.server.set_aborted(text=msg)
            return  

        try:
            indexes = [traj.joint_names.index(joint.name) for joint in self.joints]#按照joints列表的顺序对traj的数据进行排序,把排序数据放到indexes中
        except ValueError as val:
            msg = "Trajectory invalid."
            rospy.logerr(msg)
            self.server.set_aborted(text=msg)
            return

        start = traj.header.stamp#当前的时间戳
        if start.secs == 0 and start.nsecs == 0:
            start = rospy.Time.now()

        r = rospy.Rate(self.rate)
        for point in traj.points:            
            desired = [ point.positions[k] for k in indexes ]#期望的控制点
            for i in indexes
                self.joints[i].position=desired[i]#控制点对应的舵机的位置
                self.joints[i].setCurrentPosition()#发送舵机的控制命令

            while rospy.Time.now() + rospy.Duration(0.01) < start:#如果当前时间小于舵机这个点预期完成时间,则等待
                rospy.sleep(0.01)                        

        rospy.loginfo(self.name + ": Done.")

参考文献:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章