4:机器人目标识别无序抓取程序二次开发

判断文件是否存在


//判断文件在不在
int HandEyeCalib::AnsysFileExists(QString FileAddr)
{
    QFile File1(FileAddr);
    if(!File1.exists())
    {
      QMessageBox::warning(this,QString::fromLocal8Bit("提示"),FileAddr+QString::fromLocal8Bit("文件不存在"));
      return -1;
    }
    else
    {
        return 0;
    }
}

图像九点坐标的获取与显示

1.首先进行九点标定

在UI界面上添加九点标定QT设计师类

在主程序中声明此类头文件,并添加此界面

.h文件

private:   
//手眼标定类
    HandEyeCalib *m_PHandEyeCalib=NULL;

.cpp文件

  m_PHandEyeCalib=new HandEyeCalib();
  ui->MainTab->addTab(m_PHandEyeCalib,QString::fromLocal8Bit("标定"));












    if(m_PHandEyeCalib!=NULL)
    {
        delete m_PHandEyeCalib;
        m_PHandEyeCalib=NULL;
    }


第一步应该是打开一张拍摄好的九点图像,或者是打开相机现场采集。

则读图操作为:

//读图
void HandEyeCalib::on_pB_OpenImage_clicked()
{
    //调取 不同的图像 在这里完成测试
    //传入路径
    QString path = QFileDialog::getOpenFileName(this,"选择图片","","JPG文件(*.jpg;*.bmp)");
    if(path == "") return;

    //read  image
    HTuple file2=HTuple(path.toStdString().c_str());
    ReadImage(&halconImage,file2);


    //2592 1544
    SetPart(WindowHandle, 0, 0, 1544, 2592);
    DispObj(halconImage,WindowHandle);
}

绘制像素坐标点或者圆

可以现在HALCON中编写程序,如何导出C++添加到QT中

//绘制点
void MainWindow::on_action_triggered()
{
    HObject Cross;
    DrawPoint(WindowHandle, &Row, &Column);
    GenCrossContourXld(&Cross, Row, Column, 116, 0.785398);
    DispObj(Cross, WindowHandle);
}

由于绘制的点,在九点标定类中需要用到,所以要把得到的XY坐标点声明在全局变量中

HTuple Row, Column; //绘制点

然后在九点标定类的上面引用这两个变量(这是个通用方法,如果两个类都需要用到同一个变量,则可以使用此方法;也可以利用信号与槽机制)

extern HTuple Row, Column;  //画点   -

在得到像素点之后,则可以显示加载在界面上

//加载显示像素点
void HandEyeCalib::on_pB_LoadPixelCoord_clicked()
{
    // Row  的长度为0
    // try catch    ----
    HTuple Length;
    TupleLength(Row, &Length);
    if(Length[0].D()==0)
    {
        QMessageBox::warning(this,"warning",QString::fromLocal8Bit("数据异常"));
        return;
    }

    //点1
    if(ui->spinBox_PointNum2->value()==1)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_17->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_17->setValue(Column[0].D());
    }

    //点2
    if(ui->spinBox_PointNum2->value()==2)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_18->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_18->setValue(Column[0].D());
    }

    //点3
    if(ui->spinBox_PointNum2->value()==3)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_19->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_19->setValue(Column[0].D());
    }

    //点4
    if(ui->spinBox_PointNum2->value()==4)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_20->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_20->setValue(Column[0].D());
    }

    //点5
    if(ui->spinBox_PointNum2->value()==5)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_21->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_21->setValue(Column[0].D());
    }


    //点6
    if(ui->spinBox_PointNum2->value()==6)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_22->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_22->setValue(Column[0].D());
    }

    //点7
    if(ui->spinBox_PointNum2->value()==7)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_23->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_23->setValue(Column[0].D());
    }


    //点8
    if(ui->spinBox_PointNum2->value()==8)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_24->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_24->setValue(Column[0].D());
    }

    //点9
    if(ui->spinBox_PointNum2->value()==9)
    {
        //界面的点1  的 xy  更新为  row  column
        ui->x_25->setValue(Row[0].D());   //HTUPLE  转换为 double
        ui->y_25->setValue(Column[0].D());
    }

}


机械臂坐标的获取与显示

包含库目录

include文件

lib文件

realse文件

.pro目录

INCLUDEPATH += $$PWD/include/libfairino



LIBS += -L$$PWD/lib/FairinoLib/ -lfairino
LIBS += -L$$PWD/lib/FairinoLib/ -lfairinod

头文件声明

#include <QWidget>
#include "robot.h"
#ifdef WINDOWS_OPTION
#include <string.h>
#include <windows.h>
#elif LINUX_OPTION
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <unistd.h>
#endif

#include <chrono>
#include <thread>

添加机械臂的UI类,并在主函数中声明添加界面

.h文件

 //法奥机器人类
    FairinoRobtics *m_pFairinoRobtics=NULL;

.cpp文件

  //机器人UI类的实例化
      m_pFairinoRobtics= new FairinoRobtics();
      ui->MainTab->addTab(m_pFairinoRobtics,QString::fromLocal8Bit("法奥机器人"));





    if(m_pFairinoRobtics!=NULL)
    {
        delete m_pFairinoRobtics;
        m_pFairinoRobtics=NULL;
    }

获取坐标

在机械臂类中,实例化具体的对象 —名字叫:robot

    FRRobot robot;//声明机器人对象

连接机械臂

void FairinoRobtics::on_pushButton_2_clicked()
{
    robot.RPC("192.168.1.2");
}

获取当前坐标点


void FairinoRobtics::on_ptn_ModifyA_clicked()
{

    GetTargetTCPPose(nowPos);//获取坐标函数

    RobX=nowPos.tran.x;
    RobY=nowPos.tran.y;

}

//获取坐标定义
void FairinoRobtics::GetTargetTCPPose(DescPose &nowPos)
{
    int ret=robot.GetActualTCPPose(0,&nowPos);

    ui->Dx->setValue(nowPos.tran.x);
    ui->Dy->setValue(nowPos.tran.y);
    ui->Dz->setValue(nowPos.tran.z);

    ui->Drx->setValue(nowPos.rpy.rx);
    ui->Dry->setValue(nowPos.rpy.ry);
    ui->Drz->setValue(nowPos.rpy.rz);

}

机械臂走点

void FairinoRobtics::on_pushButton_clicked()
{
    DescPose desc_pos;//创建一个笛卡尔空间位置数据
    memset(&desc_pos, 0, sizeof(DescPose));//初始化笛卡尔空间位置数据
    double x = ui->Dx->value();//取得ui空间的值(doubleSpinBox)
    double y = ui->Dy->value();//取得ui空间的值(doubleSpinBox)
    double z = ui->Dz->value();//取得ui空间的值(doubleSpinBox)
    double rx = ui->Drx->value();//取得ui空间的值(doubleSpinBox)
    double ry = ui->Dry->value();//取得ui空间的值(doubleSpinBox)
    double rz = ui->Drz->value();//取得ui空间的值(doubleSpinBox)

    desc_pos.tran.x = x;   //为desc_pos赋值
    desc_pos.tran.y = y;
    desc_pos.tran.z = z;
    desc_pos.rpy.rx = rx;
    desc_pos.rpy.ry = ry;
    desc_pos.rpy.rz = rz;

    int tool = ui->sTool->value();
    int user = ui->sUser->value();
    double vel = 100;
    double acc = 100;
    double ovl = 100;
    double blendT = -1;
    double config = -1;

    robot.MoveCart(&desc_pos,tool,user,vel,acc,ovl,blendT,config);
}

在获取到坐标之后,需要把前两个参数传给九点标定的类中,所以需要把下面这两个坐标声明为全局变量


double  RobX=1.5;
double  RobY=1.6;

然后在九点标定类中引用这两个点

extern double  RobX;
extern double  RobY;

加载显示机械臂的点

void HandEyeCalib::on_pB_LoadRobCoord_clicked()
{
    if(ui->spinBox_PointNum1->value()==1)  //value 获取值
    {
        ui->x_1->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_1->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }

    //点2
    if(ui->spinBox_PointNum1->value()==2)  //value 获取值
    {
        ui->x_2->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_2->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }

    //点3
    if(ui->spinBox_PointNum1->value()==3)  //value 获取值
    {
        ui->x_3->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_3->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }

    //点2
    if(ui->spinBox_PointNum1->value()==4)  //value 获取值
    {
        ui->x_4->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_4->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
    //点2
    if(ui->spinBox_PointNum1->value()==5)  //value 获取值
    {
        ui->x_5->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_5->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
    //点2
    if(ui->spinBox_PointNum1->value()==6)  //value 获取值
    {
        ui->x_6->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_6->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
    //点2
    if(ui->spinBox_PointNum1->value()==7)  //value 获取值
    {
        ui->x_7->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_7->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
    //点2
    if(ui->spinBox_PointNum1->value()==8)  //value 获取值
    {
        ui->x_8->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_8->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
    //点2
    if(ui->spinBox_PointNum1->value()==9)  //value 获取值
    {
        ui->x_9->setValue(RobX);   //机器人类的变量  extern  引用,赋值 设置值
        ui->y_9->setValue(RobY);   //机器人类的变量  extern  引用,赋值 设置值
    }
}


上面已经完整对像素和机械臂的坐标加载显示;为了方便需要保存这些点

//保存所有点
void HandEyeCalib::on_pB_SaveParamters_clicked()
{
    //机器人坐标  ---QSeting   ,htuple WriteTuple
    //像素坐标  PixelX,PixelY
    HTuple RobX,RobY,PixelX,PixelY;
    RobX = HTuple();
    RobX[0]=ui->x_1->value();
    RobX[1]=ui->x_2->value();
    RobX[2]=ui->x_3->value();
    RobX[3]=ui->x_4->value();
    RobX[4]=ui->x_5->value();
    RobX[5]=ui->x_6->value();
    RobX[6]=ui->x_7->value();
    RobX[7]=ui->x_8->value();
    RobX[8]=ui->x_9->value();

    RobY = HTuple();
    RobY[0]=ui->y_1->value();
    RobY[1]=ui->y_2->value();
    RobY[2]=ui->y_3->value();
    RobY[3]=ui->y_4->value();
    RobY[4]=ui->y_5->value();
    RobY[5]=ui->y_6->value();
    RobY[6]=ui->y_7->value();
    RobY[7]=ui->y_8->value();
    RobY[8]=ui->y_9->value();


    PixelX=HTuple();
    PixelX[0]=ui->x_17->value();
    PixelX[1]=ui->x_18->value();
    PixelX[2]=ui->x_19->value();
    PixelX[3]=ui->x_20->value();
    PixelX[4]=ui->x_21->value();
    PixelX[5]=ui->x_22->value();
    PixelX[6]=ui->x_23->value();
    PixelX[7]=ui->x_24->value();
    PixelX[8]=ui->x_25->value();


    PixelY = HTuple();
    PixelY[0]=ui->y_17->value();
    PixelY[1]=ui->y_18->value();
    PixelY[2]=ui->y_19->value();
    PixelY[3]=ui->y_20->value();
    PixelY[4]=ui->y_21->value();
    PixelY[5]=ui->y_22->value();
    PixelY[6]=ui->y_23->value();
    PixelY[7]=ui->y_24->value();
    PixelY[8]=ui->y_25->value();


    //判断文件夹是否存在
    QString  FileAddr="./data/Param";
    QFile File1(FileAddr);
    if(File1.exists())
    {
       WriteTuple(RobX, "./data/Param/robX.tup");
       WriteTuple(RobY, "./data/Param/robY.tup");
       WriteTuple(PixelX, "./data/Param/RowS.tup");
       WriteTuple(PixelY, "./data/Param/ColumnS.tup");
       ui->textBrowser->append(QString::fromLocal8Bit("保存成功"));
    }
    else
    {
       ui->textBrowser->append(FileAddr+QString::fromLocal8Bit("文件不存在,无法保存"));
    }

}

重新读图保存的坐标

void HandEyeCalib::on_pB_LoadParameters_clicked()
{
    HTuple RobX,RobY;
    QString  FileAddr="./data/Param";
    QFile File1(FileAddr);
    try
    {
        if(File1.exists())
        {
            ReadTuple("./data/Param/robX.tup", &RobX);
            ReadTuple("./data/Param/robY.tup", &RobY);
            ui->textBrowser->append(QString::fromLocal8Bit("读取成功"));
            ui->x_1->setValue(RobX[0].D());
            ui->x_2->setValue(RobX[1].D());
            ui->x_3->setValue(RobX[2].D());
            ui->x_4->setValue(RobX[3].D());
            ui->x_5->setValue(RobX[4].D());
            ui->x_6->setValue(RobX[5].D());
            ui->x_7->setValue(RobX[6].D());
            ui->x_8->setValue(RobX[7].D());
            ui->x_9->setValue(RobX[8].D());

            ui->y_1->setValue(RobY[0].D());
            ui->y_2->setValue(RobY[1].D());
            ui->y_3->setValue(RobY[2].D());
            ui->y_4->setValue(RobY[3].D());
            ui->y_5->setValue(RobY[4].D());
            ui->y_6->setValue(RobY[5].D());
            ui->y_7->setValue(RobY[6].D());
            ui->y_8->setValue(RobY[7].D());
            ui->y_9->setValue(RobY[8].D());

        }
        else
        {
           ui->textBrowser->append(FileAddr+QString::fromLocal8Bit("文件不存在,无法保存"));
        }
    }
    catch(...)
    {
        ui->textBrowser->append(FileAddr+QString::fromLocal8Bit("文件缺失"));
    }

}

因为保存点和重新读图点,都是数组点;可以现在HALCON软件中写好程序,然后导出更方便


最终生成标定文件

void HandEyeCalib::on_pB_GenCalibResult_clicked()
{
    HTuple  RowS, ColumnS, RobX, RobY;
    HTuple  HomMat2D;
    //1.获取 4---9个点的  像素坐标系
    RowS = HTuple();
    ColumnS = HTuple();

    RobX = HTuple();
    RobY = HTuple();

    QString  FileAddr;
    FileAddr="./data/Param/robX.tup";

    //判断文件在不在
    int ret=AnsysFileExists( FileAddr);
    if(ret==-1){return;}
    FileAddr="./data/Param/robY.tup";
    ret=AnsysFileExists( FileAddr);
    if(ret==-1){return;}
    FileAddr="./data/Param/RowS.tup";
    ret=AnsysFileExists( FileAddr);
    if(ret==-1){return;}
    FileAddr="./data/Param/ColumnS.tup";
    ret=AnsysFileExists( FileAddr);
    if(ret==-1){return;}
    try
    {
    ReadTuple("./data/Param/robX.tup", &RobX);
    ReadTuple("./data/Param/robY.tup", &RobY);
    ReadTuple("./data/Param/RowS.tup", &RowS);
    ReadTuple("./data/Param/ColumnS.tup", &ColumnS);

    //生成一个矩阵  HomMat2D
    VectorToHomMat2d(RowS, ColumnS, RobX, RobY, &HomMat2D);

    WriteTuple(HomMat2D, "./data/Param/HomMat2D.tup");  //标定文件

    QMessageBox::warning(this,QString::fromLocal8Bit("提示"),QString::fromLocal8Bit("创建标定矩阵成功"));
    return;
    }
    catch(...)
    {
        QMessageBox::warning(this,QString::fromLocal8Bit("提示"),QString::fromLocal8Bit("创建标定矩阵失败"));
        return;

    }

}




HALCON程序附录

保存、读图数组、绘制点、绘制圆


九点标定
 

    
    *1.获取 4---9个点的  像素坐标系
    RowS:=[]
    ColumnS:=[]
    
    RobX:=[]
    RobY:=[]
    
    dev_open_window(0, 0, 512, 512, 'black', WindowHandle)
    
*     read_image(Image, '标定')
*     draw_circle(WindowHandle, Row, Column, Radius)
*     CenterCoord:=[Row, Column]
    
    Pose:=[253.871, 342.389]
    write_tuple(Pose,'./像素/Pose0.dat')
         
         
   Pose:=[253.487, 591.21]
    write_tuple(Pose,'./像素/Pose1.dat')
    
   Pose:=[251.388, 849.435]
    write_tuple(Pose,'./像素/Pose2.dat')
    
    
    Pose:=[496.451, 340.278]
    write_tuple(Pose,'./像素/Pose3.dat')
    
    Pose:=[499.304, 590.602]
    write_tuple(Pose,'./像素/Pose4.dat')
    
    Pose:=[502.83, 851.243]
    write_tuple(Pose,'./像素/Pose5.dat')
    
   Pose:=[707.115, 339.089]
    write_tuple(Pose,'./像素/Pose6.dat')
    Pose:=[700.256, 591.442]
    write_tuple(Pose,'./像素/Pose7.dat')
    Pose:=[694.649, 853.365]
    write_tuple(Pose,'./像素/Pose8.dat')
    
    *获取9个点的像素点
     for I := 0 to 8 by 1
         FileName:='./像素/Pose'+I+'.dat'
         read_tuple(FileName, Pose)
         RowS[I]:=Pose[0]
         ColumnS[I]:=Pose[1]
     endfor
    
    
    
    
    *获取9个点的机械手坐标
    *2获取4---9个点  机械手 坐标!  (mm)
     for I := 11 to 19 by 1
         FileName:='./坐标/Pose'+I$'01d'+'.dat'
         read_pose(FileName, Pose)
         RobX[I-11]:=Pose[0]
         RobY[I-11]:=Pose[1]
     endfor
     
     
     *两者进行仿射变换 ,就可以得到  像素坐标和 机械手坐标的变换 。 
     *相机固定位置 ,   机械手 定点拍照 都可以使用 
     *如果机械手移动拍照 ,  + 机械手 和标定 时刻拍照间的差值 !

     *生成一个矩阵  HomMat2D
     vector_to_hom_mat2d(RowS ,ColumnS,RobX,RobY, HomMat2D)
     
     write_tuple(HomMat2D, 'HomMat2D')
     *
     
     *识别图像的坐标 假如是RowS[0]  ,ColumnS[0]
     *根据 这个矩阵 能否求出机械手坐标!
     
     Row1:=512
     Column1:= 640
     affine_trans_point_2d(HomMat2D,253.871, 342.389,Qx, Qy)
     

TCP标定

1.法兰盘姿态换算到工具姿态

     
    *法兰盘坐标 换算到 工具末端坐标
    *X219.108Y579.008Z364.915RX-179.026RY0.549RZ-64.079,2
     
     *法兰盘 坐标  记录
     pose1:=[219.108,579.008,364.915,-179.026,0.549,-64.079,2]
     
     *坐标换算  旋转轴2 换算到旋转轴0
     convert_pose_type(pose1, 'Rp+T', 'gba', 'point', Pose11)
     
     *标定的 工具与法兰盘的 位置 tcp
     tcpPose:=[-5.593,7.166,249.3040,0,0,0,0]
    
     *法兰盘 换算到 工具坐标系
     pose_compose( Pose11,tcpPose,  PoseCompose1)
     
     *工具坐表 旋转 状态变换
     convert_pose_type(PoseCompose1, 'Rp+T', 'abg', 'point', Pose22)
     if(Pose22[3]>180)
        Pose22[3]:=Pose22[3]-360 
     endif
     
     if(Pose22[4]>180)
        Pose22[4]:=Pose22[4]-360 
     endif
     
     if(Pose22[5]>180)
        Pose22[5]:=Pose22[5]-360 
     endif
     
     *Pose22 就是最终的姿态结果
     
     *[212.986, 584.908, 115.59, 180.92, 0.636037, 64.0786,2]

2.工具姿态换算到法兰盘姿态

     
    * 工具末端坐标换算到法兰盘坐标 

    
    
     *X212.988Y584.915Z115.59RX-179.026RY0.549RZ-64.079
     
     Pose22:=[212.986, 584.908, 115.59, -179.026, 0.549, -64.079, 2]
     
     *坐标换算  旋转轴2 换算到旋转轴0
     convert_pose_type(Pose22, 'Rp+T', 'gba', 'point', Pose2)
    
     *标定的 工具与法兰盘的 位置 tcp
     tcpPose:=[-5.593,7.166,249.3040,0,0,0,0]
     
     *对标定结果进行逆变换
     pose_invert(tcpPose, PoseInvert1)
     
     pose_compose( Pose2, PoseInvert1,  Pose11)
     
      *工具坐表 旋转 状态变换
     convert_pose_type(Pose11, 'Rp+T', 'abg', 'point', Pose1)
     
     if(Pose1[3]>180)
        Pose1[3]:=Pose1[3]-360 
     endif
     
     if(Pose1[4]>180)
        Pose1[4]:=Pose1[4]-360 
     endif
     
     if(Pose1[5]>180)
        Pose1[5]:=Pose1[5]-360 
     endif
     
     *Pose1 就是最终的姿态结果
     *[219.108, 579.008, 364.915, -179.026, 0.549, -64.079, 2]
     *法兰盘 坐标  记录
     *pose1:=[219.108,579.008,364.915,-179.026,0.549,-64.079,2]
     

已经看到这里了,点个赞和关注吧!

      刚开始写文章,如有不足请多多包含;之后会持续更新关于(halcon学习,VS联合编程,QT联合编程,C++,C#,Opencv图像处理库,三维点云库pcl,相机以及机器人的二次开发)等系统化学习文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值