【QT+OpenCascade+RL】安川机器人仿真器源码学习

4988251a745dade9a8c15e8b0300f2cf.png主界面

该仿真器通过加载障碍物模型,设置关节起始配置,设置关节终点配置(后续可设置多个终点),再之后开启运动规划线程即可实现机械臂的避障运动规划。

机械臂基本操作

该软件基于QT开发,OpenCascade作为显示内核,借助RoboticsLibrary库作为为运动学正逆解计算、碰撞检测和运动规划引擎。该软件可以实现以下功能:1.DH坐标系形状的绘制。2.移动机械臂的连杆在场景中的位置。3.场景的gif以及视频录制。4.滑动条设置关节位置……

运动规划操作演示视频

5a7572760c62170010b7aaffeb5a4824.png

程序框架

部分代码:

封装的RLAPI接口:

#include "RLConvertAPI.h"


//=======================================================================
//function : RLConvertAPI
//purpose  : *
//=======================================================================
RLConvertAPI::RLConvertAPI(QString &JointMdlFile, QString &JointSgFile, QString &JointModelFile,
                           QObject *parent) : QObject(parent)
  ,mJointMdlFileName(JointMdlFile)
  ,mJointSgFileName(JointSgFile)
  ,mJointModelFilePath(JointModelFile)
{
    aWriterAPI = new RLAPI_Writer;
    aReaderAPI = new RLAPI_Reader;
}


//=======================================================================
//function : RLConvertAPI
//purpose  : *
//=======================================================================
RLConvertAPI::~RLConvertAPI()
{
    delete aReaderAPI;
    aReaderAPI = nullptr;
    delete aWriterAPI;
    aWriterAPI = nullptr;
}


//=======================================================================
//function : LoadFiles
//purpose  : * 加载文件
//=======================================================================
void RLConvertAPI::InitLoadData()
{
    if(aReaderAPI==nullptr)
        aReaderAPI = new RLAPI_Reader;


    emit RLSatutsChanged(RLStatus::ReadingMdlXML);
    aReaderAPI->ReadModelXMLFIle(mJointMdlFileName);


    emit RLSatutsChanged(RLStatus::ReadingSceneXML);
    aReaderAPI->ReadSceneXMLFile(mJointSgFileName);


    emit RLSatutsChanged(RLStatus::ParsingAssembleArgs);
    aReaderAPI->ReadAssembleArgs(mJointSgFileName);


    emit RLSatutsChanged(RLStatus::ParsingMotionArgs);
    aReaderAPI->ReadAixsDirection(mJointMdlFileName);


    emit RLSatutsChanged(RLStatus::ReadingJointFiles);
    aReaderAPI->ReadJointModels(mJointModelFilePath);


    SetJointValue(aReaderAPI->JointModel->getHomePosition());
    aReaderAPI->MeasureAISShape->SetLocalTransformation(aReaderAPI->MeasureModelTrsf);
    MotionMaxValues = aReaderAPI->JointModel->getMaximum();
    MotionMinValues = aReaderAPI->JointModel->getMinimum();
    MotionSpeedValues = aReaderAPI->JointModel->getSpeed();
}


//=======================================================================
//function : ImportSceneModel
//purpose  : * 写入场景模型vrml文件  .wrl文件//
//=======================================================================
void RLConvertAPI::ImportSceneModel(const QString &theName)
{
    mImportModelFileName = theName;


    QFileInfo aInfo(mImportModelFileName);
    QString Path = aInfo.filePath().remove(aInfo.fileName());
    QString theVrmlFile(Path+aInfo.baseName()+".wrl");
    aInfo.setFile(theVrmlFile);


    if(!aInfo.exists())
    {
        //1、从形状构建网格 build the mesh from the shape
        Handle(Poly_Triangulation) aMesh = aWriterAPI->BuildMesh(aReaderAPI->ReadAModelFile(theName)->Shape());


        //2、生成 generate a vrml file that has the same base name
        aWriterAPI->WriteMeshToVrml(aMesh,theVrmlFile);
    }


    //3、创建场景VRML文件creat the scene vrml file
    aWriterAPI->GenerateSceneVrmlFile(theVrmlFile ,aReaderAPI->SceneVrmlFileName);


    //4、创建场景XML文件creat the scene xml file
    aWriterAPI->GenerateSceneXMLFile(aReaderAPI->SceneVrmlFileName,mJointSgFileName,aReaderAPI->JointModel->getDof());
}


//=======================================================================
//function : Reset
//purpose  : *重置场景模型
//=======================================================================
void RLConvertAPI::ResetSceneModel()
{    
    delete aReaderAPI->SceneModel;
    aReaderAPI->SceneModel = nullptr;
    aReaderAPI->CollisionScene.reset();
    aReaderAPI->AssembleTrsfs.clear();
    aReaderAPI->MotionCenters.clear();
    aReaderAPI->MeasureAISShape.reset(nullptr);


    aReaderAPI->ReadSceneXMLFile(mJointSgFileName);//读取场景xml文件//
    aReaderAPI->ReadAssembleArgs(mJointSgFileName);//读取装配参数//


    SetJointValue(aReaderAPI->JointModel->getHomePosition());//设置关节位置:关节模型的 home位置//
    aReaderAPI->MeasureAISShape->SetLocalTransformation(aReaderAPI->MeasureModelTrsf);//设置测量模型位姿//
}


//=======================================================================
//function : SetIndexedJointValue
//purpose  : *设置指定索引的关节值//
//=======================================================================
void RLConvertAPI::SetIndexedJointValue(const int &index, const double &angle)
{
    rl::mdl::Kinematic* aKinematic = dynamic_cast<rl::mdl::Kinematic*>(aReaderAPI->JointModel.get());//关节模型的运动学对象
    rl::math::Vector pos = aKinematic->getPosition();//获取关节位置矢量//
    if(aReaderAPI->JointType.at(index)==RLAPI_JointType::Revolute)//转动副//
        pos(index) = angle * rl::math::constants::deg2rad;//rad used in calculate but deg used in ui
    else if(aReaderAPI->JointType.at(index)==RLAPI_JointType::Prismatic)//移动副//
        pos(index) = angle;
    else//其他转动副//
        pos(index) = angle * rl::math::constants::deg2rad;
    SetJointValue(pos);//设置关节位置//
}


//=======================================================================
//function : SetJointValue
//purpose  : * 根据矢量设定关节位置
//=======================================================================
void RLConvertAPI::SetJointValue(const rl::math::Vector &aVector)
{
    rl::mdl::Kinematic* aKinematic = dynamic_cast<rl::mdl::Kinematic*>(aReaderAPI->JointModel.get());//运动学对象//


    aKinematic->setPosition(aVector);//设置运动学对象的关节位置矢量//
    aKinematic->forwardPosition();//位置正解//


    for (std::size_t i = 0; i<aReaderAPI->SceneModel->getNumBodies(); ++i)//遍历场景模型的所有零件//
    {
        rl::math::Transform theTrans = aKinematic->getBodyFrame(i);//获取零件坐标系位姿//
        aReaderAPI->CollisionScene->getModel(0)->getBody(i)->setFrame(theTrans);//获取碰撞场景中运动学对象的零件i,设置其位姿//
    }
    //设置一个累积Trsf来改变当前轴之后的轴//
    gp_Trsf CumulativeTrsf;//set an Cumulative Trsf to change the axis after the current one
    for(int i=0;i<aReaderAPI->MotionAxis.size();++i)
    {
        gp_Trsf aTrsf = aReaderAPI->JointAISShapes.at(i+1)->Shape().Location().Transformation();//下一关节形状的变换矩阵//
        if(aReaderAPI->JointType.at(i)==RLAPI_JointType::Revolute)//转动副//
            aTrsf.SetRotation(aReaderAPI->MotionAxis.at(i),aVector(i));//旋转变换//


        else if(aReaderAPI->JointType.at(i)==RLAPI_JointType::Prismatic)//移动副//
            aTrsf.SetTranslation(gp_Vec(aReaderAPI->MotionAxis.at(i).Direction())*aVector(i));//平移变换//


        CumulativeTrsf.Multiply(aTrsf);//累积变换//


        gp_Trsf workTrsf;//the real work Trsf ,E * Cumulative * Assemble
        workTrsf.Multiply(CumulativeTrsf);//相对运动位姿//
        workTrsf.Multiply(aReaderAPI->AssembleTrsfs.value(i));//装配参数:初始位姿矩阵//


        //set the value JointAISShapes a public member in the class,when u change here ,u needn't to display them again in the main function, update the occWidget is enough
        //在类中设置值JointAISShapes为公共成员,当你在这里更改时,你不需要在main函数中再次显示它们,更新occWidget就足够了
        aReaderAPI->JointAISShapes.at(i+1)->SetLocalTransformation(workTrsf);
    }


    //here is the signal to update the occWidget这里是更新occWidget的信号//
    emit JointPositionChanged();
    IsCollision();//碰撞检测//
}


//=======================================================================
//function : SetIndexedInverseValue
//purpose  : * 设置tcp某项,进行逆解//
//=======================================================================
bool RLConvertAPI::SetIndexedInverseValue(const int &index, const double &value)
{
    if (rl::mdl::Kinematic* kinematic = dynamic_cast<rl::mdl::Kinematic*>(aReaderAPI->JointModel.get()))
    {
        rl::math::Transform transform = kinematic->getOperationalPosition(0);//当前tcp位置//
        rl::math::Vector3 orientation = transform.linear().eulerAngles(2, 1, 0).reverse();//当前tcp欧拉角//


        switch (index)
        {
        case 0:
        case 1:
        case 2:
            transform.translation()(index) = value;//设置tcp的 x或y或z
            break;
        case 3:
            transform.linear() = (
                        rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
                        rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
                        rl::math::AngleAxis(value * rl::math::constants::deg2rad, rl::math::Vector3::UnitX())
                        ).toRotationMatrix();//绕x轴旋转//
            break;
        case 4:
            transform.linear() = (
                        rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
                        rl::math::AngleAxis(value * rl::math::constants::deg2rad, rl::math::Vector3::UnitY()) *
                        rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
                        ).toRotationMatrix();//绕y轴旋转//
            break;
        case 5:
            transform.linear() = (
                        rl::math::AngleAxis(value * rl::math::constants::deg2rad, rl::math::Vector3::UnitZ()) *
                        rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
                        rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
                        ).toRotationMatrix();//绕z轴旋转//
            break;
        default:
            break;
        }


        rl::math::Vector q = kinematic->getPosition();//获取更新前关节位置//
        rl::mdl::NloptInverseKinematics* aInverse = new rl::mdl::NloptInverseKinematics(kinematic);//位置逆解对象//
        aInverse->setIterations(10000);//迭代次数//
        aInverse->setDuration(std::chrono::milliseconds(500));//持续时间500ms//


        for (std::size_t i = 0; i < kinematic->getOperationalDof(); ++i)//操作空间自由度//
        {
            aInverse->addGoal(i == 0 ? transform : kinematic->getOperationalPosition(i), i);//设置逆解目标//
        }


        bool solved = aInverse->solve();//逆解求解//


        if (solved)//有解//
        {
            rl::math::Vector currentPos = aReaderAPI->JointModel->getPosition();//新的当前关节位置//
            SetJointValue(currentPos);//更新关节位置//
            delete aInverse;
            return true;
        }
        else//无解//
        {
            kinematic->setPosition(q);//恢复求解前关节位置//
            kinematic->forwardPosition();//正解计算//
            delete aInverse;//释放逆解对象//
            return false;//求解失败//
        }
    }
    return false;
}


//=======================================================================
//function : SetInverseValue
//purpose  : * 设置tcp 位姿矢量 求逆解//
//=======================================================================
bool RLConvertAPI::SetInverseValue(const QList<double> &TCPInfo)
{
    Q_ASSERT(TCPInfo.size() == 6);


    if (rl::mdl::Kinematic* kinematic = dynamic_cast<rl::mdl::Kinematic*>(aReaderAPI->JointModel.get()))
    {
        rl::math::Transform transform = kinematic->getOperationalPosition(0);


        transform.translation()(0) = TCPInfo[0];
        transform.translation()(1) = TCPInfo[1];
        transform.translation()(2) = TCPInfo[2];
        transform.linear() = (
                    rl::math::AngleAxis(TCPInfo[5], rl::math::Vector3::UnitZ()) *
                    rl::math::AngleAxis(TCPInfo[4], rl::math::Vector3::UnitY()) *
                    rl::math::AngleAxis(TCPInfo[3], rl::math::Vector3::UnitX())
                ).toRotationMatrix();


        rl::math::Vector q = kinematic->getPosition();
        rl::mdl::NloptInverseKinematics* aInverse = new rl::mdl::NloptInverseKinematics(kinematic);
        aInverse->setIterations(10000);
        aInverse->setDuration(std::chrono::milliseconds(500));


        for (std::size_t i = 0; i < kinematic->getOperationalDof(); ++i)
        {
            aInverse->addGoal(i == 0 ? transform : kinematic->getOperationalPosition(i), i);
        }


        bool solved = aInverse->solve();


        if (solved)
        {
            rl::math::Vector currentPos = aReaderAPI->JointModel->getPosition();
            SetJointValue(currentPos);
            delete aInverse;
            return true;
        }
        else
        {
            kinematic->setPosition(q);
            kinematic->forwardPosition();
            delete aInverse;
            return false;
        }
    }
    return false;
}


//=======================================================================
//function : UnLockBasePosition
//purpose  : * 锁定基座位置//
//=======================================================================
void RLConvertAPI::LockBasePosition()
{   //两个移动轴 设定最大 最小关节位置为当前关节位置//
    aReaderAPI->JointModel->getJoint(0)->max(0) = aReaderAPI->JointModel->getPosition()(0);
    aReaderAPI->JointModel->getJoint(0)->min(0) = aReaderAPI->JointModel->getPosition()(0);
    aReaderAPI->JointModel->getJoint(1)->max(0) = aReaderAPI->JointModel->getPosition()(1);
    aReaderAPI->JointModel->getJoint(1)->min(0) = aReaderAPI->JointModel->getPosition()(1);
}


//=======================================================================
//function : UnLockBasePosition
//purpose  : *  解锁基座位置//
//=======================================================================
void RLConvertAPI::UnLockBasePosition()
{   //恢复两个移动轴关节位置上下限为默认设置//
    aReaderAPI->JointModel->getJoint(0)->max(0) = MotionMaxValues[0];
    aReaderAPI->JointModel->getJoint(0)->min(0) = MotionMinValues[0];
    aReaderAPI->JointModel->getJoint(1)->max(0) = MotionMaxValues[1];
    aReaderAPI->JointModel->getJoint(1)->min(0) = MotionMinValues[1];
}


//=======================================================================
//function : IsCollision
//purpose  : *  碰撞检测//
//=======================================================================
void RLConvertAPI::IsCollision()
{
    if (rl::sg::SimpleScene* simpleScene = dynamic_cast<rl::sg::SimpleScene*>(aReaderAPI->CollisionScene.get()))//简单场景--碰撞场景//
    {
        bool collision = false;   //默认不碰撞//
        size_t index=0;
        //遍历碰撞场景的 A/B 集合
        for(std::size_t i=1;i<aReaderAPI->CollisionScene->getModel(0)->getNumBodies();++i)//body0和参考面接触,collision恒为true
        {
            for(std::size_t j=0;j<aReaderAPI->CollisionScene->getModel(1)->getNumBodies();++j)
            {
                collision = simpleScene->areColliding(aReaderAPI->CollisionScene->getModel(0)->getBody(i),
                                                     aReaderAPI->CollisionScene->getModel(1)->getBody(j));//判断碰撞//
                if(collision)//如果碰撞//
                {
                    index = i;//获得碰撞的关节索引//
                    emit JointCollision(index);//发送关节碰撞信号  参数-关节索引//
                    return;
                }
            }
        }


        //self check 机器人自碰撞检测//
        bool selfCollision = false;
        size_t aIndex=0,bIndex=0;
        //  判断机械臂的 两两连杆是否碰撞//
        for(std::size_t m=0;m<aReaderAPI->CollisionScene->getModel(0)->getNumBodies();++m)
        {
            for(std::size_t n=aReaderAPI->CollisionScene->getModel(0)->getNumBodies()-1;n>m;--n)
            {
                selfCollision = simpleScene->areColliding(aReaderAPI->CollisionScene->getModel(0)->getBody(m),
                                                     aReaderAPI->CollisionScene->getModel(0)->getBody(n));
                if(selfCollision)
                {
                    if(n-m==1)
                        continue;


                    aIndex=m;
                    bIndex=n;
                    emit SelfCollision(aIndex,bIndex);//自碰撞信号//
                    return;
                }
            }
        }


        emit NoCollision();//无碰撞//
    }
}


//=======================================================================
//function : GetJointPosition
//purpose  : *  获取关节位置//
//=======================================================================
rl::math::Vector RLConvertAPI::GetJointPosition()
{
    rl::math::Vector currentPos = aReaderAPI->JointModel->getPosition();//从关节模型获取当前关节位置//
    return currentPos;
}


//=======================================================================
//function : GetOperationalPosition
//purpose  : * 获取tcp位姿//
//=======================================================================
QList<double> RLConvertAPI::GetOperationalPosition()
{
    QList<double> pos;


    rl::math::Transform Tr = aReaderAPI->JointModel->getOperationalPosition(0);
    rl::math::Vector3 OR = Tr.rotation().eulerAngles(2, 1, 0).reverse();//欧拉角 ZYX//
    pos.append(Tr.translation()(0));
    pos.append(Tr.translation()(1));
    pos.append(Tr.translation()(2));
    pos.append(OR(0)* rl::math::constants::rad2deg);
    pos.append(OR(1)* rl::math::constants::rad2deg);
    pos.append(OR(2)* rl::math::constants::rad2deg);


    return pos;
}


//=======================================================================
//function : GetJointVelocity
//purpose  : *  获取关节速度矢量//
//=======================================================================
QList<double> RLConvertAPI::GetJointVelocity()
{
    QList<double> speed;
    rl::math::Vector s = aReaderAPI->JointModel->getVelocity();//从关节模型获取关节速度矢量//
    for (int i=0;i<s.size();++i)
    {
        speed.append(s[i]);
    }
    return speed;
}


//=======================================================================
//function : GetJointAcceleration
//purpose  : *  获取关节加速度矢量//
//=======================================================================
QList<double> RLConvertAPI::GetJointAcceleration()
{
    QList<double> Acceleration;
    rl::math::Vector a = aReaderAPI->JointModel->getAcceleration();
    for (int i=0;i<a.size();++i)
    {
        Acceleration.append(a[i]);
    }
    return Acceleration;
}

 OCC部件:

#include "occWidget.h"
//构造函数//
OCCWidget::OCCWidget(QWidget *parent) :QWidget(parent)
{
    if (m_context.IsNull())//交互上下文为空//
    {
        Handle(Aspect_DisplayConnection) m_display_donnection = new Aspect_DisplayConnection();//显示连接//
        if (m_graphicDriver.IsNull())//图形驱动器为空//
        {
            m_graphicDriver = new OpenGl_GraphicDriver(m_display_donnection);//初始化opengl图形驱动器//
        }
        WId window_handle =  winId();//窗口句柄//
        Handle(WNT_Window) wind = new WNT_Window((Aspect_Handle) window_handle);
        m_viewer = new V3d_Viewer(m_graphicDriver);//观察者  查看器//
        m_view = m_viewer->CreateView();//查看器创建视图//
        m_view->SetWindow(wind);//设置视图的窗口为  OCCWidget的窗口//


        if (!wind->IsMapped())
        {
            wind->Map();
        }
        m_context = new AIS_InteractiveContext(m_viewer);//获取查看器 (观察者)的交互上下文//
        m_viewer->SetDefaultLights();//设置查看器的默认光照//
        m_viewer->SetLightOn();//开启查看器光照//
        //设置视图//
        m_view->ChangeRenderingParams().Method = Graphic3d_RM_RASTERIZATION;//改变渲染参数的方法:Graphic3d_RM_RASTERIZATION//
        m_view->ChangeRenderingParams().IsAntialiasingEnabled = Standard_False;//是否启用了反锯齿:false
        m_view->SetBgGradientColors(Quantity_NOC_GRAY80,Quantity_NOC_WHITESMOKE,Aspect_GFM_VER);//设置背景梯度颜色//
        m_view->MustBeResized();//视图必须可改变尺寸//
        m_context->SetDisplayMode(AIS_Shaded, Standard_True);//设置上下文显示模式  AIS_Shaded //
    }


    setAttribute(Qt::WA_PaintOnScreen);//在屏幕绘制//
    setAttribute(Qt::WA_NoSystemBackground);//无系统背景//
    setBackgroundRole( QPalette::NoRole );//设置颜色角色//
    setFocusPolicy( Qt::StrongFocus );//强聚焦策略//
    setMouseTracking(true);//鼠标跟踪//
    //上下文风格颜色设置//
    m_context->HighlightStyle()->SetColor(Quantity_NOC_CYAN1);//上下文高亮颜色//
    m_context->SelectionStyle()->SetColor(Quantity_NOC_CYAN1);//上下文选中风格-颜色//
    m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalDynamic)->SetColor(Quantity_NOC_CYAN1);
    m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalSelected)->SetColor(Quantity_NOC_CYAN1);
    //显示模式  透明度设置//
    m_context->HighlightStyle()->SetDisplayMode(1);
    m_context->SelectionStyle()->SetDisplayMode(1);
    m_context->SelectionStyle()->SetTransparency(0.2f);
    m_context->HighlightStyle()->SetTransparency(0.2f);
    //主选择器-拣选最近:false//
    m_context->MainSelector()->SetPickClosest(Standard_False);
    //框选橡皮筋:初始化矩形//
    m_rubberBand = new QRubberBand(QRubberBand::Rectangle,this);
    m_rubberBand->setStyle(QStyleFactory::create("windows"));//框选风格//
    //操作器设置//
    m_manipulator = new AIS_Manipulator();//初始化AIS操作器//
    m_manipulator->SetPart (0, AIS_MM_Scaling, Standard_True);//设置缩放//
    m_manipulator->SetPart (1, AIS_MM_Rotation, Standard_True);//设置旋转//
    m_manipulator->SetPart (2, AIS_MM_Translation, Standard_True);//设置平移//
    m_manipulator->EnableMode (AIS_MM_Translation);//启用平移//
    m_manipulator->EnableMode (AIS_MM_Rotation);//启用旋转//
    m_manipulator->EnableMode (AIS_MM_Scaling);//启用缩放//
    //创建cube//
    Handle(AIS_ViewCube) aCube = new AIS_ViewCube();
    aCube->SetAutoStartAnimation(Standard_True);//自动开启动画//
    aCube->SetSize(60);//设置cube尺寸//
    aCube->SetFontHeight(13);//字体高度13//
    m_context->Display(aCube,Standard_False);//上下文显示cube//
}
//绘制事件//
void OCCWidget::paintEvent(QPaintEvent *)
{
    m_view->Redraw();//重绘视图//
}
//缩放视图//
void OCCWidget::resizeEvent(QResizeEvent *)
{
    if( !m_view.IsNull() )
    {
        m_view->MustBeResized();
    }
}
//鼠标按下事件//
void OCCWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::RightButton)//右键//
    {
        m_view->StartRotation(event->x(),event->y());//视图旋转//
    }
    else if(event->button()==Qt::LeftButton)//左键//
    {
        m_context->MoveTo(event->pos().x(),event->pos().y(),m_view,Standard_True);//上下文移动到单击点//
        startPnt = event->pos();//起点//


        if(!m_manipulator->IsAttached())//操作器未附加//
            m_rubberBand->setGeometry(QRect(startPnt,QSize(1,1)));//框选1像素区域//
        else
            m_manipulator->StartTransform(event->pos().x(),event->pos().y(),m_view);//平移操作器//
    }
    else if(event->button() == Qt::MidButton)//中键//
    {   //记录中键位置//
        midBtn_x=event->x();
        midBtn_y=event->y();
    }
}
//鼠标释放//
void OCCWidget::mouseReleaseEvent(QMouseEvent *event)
{
    unsetCursor();
    m_context->MoveTo(event->pos().x(),event->pos().y(),m_view,Standard_True);   //上下文移动//


    if(event->button()==Qt::LeftButton)//左键//
    {
        if(!m_rubberBand->isHidden()&&!m_manipulator->IsAttached())//框选未隐藏或者操作器未附加//
            m_rubberBand->hide();//隐藏框选器//


        if(m_manipulator->IsAttached())//操作器附加,停止平移//
            m_manipulator->StopTransform();


        if(event->pos()==startPnt)//释放位置在起点//
        {
            AIS_StatusOfPick t_pick_status = AIS_SOP_NothingSelected;//啥都没选中//
            if(qApp->keyboardModifiers()==Qt::ControlModifier)//ctrl按键//
            {
                t_pick_status = m_context->ShiftSelect(true);// 多选 //
            }
            else
            {
                t_pick_status = m_context->Select(true);   //选中//
            }


            if(t_pick_status == AIS_SOP_OneSelected || t_pick_status == AIS_SOP_SeveralSelected)//单选或者多选//
            {
                emit selectShapeChanged(m_context->SelectedShape());//发送选择形状改变信号:参数-选择的形状//
                m_context-> InitSelected();//初始化选择//
            }


            emit pickPixel(event->x(),event->y());//发送拣选像素信号:参数 位置x,y//
        }
        else//
        {
            m_context->Select(startPnt.x(),startPnt.y(),event->x(),event->y(),m_view,Standard_True);//选择区域//
            m_context-> InitSelected();
        }
    }
}
//鼠标移动事件//
void OCCWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons()&Qt::RightButton)//右键//
    {
        setCursor(Qt::ClosedHandCursor);//设置鼠标形状//
        m_view->Rotation(event->x(),event->y());//视图旋转//
    }
    else if(event->buttons()&Qt::MidButton)//中键//
    {
        setCursor(Qt::SizeAllCursor);//
        m_view->Pan(event->pos().x()-midBtn_x,midBtn_y-event->pos().y());//zoom//
        midBtn_x=event->x();//更新中键位置//
        midBtn_y=event->y();
    }
    else if(event->buttons()&Qt::LeftButton)//左键移动//
    {
        if(!m_manipulator->IsAttached())//操作器未附加//
        {
            m_rubberBand->show();//框选//
            m_rubberBand->setGeometry(QRect(startPnt,event->pos()).normalized());
        }
        else//移动操作器//
        {
            m_manipulator->Transform(event->pos().x(),event->pos().y(),m_view);
            m_view->Redraw();
        }
    }
    else//未按下移动//
    {
        m_context->MoveTo(event->pos().x(),event->pos().y(),m_view,Standard_True);
    }
}
//滚轮事件zoom//
void OCCWidget::wheelEvent(QWheelEvent *event)
{
    m_view->StartZoomAtPoint(event->pos().x(),event->pos().y());
    m_view->ZoomAtPoint(0, 0, event->angleDelta().y(), 0);
}
//绘制引擎//
QPaintEngine *OCCWidget::paintEngine() const
{
    return nullptr;
}

规划线程:

#include "RLAPI_PlanThread.h"
#include <QDebug>


bool RLAPI_PlanThread::PlannerSolved = false;


//=======================================================================
//function : RLAPI_PlanThread
//purpose  : * 规划线程构造函数
//=======================================================================
RLAPI_PlanThread::RLAPI_PlanThread(const rl::mdl::Dynamic &aDynamic, rl::sg::pqp::Scene &aScene, const double &minModelSize,
                                   QObject *parent) : QThread(parent),minMdlSize(minModelSize)
{
    mDynamic = new rl::mdl::Dynamic(aDynamic);//动态对象
    mPlanScene = &aScene;//指向主线程中的场景point to the scene in the main thread
}


//=======================================================================
//function : RLAPI_PlanThread
//purpose  : * 规划线程析构函数//
//=======================================================================
RLAPI_PlanThread::~RLAPI_PlanThread()
{
    delete mDynamic;
    mDynamic = nullptr;
    mPlanScene = nullptr;//if delete here, pointer in the main thread will be held on
}


//=======================================================================
//function : GetComputeArguments
//purpose  : * 获取计算参数  设置起点和终点//
//=======================================================================
void RLAPI_PlanThread::GetComputeArguments(const rl::math::Vector &startPnt, const rl::math::Vector &endPnt)
{
    mStartPnt = startPnt;
    mEndPnt = endPnt;
}


//=======================================================================
//function : pause
//purpose  : * 暂停线程//
//=======================================================================
void RLAPI_PlanThread::pause()
{
    if(isRunning())
        doCollisionWait = true;//碰撞等待=true//
}


//=======================================================================
//function : resume
//purpose  : * 恢复线程//
//=======================================================================
void RLAPI_PlanThread::resume()
{
    if(isRunning())
    {
        doCollisionWait = false;//碰撞等待=false//
        waitCondition.wakeAll();
    }
}


//=======================================================================
//function : run
//purpose  : *  路径规划 并发送准备更新关节位置信号// https://www.roboticslibrary.org/tutorials/
//=======================================================================
void RLAPI_PlanThread::run()
{
    rl::plan::SimpleModel *mPlanModel = new rl::plan::SimpleModel();//新建规划模型-简单模型//
    rl::plan::AdvancedOptimizer *mPathOptimizer = new rl::plan::AdvancedOptimizer;//高级优化器//
    rl::plan::GnatNearestNeighbors nearestNeighbors(mPlanModel);//获取最近邻//
    rl::plan::Prm planner;//规划器//http://doc.roboticslibrary.org/0.7.0/d7/d24/classrl_1_1plan_1_1_prm.html
    rl::plan::UniformSampler sampler;//采样器//
    rl::plan::RecursiveVerifier verifier;//递归的验证器//


    mPlanModel->mdl = mDynamic;//设置规划模型的 mdl//
    mPlanModel->model = mPlanScene->getModel(0);//设置规划模型的运动学模型//
    mPlanModel->scene = mPlanScene;//设置规划模型的场景//


    verifier.delta = 10.0f * rl::math::constants::deg2rad;//验证器 增量10度//
    verifier.model = mPlanModel;//验证器的模型:规划模型//


    mPathOptimizer->model = mPlanModel;//路径优化器的模型--规划模型//
    mPathOptimizer->verifier = &verifier;//路径优化器的  验证器//
    mPathOptimizer->ratio = 0.01;//
    mPathOptimizer->length = 0.2*minMdlSize;


    sampler.model = mPlanModel;//采样器的模型-规划模型//


    planner.start = &mStartPnt;//规划器起点关节配置//
    planner.goal = &mEndPnt;//规划器终点关节配置//
    planner.model = mPlanModel;//规划器的模型-规划模型//
    planner.verifier = &verifier;//规划器的验证器//
    planner.setNearestNeighbors(&nearestNeighbors);//设置规划器的最近邻//
    planner.sampler = &sampler;//设置规划器的采样器//


    //verify the start and the goal.if there is an invalid value ,thread will be crashed
    //验证开始和目标。如果有一个无效的值,线程将崩溃//
    if(!planner.verify())
    {
        emit ComputeFailed(ComputeError::InvalidConfig);//计算失败//
        return;
    }


    PlannerSolved = false;
    QTimer aComputeTimer;//计算超时定时器//
    aComputeTimer.singleShot(8000,this,[=](){
        if(!PlannerSolved)//检查未求解//
            emit ComputeTimeOut();//发送超时信号//
        return;
    });


    QElapsedTimer aElapsedTimer;
    aElapsedTimer.start();//计算时间定时器//


    PlannerSolved = planner.solve();//求解//


    if(PlannerSolved)//找到解//
    {
        emit ComputeSuccess(aElapsedTimer.elapsed());//计算成功//


        rl::plan::VectorList solvedPath = planner.getPath();//获取求解的路径//


        verifier.delta *= 2;
        mPathOptimizer->process(solvedPath);//优化求解路径//
        qDebug()<<"compute+optimize "<<aElapsedTimer.elapsed();//输出计算时间//


        rl::math::Vector tmpPos(mPlanModel->getDofPosition());//获取tcp位姿参数//


        rl::plan::VectorList::iterator i = solvedPath.begin();
        rl::plan::VectorList::iterator j = ++solvedPath.begin();


        //路径插值//
        //1、添加起点  add the start
        if (i != solvedPath.end() && j != solvedPath.end())//遍历求解的优化路径//
        {
            emit ReadyToSetJointValue(*i);//发送准备设置关节位置信号//
            QThread::usleep(50000);//等待50ms//
        }


        rl::math::Real delta = 10.0f;
        double pathLength = 0;


        //2、插值 add the interpolations until the goal
        for (; i != solvedPath.end() && j != solvedPath.end(); ++i, ++j)
        {
            pathLength += mPlanModel->distance(*i ,*j);//计算路径段距离//
            rl::math::Real stepLength = std::ceil(mPlanModel->distance(*i, *j) / delta);   //插值步数//


            for (std::size_t k = 1; k < stepLength + 1; ++k)
            {
                if(doCollisionWait)//碰撞等待
                {
                    aMutex.lock();
                    waitCondition.wait(&aMutex);//等待条件满足//
                    aMutex.unlock();
                }
                mPlanModel->interpolate(*i, *j, k/stepLength, tmpPos);//插值tmpPos//
                emit ReadyToSetJointValue(tmpPos);//发送准备设置关节位置信号//
                QThread::usleep(50000);//等待50ms//
            }
        }
        PlannerSolved = false;//恢复为未找到解状态//
        emit ComputeOver(pathLength);//计算完毕//
    }
    else//没找到解//
    {
        emit ComputeFailed(ComputeError::ArgumentError);
        return;
    }
    delete mPlanModel;
    delete mPathOptimizer;
}

The End

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值