Dobot magician + realsense D435i 手眼标定(外参)C++

3 篇文章 2 订阅

之前写过一篇用python实现的,最近在ubuntu18.04弄了一个c++的,记录一下

一、pipeline:

1.下载aruco_ros、realsense-ros,打印aruco二维码,最好打印这个ros包里面的二维码,写好启动realsense和aruco的文件,直接通过获取ros消息获得二维码在相机坐标系里的位置,默认topic是“/aruco_tracker/position”;

2.dobot跑8个目标点,获得对应8个二维码坐标位置;

3.利用T*aruco_position=dobot_position, T=dobot_positon*inv(aruco_position)求出变换矩阵T。

二、过程中的坑

1.注意dobot运动到目标点后才读取aruco位置数据,需要对dobot运行的cmd消息队列中的index和完成的cmd index进行比较延时。一开始想着用dobot_ros ,调用服务的方式进行,不过太麻烦,改正直接用dobot的API,注意用得出的变化矩阵,通过相机得到的数据变换到dobot base基坐标下不是末端TCP点的位置,有个偏差,因为如图所示,二维码的中心点位置与吸盘有一定偏差,所以在后面用的时候主要把这个修正这个偏差。

2.ros中的消息可以按需求时再去订阅,不用循环订阅,代码如下

	aruco_position_msg = ros::topic::waitForMessage<geometry_msgs::Vector3Stamped >("/aruco_tracker/position",ros::Duration(5));
	aruco_position(0,i)=aruco_position_msg->vector.x;
    aruco_position(1,i)=aruco_position_msg->vector.y;
	aruco_position(2,i)=aruco_position_msg->vector.z;
	aruco_position(3,i)=1;

3.运行前,先获得串口权限

终端运行 sudo chmod a+rw /dev/ttyUSB0 , 后面的串口要根据自己的端口写。

三、完整代码

#include<iostream> 
#include<fstream>
#include<sstream>
#include<cmath> 
#include<cstdlib>
#include<vector>
#include <unistd.h>
#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/SVD>
using namespace std;

#include "ros/ros.h"
//#include "std_msgs/String.h"
//#include "std_msgs/Float32MultiArray.h"
#include "geometry_msgs/Vector3Stamped.h"

#include "DobotDll.h"

//用eigen计算伪逆矩阵函数
template<typename _Matrix_Type_> 
_Matrix_Type_ pseudoInverse(const _Matrix_Type_ &a, double epsilon = 
    std::numeric_limits<double>::epsilon()) 
{  
    Eigen::JacobiSVD< _Matrix_Type_ > svd(a ,Eigen::ComputeThinU | Eigen::ComputeThinV);  
    double tolerance = epsilon * std::max(a.cols(), a.rows()) *svd.singularValues().array().abs()(0);  
    return svd.matrixV() *  (svd.singularValues().array().abs() > tolerance).select(svd.singularValues().array().inverse(), 0).matrix().asDiagonal() * svd.matrixU().adjoint(); 
}  



int main(int argc, char **argv)
{
   //connecte dobot
    if (argc < 2) {
        cout<<"Application portName"<<endl;
        return -1;
    }
    // Connect Dobot before start the service
    int result = ConnectDobot(argv[1], 115200, 0, 0);
    switch (result) {
    case DobotConnect_NoError:
        break;
    case DobotConnect_NotFound:
        cout<<"Dobot not found!"<<endl;
        return -2;
        break;
    case DobotConnect_Occupied:
        cout<<"Invalid port name or Dobot is occupied by other application!"<<endl;
        return -3;
        break;
    default:
        break;
    }

    //读取8个目标数据,xyzr数据
    std::cout << "-----------test----------- " <<std:: endl;
	std::ifstream in("/home/yu/test_ws/src/dobot/data/trainData.txt");//自己的路径,可以用相对路径
	std::string line;
   double  dobot_target_data[8][4];

	if (in.fail())
	{
		std::cout << "no file!" << std::endl;
		std::getchar();
		std::exit(0);
	}
	std::cout << "there is  file!" << std::endl;
	/*vector< vector<float> >trainData(8,vector<float>(4));*/
	int count = 0;
	int i = 0, j = 0;
	while (getline(in, line)) {
		std::stringstream ss(line);
		float x;
		while (ss >> x) {
			count++;
			if (count < 5)
			{
				 dobot_target_data[i][j] = x;
				std::cout<< dobot_target_data[i][j] <<"\t";
				j++;
			}
			
		}
		std::cout << std::endl;
		i++;
		j = 0;
		count = 0;
		
	}
	in.close();

      //初始化节点
	ros::init(argc, argv, "aruco_position_subscriber");
	ros::NodeHandle n;
	// ros::ServiceClient client;
	ros::Rate loop_rate(2);
    ROS_INFO("arocu_position_subscriber running.../n");

    boost::shared_ptr<geometry_msgs::Vector3Stamped const>  aruco_position_msg;
	Eigen::MatrixXd  aruco_position(4,8);
	Eigen::MatrixXd dobot_target_position(4,8);

     SetCmdTimeout(3000);
     SetQueuedCmdClear();
     SetQueuedCmdStartExec();

    uint64_t executedCmdIndex=0 ;
    uint64_t  queuedCmdIndex;
    PTPCmd  ptpcmd[8 ];
    WAITCmd cmd;
    cmd.timeout = 1500;
    for(i=0;i<8;i++)
    {
        ptpcmd[i].ptpMode = 1;
        ptpcmd[i].x = dobot_target_data[i][0] ;
        ptpcmd[i].y = dobot_target_data[i][1] ;
        ptpcmd[i].z = dobot_target_data[i][2] ;
        ptpcmd[i].r = dobot_target_data[i][3] ;

        SetPTPCmd(&ptpcmd[i], true, &queuedCmdIndex);
        while(executedCmdIndex != queuedCmdIndex)
        {
          
            GetQueuedCmdCurrentIndex(&executedCmdIndex);
            sleep(2);
        }
        SetWAITCmd(&cmd, true, &queuedCmdIndex);
        cout<<"if delay print?"<<i<<endl;

        //接收aruco位置数据,最后得到4*8的矩阵
		aruco_position_msg = ros::topic::waitForMessage<geometry_msgs::Vector3Stamped >("/aruco_tracker/position",ros::Duration(5));
		aruco_position(0,i)=aruco_position_msg->vector.x;
		aruco_position(1,i)=aruco_position_msg->vector.y;
		aruco_position(2,i)=aruco_position_msg->vector.z;
		aruco_position(3,i)=1;
		cout<<"aruco_position is "<<aruco_position(0,i)<<"\t"<<aruco_position(1,i)<<"\t"<<aruco_position(2,i)<<endl;
		// 把dobot运动的目标点数据改成4*8的matrix,
		dobot_target_position(0,i)=dobot_target_data[i][0]+30;//aruco position is differ 30MM from TCP
		dobot_target_position(1,i)=dobot_target_data[i][1];
		dobot_target_position(2,i)=dobot_target_data[i][2];
		dobot_target_position(3,i)=1;

    }

    SetQueuedCmdStopExec();
       // Disconnect Dobot
    DisconnectDobot();

   
    //计算AX=BX 求解变换矩阵
	Eigen::MatrixXd image_to_arm(4,4);
	Eigen::MatrixXd arm_to_image(4,4);
   
    image_to_arm = dobot_target_position* pseudoInverse(aruco_position);
	arm_to_image = pseudoInverse( image_to_arm);
    cout<<"image to arm matrix is "<<image_to_arm<<endl;
    cout<<"arm to image matrix is "<<arm_to_image<<endl;

    	// //验证变换矩阵准确度
	cout<<"test the result!!!!"<<endl<<"image_to_arm"<<endl;
	cout<<image_to_arm*aruco_position<<endl;
	cout<<"Expected:"<<endl<<dobot_target_position.transpose()<<endl;

    //  transition matrix of  image to base,保存变换矩阵到txe文档,方便后面用
    ofstream output_stream;
    string txt_path = "/home/yu/"; 
    string txt_name = "";
    
    txt_name = txt_path +  "handeye_param.txt";
    output_stream.open(txt_name);
    for(i=0;i<4;i++)//其中originFeat是一个vector<float>,
    {
        for(int j = 0;j<4;j++)
        {

            output_stream << image_to_arm (i,j);
            if(j<3)
                output_stream << "\t";
            else
                output_stream<<"\n";
        }
        
    }
    output_stream.close();



}

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
下面是一个使用Dobot Magician机械手进行五子棋游戏的简单代码: ```python import time from dobot import Dobot def play_five_in_a_row(): dobot = Dobot() # 设置棋盘大小 board_size = 15 # 初始化棋盘 board = [[' ' for _ in range(board_size)] for _ in range(board_size)] # 游戏开始 while(True): # 机械手获取对手的下棋位置 opponent_move = dobot.get_opponent_move(board) # 在棋盘上更新对手的下棋位置 board[opponent_move[0]][opponent_move[1]] = 'O' # 打印当前棋盘状态 print_board(board) # 检查是否有五子连珠 if check_five_in_a_row(board): print("对手赢了!") break # 机械手计算并下下一步棋 dobot_move = dobot.calculate_next_move(board) # 在棋盘上更新机械手的下棋位置 board[dobot_move[0]][dobot_move[1]] = 'X' # 打印当前棋盘状态 print_board(board) # 检查是否有五子连珠 if check_five_in_a_row(board): print("机械手赢了!") break def print_board(board): print('+' + '-'*(len(board[0])*2-1) + '+') for i in range(len(board)): print('|', end='') for j in range(len(board[0])): print(board[i][j], end='|') print('\n+' + '-'*(len(board[0])*2-1) + '+') def check_five_in_a_row(board): # 检查行 for row in board: for i in range(len(row)-4): if row[i] != ' ' and row[i] == row[i+1] == row[i+2] == row[i+3] == row[i+4]: return True # 检查列 for i in range(len(board[0])): for j in range(len(board)-4): if board[j][i] != ' ' and board[j][i] == board[j+1][i] == board[j+2][i] == board[j+3][i] == board[j+4][i]: return True # 检查主对角线 for i in range(len(board)-4): for j in range(len(board[0])-4): if board[i][j] != ' ' and board[i][j] == board[i+1][j+1] == board[i+2][j+2] == board[i+3][j+3] == board[i+4][j+4]: return True # 检查副对角线 for i in range(len(board)-4): for j in range(len(board[0])-4): if board[i][j+4] != ' ' and board[i][j+4] == board[i+1][j+3] == board[i+2][j+2] == board[i+3][j+1] == board[i+4][j]: return True return False # 主函数 if __name__ == '__main__': play_five_in_a_row() ``` 以上代码使用Dobot Magician机械手进行五子棋游戏。代码首先通过Dobot类连接并初始化机械手。然后,使用一个二维列表来表示棋盘,空格表示未下棋的位置。在游戏开始阶段,机械手获取对手的下棋位置,并在棋盘上更新对手的位置。接着,检查是否有五子连珠,如果有则游戏结束,对手赢了。接下来,机械手计算并下下一步棋,并在棋盘上更新机械手的位置。然后,再次检查是否有五子连珠,如果有则游戏结束,机械手赢了。如果没有五子连珠,则循环继续,直到游戏出现胜负或平局。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值