背景
最近开发了一个六自由度机械臂调姿平台的控制软件,集成了API激光跟踪仪和KUKA机器人,实现了根据产品的测量位姿驱动仿真环境中模型并且实现模型间的碰撞检测。
其中KUKA机器人的控制可以参考笔者以前的博客:
https://blog.csdn.net/iamqianrenzhan/article/details/103115580
关于API激光跟踪仪的基本使用方法,将会在后续博客中介绍。本文主要是关于OpenCasCAD的使用,以及在qt中的配置。
OpenCasCAD简介
Open CASCADE(简称OCC)平台是由法国Matra Datavision公司开发的CAD/CAE/CAM软件平台。开源OCC对象库是一个面向对象C++类库,用于快速开发设计领域的专业应用程序。
OCC主要用于开发二维和三维几何建模应用程序,包括通用的或专业的计算机辅助设计CAD系统、制造或分析领域的应用程序、仿真应用程序或图形演示工具。OCC通过有机组织的C++库文件提供了六个模块。可视化模块作为OCC的核心部分,是可视化技术的具体体现。
OpenCasCAD的安装与自行编译
官网提供:可以在OpenCasCAD网站下载最新版
https://www.opencascade.com/content/latest-release
如果官网下载太慢,可以下载笔者上传的版本。
https://download.csdn.net/download/iamqianrenzhan/11982847
这个是安装版本,下载后可以直接使用。因为该安装版本也包含源码,也可以自行编译。自行编译参考笔者以前的博客:
https://blog.csdn.net/iamqianrenzhan/article/details/79558781
或者直接参考官网
https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_dev_guides__building_msvc.html
如果要用qt进行开发,最好在编译时把qt的版本修改为自己所用的版本。
Qt工程的建立
Qt工程主要参考了github上一个工程:
https://github.com/eryar/occQt
在pro文件中
QT += opengl
INCLUDEPATH += C:\OpenCASCADE-7.4.0-vc14-64\opencascade-7.4.0\inc
LIBS += -LC:\OpenCASCADE-7.4.0-vc14-64\opencascade-7.4.0\win64\vc14\lib
DEFINES += WNT
LIBS += -lTKernel -lTKMath -lTKV3d -lTKOpenGl \
-lTKBRep -lTKIGES -lTKSTL -lTKVRML -lTKSTEP -lTKSTEPAttr -lTKSTEP209 \
-lTKSTEPBase -lTKGeomBase -lTKGeomAlgo -lTKG3d -lTKG2d \
-lTKXSBase -lTKShHealing -lTKHLR -lTKTopAlgo -lTKMesh -lTKPrim \
-lTKCDF -lTKBool -lTKBO -lTKFillet -lTKOffset -lTKLCAF -lTKService
模型导入
新建一个管理模型导入导出的类:
class Standard_EXPORT ImportExport
{
public:
ImportExport();
public :
static void ReadIGES(const Handle(AIS_InteractiveContext)& anInteractiveContext,
Handle(AIS_Shape)& aShape);
static void ReadSTEP(const Handle(AIS_InteractiveContext)& anInteractiveContext,
Handle(AIS_Shape)& aShape);
};
目前这个类中只有两种格式模式的导入,后续会增加多种格式的导入和导出。
Stp文件导入
回传aShape参数是为了分别对导入的模型进行颜色设置,删除,移动等操作。
void ImportExport::ReadSTEP(const Handle(AIS_InteractiveContext)& anInteractiveContext,
Handle(AIS_Shape)& aShape)
{
Handle(TopTools_HSequenceOfShape) aSequence= new TopTools_HSequenceOfShape();
QString fileName = QFileDialog::getOpenFileName(nullptr,
QObject::tr("read a stp file"),
"E:",
QObject::tr("STEP Files(*.stp *.step)"));
qDebug() << fileName;
if(fileName.isNull())
{
qDebug() << "没有选择文件";
std::cout << "没有选择文件" <<std::endl;
return;
}
std::string test = fileName.toStdString();
Standard_CString aFileName = test.data();
aSequence->Clear();
STEPControl_Reader aReader;
IFSelect_ReturnStatus status = aReader.ReadFile(aFileName);
if(status !=IFSelect_RetDone)
{
switch (status)
{
case IFSelect_RetError:
std::cout << "Not a valid Step file" << std::endl;
break;
case IFSelect_RetFail :
std::cout << "Reading has failed" << std::endl;
break;
case IFSelect_RetVoid :
std::cout << "Nothing to transfer" << std::endl;
break;
default:
break;
}
return;
}
aReader.WS()->MapReader()->SetTraceLevel(2);
Standard_Boolean failsonly = Standard_False;
aReader.PrintCheckLoad(failsonly, IFSelect_ItemsByEntity);
Standard_Integer nbr = aReader.NbRootsForTransfer();
aReader.PrintCheckTransfer (failsonly, IFSelect_ItemsByEntity);
for ( Standard_Integer n = 1; n<=nbr; n++)
{
Standard_Boolean ok = aReader.TransferRoot(n);
}
Standard_Integer nbs = aReader.NbShapes();
if (nbs == 0) return;
for (Standard_Integer i=1; i<=nbs; i++)
aSequence->Append(aReader.Shape(i));
if (!aSequence.IsNull())
{
for(int i=1;i<= aSequence->Length();i++)
{
aShape = new AIS_Shape(aSequence->Value(i));
anInteractiveContext->SetColor(aShape,Quantity_NOC_YELLOW,Standard_False);
anInteractiveContext->SetMaterial(aShape,Graphic3d_NOM_PLASTIC,Standard_False);
anInteractiveContext->SetDisplayMode(aShape,1,Standard_False);
anInteractiveContext->Display(aShape, Standard_False);
}
}
}
Igs文件导入
void ImportExport::ReadIGES(const Handle(AIS_InteractiveContext)& anInteractiveContext,
Handle(AIS_Shape)& aShape)
{
Handle(TopTools_HSequenceOfShape) aSequence = new TopTools_HSequenceOfShape();
QString fileName = QFileDialog::getOpenFileName(nullptr,
QObject::tr("read a igs file"),
"E:",
QObject::tr("IGES Files(*.iges *.igs)"));
if(fileName.isNull())
{
qDebug() << "没有选择文件";
std::cout << "没有选择文件" << std::endl;
return;
}
qDebug() << fileName;
std::string test = fileName.toStdString();
Standard_CString aFileName = test.data();
IGESControl_Reader Reader;
Standard_Integer status = Reader.ReadFile(aFileName);
if (status != IFSelect_RetDone)
{
std::cout << "Error : The file is not read" << std::endl;
qDebug() << "Error : The file is not read";
return;
}
Reader.TransferRoots();
TopoDS_Shape tShape = Reader.OneShape();
aSequence->Append(tShape);
if (!aSequence.IsNull())
{
for(int i=1;i<= aSequence->Length();i++)
{
aShape = new AIS_Shape(aSequence->Value(i));
anInteractiveContext->SetColor(aShape,Quantity_NOC_YELLOW,Standard_False);
anInteractiveContext->SetMaterial(aShape,Graphic3d_NOM_PLASTIC,Standard_False);
anInteractiveContext->SetDisplayMode(aShape,1,Standard_False);
anInteractiveContext->Display(aShape, Standard_False);
}
}
}
位姿驱动
这里提供两种方法,一种是提供12个参数的其次RT矩阵,一个是提供6个参数的ABCXYZ参数。
void OccView::SetModelLocation(Handle(AIS_Shape)& aShape,gp_Trsf trsf)
{
Handle_AIS_InteractiveObject Current(aShape);
if(!Current.IsNull())
{
myContext->SetLocation(Current,trsf);
myContext->Update(Current,Standard_True);
}
}
void OccView::OccView::SetModelLocation_Matrix(Handle(AIS_Shape)& aShape, double* matrixTemp)
{
gp_Trsf trsf;
trsf.SetValues(matrixTemp[0],matrixTemp[1],matrixTemp[2], matrixTemp[3],
matrixTemp[4],matrixTemp[5],matrixTemp[6], matrixTemp[7],
matrixTemp[8],matrixTemp[9],matrixTemp[10],matrixTemp[11]);
SetModelLocation(aShape,trsf);
}
void OccView::SetModelLocation_Euler(Handle(AIS_Shape)& aShape, double* pTemp)
{
pTemp[0] = pTemp[0]/180*M_PI;
pTemp[1] = pTemp[1]/180*M_PI;
pTemp[2] = pTemp[2]/180*M_PI;
gp_Trsf aTrsf_Rotation;
gp_Quaternion aQ;
aQ.SetEulerAngles(gp_YawPitchRoll,pTemp[0],pTemp[1],pTemp[2]);
aTrsf_Rotation.SetRotation(aQ);
gp_Trsf aTrsf_Translation;
gp_Vec theVectorOfTrans(pTemp[3],pTemp[4],pTemp[5]);
aTrsf_Translation.SetTranslation(theVectorOfTrans);
gp_Trsf trsf = aTrsf_Translation * aTrsf_Rotation;
SetModelLocation(aShape,trsf);
}
碰撞检测
这里碰撞检测使用bool交操作,对两个模型进行bool交操作,根据交集结果进行是否碰撞判断。
bool OccView::IsCommon()
{
if(m_AISTargetBody.IsNull() || m_AISMoveBody.IsNull())
{
qDebug() << "no model imported";
return false;
}
m_TppoTargetBody = m_AISTargetBody->Shape();
m_TopoMoveBody = m_AISMoveBody->Shape();
Standard_Boolean bRunParallel;
Standard_Real aFuzzyValue;
BRepAlgoAPI_Common aBuilder;
TopTools_ListOfShape aLS;
TopTools_ListOfShape aLT;
aLS.Append(m_TppoTargetBody_cal);
aLT.Append(m_TopoMoveBody_cal);
bRunParallel=Standard_True;
aFuzzyValue=2.1e-5;
aBuilder.SetArguments(aLS);
aBuilder.SetTools(aLT);
aBuilder.SetRunParallel(bRunParallel);
aBuilder.SetFuzzyValue(aFuzzyValue);
aBuilder.Build();
if (aBuilder.HasErrors())
{
std::ofstream fout;
fout.open("errormessage.txt",std::ios_base::app);
aBuilder.DumpErrors(fout);
fout.flush();
fout.close();
qDebug() << "error";
return false;
}
const TopoDS_Shape& aR=aBuilder.Shape();
Bnd_Box B;
BRepBndLib::Add(aR, B);
double Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
if(!B.IsVoid())
{
B.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
}
int nb = aR.NbChildren();
if(!B.IsVoid())
{
std::cout << "common" << std::endl;
return true;
}
else
{
std::cout << "no common" << std::endl;
return false;
}
}
最终效果展示
![在这里插入图片描述](https://img-blog.csdnimg.cn/201911231439052.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2lhbXFpYW5yZW56aGFu,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191123143910746.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2lhbXFpYW5yZW56aGFu,size_16,color_FFFFFF,t_70)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)