实现机械臂抓取Marker,并放置到指定位置
1. Version-1 Program
- 实现了kinova的end effector随Marker的移动而移动
- 仍需改进的地方
(1)代码结构凌乱,可以引入类来提高代码的整洁与可读性。
(2)实现kinova抓取Marker并可以将其放置到指定位置的demo
#include "ros/ros.h"
#include<iostream> //C++标准输入输出库
#include <vector>
#include "std_msgs/String.h"
#include "geometry_msgs/PoseStamped.h"
#include <kinova_msgs/ArmPoseActionGoal.h> // 注意格式源文件名字为ArmPose.action
#include <ros/ros.h>
#include <kinova_driver/kinova_ros_types.h>
#include <actionlib/client/simple_action_client.h>
#include <kinova_msgs/SetFingersPositionAction.h>
#include <kinova_msgs/ArmPoseAction.h>
#include <kinova_msgs/HomeArm.h>
#include <kinova_msgs/ArmJointAnglesAction.h>
const int FINGER_MAX = 6400;
bool cartesian_pose_client(float x, float y, float z, float qx, float qy, float qz, float qw)//四元数
{
actionlib::SimpleActionClient <kinova_msgs::ArmPoseAction> *client = new actionlib::SimpleActionClient<kinova_msgs::ArmPoseAction>(
"/j2n6s300_driver/pose_action/tool_pose");//取的主题
client->waitForServer();
kinova_msgs::ArmPoseGoal pose_goal;//注意形式ArmPose.action
pose_goal.pose.header.frame_id = "j2n6s300_link_base";
pose_goal.pose.pose.position.x = x;
pose_goal.pose.pose.position.y = y;
pose_goal.pose.pose.position.z = z;
pose_goal.pose.pose.orientation.x = qx;
pose_goal.pose.pose.orientation.y = qy;
pose_goal.pose.pose.orientation.z = qz;
pose_goal.pose.pose.orientation.w = qw;
client->sendGoal(pose_goal);
if (client->waitForResult(ros::Duration(150.0)))//延时得高机械臂不会发送,只能自己检测坐标,奇异值也不会告诉所有信息都通过主题反馈
{
client->getResult();
return true;
} else {
client->cancelAllGoals();
ROS_WARN_STREAM("The gripper action timed-out");
return false;
}
}
bool finger_control_client(float finger1, float finger2, float finger3)//0-1
{
actionlib::SimpleActionClient <kinova_msgs::SetFingersPositionAction> *finger_client = new actionlib::SimpleActionClient<kinova_msgs::SetFingersPositionAction>(
"j2n6s300_driver/fingers_action/finger_positions");
finger_client->waitForServer();
kinova_msgs::SetFingersPositionGoal finger_goal;
finger_goal.fingers.finger1 = finger1 * FINGER_MAX;
finger_goal.fingers.finger2 = finger2 * FINGER_MAX;
finger_goal.fingers.finger3 = finger3 * FINGER_MAX;
finger_client->sendGoal(finger_goal);
if (finger_client->waitForResult(ros::Duration(100.0))) {
finger_client->getResult();
return true;
} else {
finger_client->cancelAllGoals();
ROS_WARN_STREAM("The gripper action timed-out");
return false;
}
}
void MarkerCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
{
float Tf_Mat[4][4];
const float tf[16] = {0.9998, -0.0143, 0.0161, -0.002768, -0.0149, -0.9991, 0.0402, -0.56808, 0.0155, -0.0404, -0.9991, 1.09819, 0, 0, 0, 1};
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
Tf_Mat[i][j] = tf[i*4+j];
}
}
// ROS_INFO("I heard the pose from the robot");
ROS_INFO("the marker pose with cam_frame position(x,y,z) is %f , %f, %f", msg->pose.position.x, msg->pose.position.y, msg->pose.position.z);
std::cout<<"\n \n"<<std::endl;
float x, y, z, qx, qy, qz, qw, finger1, finger2, finger3, p[4], pm[4] = {msg->pose.position.x, msg->pose.position.y, msg->pose.position.z, 1};
ROS_INFO("the marker pose with pm position(x,y,z) is %f , %f, %f", pm[0], pm[1], pm[2]);
for (int i = 0; i < 4; ++i) {
p[i] = Tf_Mat[i][0]*pm[0]+Tf_Mat[i][1]*pm[1]+Tf_Mat[i][2]*pm[2]+Tf_Mat[i][3]*pm[3];
}
x=p[0];
y=p[1];//y可能需要补偿4cm y的原值为-0.528081440518
z=0.2582;
qx=0.999739147086;
qy=-0.00729168962601;
qz=0.00791491117064;
qw=0.0201450546611;
finger1 = finger2 = 0;
finger3 = 0;
try {
bool result = cartesian_pose_client(x, y, z, qx, qy, qz, qw);
if (result) {
bool finger_re = finger_control_client(finger1, finger2, finger3);
ROS_INFO("Cartesian pose sent! %f , %f, %f", x, y, z);
if (finger_re)ROS_INFO("finger move!.");
}
}
catch (ros::Exception) {
ROS_INFO("program interrupted before completion.");
}
}
int main(int argc, char **argv) {
ros::init(argc, argv, "paragram1");
ros::NodeHandle node_handle;
ros::ServiceClient start_to_home = node_handle.serviceClient<kinova_msgs::HomeArm>("j2n6s300_driver/in/home_arm");
kinova_msgs::HomeArm srv;
try {
start_to_home.call(srv);
ROS_INFO("go to home");
}
catch (ros::Exception) {
ROS_INFO("Failed to HOme.");
}
ros::Subscriber Marke_sub = node_handle.subscribe("aruco_single/pose", 1, MarkerCallback);
ros::spin();
return 0;
}
2. Version-2 Program
-
Record several kinova end effector oriention:
(1) 记录了一个当前的Marker
(2)End effector竖直向下的oriention:
qx=0.999739147086;
qy=-0.00729168962601;
qz=0.00791491117064;
qw=0.0201450546611;(3) End effector 水平向前的oriention:
(4) Marker 最终放置位置:
代码:
#include "ros/ros.h"
#include <cstdlib>
#include "std_msgs/Float64.h"
#include <unistd.h>
#include<iostream> //C++标准输入输出库
#include <vector>
#include "std_msgs/String.h"
#include "geometry_msgs/PoseStamped.h"
#include <kinova_msgs/ArmPoseActionGoal.h> // 注意格式源文件名字为ArmPose.action
#include <ros/ros.h>
#include <kinova_driver/kinova_ros_types.h>
#include <actionlib/client/simple_action_client.h>
#include <kinova_msgs/SetFingersPositionAction.h>
#include <kinova_msgs/ArmPoseAction.h>
#include <kinova_msgs/HomeArm.h>
#include <kinova_msgs/ArmJointAnglesAction.h>
const int FINGER_MAX = 6400;
class tl1{
public:
tl1();
void registerNodeHandle(ros::NodeHandle& _nh);
void registerSub();
void registerSrv();
void MarkerCallback(const geometry_msgs::PoseStamped::ConstPtr& msg);
bool cartesian_pose_client(float x, float y, float z, float qx, float qy, float qz, float qw);
bool finger_control_client(float finger1, float finger2, float finger3);
void GotoHome(kinova_msgs::HomeArm& _srv);
private:
ros::Subscriber Marke_sub;
ros::NodeHandle nh;
ros::ServiceClient start_to_home;
};
int main(int argc, char **argv) {
ros::init(argc, argv, "paragram1");
ros::NodeHandle node_handle;
tl1 loandmove;
kinova_msgs::HomeArm srv;
loandmove.registerNodeHandle(node_handle);
loandmove.registerSrv();
loandmove.GotoHome(srv);
loandmove.registerSub();
ros::spin();
return 0;
}
tl1::tl1(){};
void tl1::registerNodeHandle(ros::NodeHandle& _nh){
nh = _nh;
};
void tl1::registerSub(){
Marke_sub = nh.subscribe("aruco_single/pose", 1, &tl1::MarkerCallback, this); //this pointer here means the class itself
};
void tl1::registerSrv(){
start_to_home = nh.serviceClient<kinova_msgs::HomeArm>("j2n6s300_driver/in/home_arm");
};
bool tl1::cartesian_pose_client(float x, float y, float z, float qx, float qy, float qz, float qw)//四元数
{
actionlib::SimpleActionClient <kinova_msgs::ArmPoseAction> *client = new actionlib::SimpleActionClient<kinova_msgs::ArmPoseAction>(
"/j2n6s300_driver/pose_action/tool_pose");//取的主题
client->waitForServer();
kinova_msgs::ArmPoseGoal pose_goal;//注意形式ArmPose.action
pose_goal.pose.header.frame_id = "j2n6s300_link_base";
pose_goal.pose.pose.position.x = x;
pose_goal.pose.pose.position.y = y;
pose_goal.pose.pose.position.z = z;
pose_goal.pose.pose.orientation.x = qx;
pose_goal.pose.pose.orientation.y = qy;
pose_goal.pose.pose.orientation.z = qz;
pose_goal.pose.pose.orientation.w = qw;
client->sendGoal(pose_goal);
if (client->waitForResult(ros::Duration(200.0)))//延时得高机械臂不会发送,只能自己检测坐标,奇异值也不会告诉所有信息都通过主题反馈
{
client->getResult();
return true;
} else {
client->cancelAllGoals();
ROS_WARN_STREAM("The gripper action timed-out");
return false;
}
}
bool tl1::finger_control_client(float finger1, float finger2, float finger3)//0-1
{
actionlib::SimpleActionClient <kinova_msgs::SetFingersPositionAction> *finger_client = new actionlib::SimpleActionClient<kinova_msgs::SetFingersPositionAction>(
"j2n6s300_driver/fingers_action/finger_positions");
finger_client->waitForServer();
kinova_msgs::SetFingersPositionGoal finger_goal;
finger_goal.fingers.finger1 = finger1 * FINGER_MAX;
finger_goal.fingers.finger2 = finger2 * FINGER_MAX;
finger_goal.fingers.finger3 = finger3 * FINGER_MAX;
finger_client->sendGoal(finger_goal);
if (finger_client->waitForResult(ros::Duration(200.0))) {
finger_client->getResult();
return true;
} else {
finger_client->cancelAllGoals();
ROS_WARN_STREAM("The gripper action timed-out");
return false;
}
}
void tl1::MarkerCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)
{
float Tf_Mat[4][4];
const float tf[16] = {0.9998, -0.0143, 0.0161, -0.002768, -0.0149, -0.9991, 0.0402, -0.56808, 0.0155, -0.0404, -0.9991, 1.09819, 0, 0, 0, 1};
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
Tf_Mat[i][j] = tf[i*4+j];
}
}
ROS_INFO("the marker pose with cam_frame position(x,y,z) is %f , %f, %f", msg->pose.position.x, msg->pose.position.y, msg->pose.position.z);
std::cout<<"\n \n"<<std::endl; //add two more blank row so that we can see the message more clearly
float x, y, z, qx, qy, qz, qw, finger1, finger2, finger3, p[4], pm[4] = {msg->pose.position.x, msg->pose.position.y, msg->pose.position.z, 1};
ROS_INFO("the marker pose with pm position(x,y,z) is %f , %f, %f", pm[0], pm[1], pm[2]);
for (int i = 0; i < 4; ++i) {
p[i] = Tf_Mat[i][0]*pm[0]+Tf_Mat[i][1]*pm[1]+Tf_Mat[i][2]*pm[2]+Tf_Mat[i][3]*pm[3];
}
x=p[0];
y=p[1];//y可能需要补偿4cm y的原值为-0.528081440518
z=p[2]+0.1;
qx=0.7041;
qy=0.01358;
qz=0.07847;
qw=0.7056;
finger1 = finger2 = finger3 = 0;
try {
bool result = cartesian_pose_client(x, y, z, qx, qy, qz, qw);
if (result) {
bool finger_re = finger_control_client(finger1, finger2, finger3);
ROS_INFO("Move to Marker up! %f , %f, %f", x, y, z);
if (finger_re)ROS_INFO("finger move!.");
}
}
catch (ros::Exception) {
ROS_INFO("program interrupted before completion.");
}
x=p[0];
y=p[1];//y可能需要补偿4cm y的原值为-0.528081440518
z=p[2]-0.03;
qx=0.7041;
qy=0.01358;
qz=0.07847;
qw=0.7056;
finger1 = finger2 = finger3 = 1;
try {
bool result = cartesian_pose_client(x, y, z, qx, qy, qz, qw);
if (result) {
bool finger_re = finger_control_client(finger1, finger2, finger3);
ROS_INFO("Catch the Marker! %f , %f, %f", x, y, z);
if (finger_re)ROS_INFO("finger move!.");
}
}
catch (ros::Exception) {
ROS_INFO("program interrupted before completion.");
}
kinova_msgs::HomeArm srv;
GotoHome(srv);
x= 0.472484827042;
y= -0.172647804022;
z= 0.0302095841616;
qx= -0.0346102192998;
qy= -0.999143242836;
qz= -0.00137171335518;
qw= -0.0226511508226;
finger1 = finger2 = finger3 = 0;
try {
bool result = cartesian_pose_client(x, y, z, qx, qy, qz, qw);
if (result) {
bool finger_re = finger_control_client(finger1, finger2, finger3);
ROS_INFO("Marker move to final pose! %f , %f, %f", x, y, z);
if (finger_re)ROS_INFO("finger open!.");
}
}
catch (ros::Exception) {
ROS_INFO("program interrupted before completion.");
}
exit(0);
}
void tl1::GotoHome(kinova_msgs::HomeArm& _srv)
{
kinova_msgs::HomeArm srv;
try {
start_to_home.call(srv);
ROS_INFO("go to home");
}
catch (ros::Exception) {
ROS_INFO("Failed to HOme.");
}
}
- 代码更加简练,把几乎所有的函数变量都定义到类里面。
- 主题订阅中的函数callback仍然太繁琐,仍然需要精简!