
简介这份资源是一套基于Qt框架与OpenCASCADE几何内核构建的工业机器人仿真与路径规划系统源码面向机器人研发工程师、自动化专业学生及需要搭建仿真验证环境的技术人员。系统支持ABB与ROKAE两大品牌机器人建模集成碰撞检测与RRT路径规划算法并可通过TCPIP通讯协议将规划结果下发至真实机器人适合用于算法验证、教学演示与工程预研。压缩包共约2000个文件以1175个C/C头文件与728个cpp源文件为主体辅以txt说明、json配置、md文档及少量Python、Shell脚本整体约169.61MB工程结构完整、模块划分清晰。目前已有177人学习下载。读者可从中获取完整的机器人建模、碰撞检测、RRT路径规划与通讯控制实现思路对照源码理解各模块协作方式并在此基础上进行二次开发或功能裁剪。1. 从一台 ABB 机器人说起这套 Qt OpenCASCADE 仿真系统到底能干什么去年帮一个做焊接集成的朋友排查问题他现场那台 ABB IRB 2600 在示教器上跑得好好的换了个工件之后轨迹就撞夹具。停机改代码、重新示教、再试一天下来没跑通几条路径。他问我有没有办法先在电脑上把机器人模型和工件摆出来把路径跑一遍看会不会撞确认没问题再下发到真机。这个需求其实非常典型——工业机器人仿真与路径规划要解决的就是这件事在虚拟环境里把机器人、工件、夹具搭起来用算法算出一条无碰撞的轨迹再通过通讯把关节角或位姿发给真实控制器。这套资源就是围绕这个场景做的基于Qt 框架做界面和交互用OpenCASCADE 几何内核处理三维模型和碰撞检测内置RRT 路径规划算法支持ABB 和 ROKAE珞石两类机器人的建模并且能通过TCP/IP 通讯把规划结果下发到真实机器人。它适合三类人做机器人集成的现场工程师、研究路径规划算法的学生、以及需要快速搭一个仿真验证环境但不想从零造轮子的开发者。下面我按「资源是什么 → 怎么用 → 坑在哪」的顺序拆开讲能抄的代码和参数我都放出来。2. 环境搭建与工程结构Qt 5.15 OpenCASCADE 7.6 怎么配才不翻车2.1 为什么是 Qt 5.15 而不是 Qt 6这套工程用的是 Qt 5.15.2 的 MSVC2019 64bit 套件不是 Qt 6。原因很实际OpenCASCADE 7.6 的官方预编译包和 CMake 配置文件对 Qt 5 的支持最成熟Qt 6 的 CMake 模块名和部分 API 有变动直接迁过去会在Qt5Config.cmake和Qt6Config.cmake的查找逻辑上卡住。热搜里有人问「qt 编译时候 cannot find -lpublic」和「unknown module(s) in qt: webenginewidgets」前者通常是 OpenCASCADE 的库路径没进LIBS后者是装了 Qt 6 但工程还在找 Qt 5 的 WebEngine 模块——这套工程不需要 WebEngine遇到这个报错直接检查.pro或CMakeLists.txt里有没有多余的QT webenginewidgets。安装顺序建议先装 Visual Studio 2019带 C 桌面开发负载再装 Qt 5.15.2 并勾选 MSVC2019 64bit 组件最后装 OpenCASCADE 7.6。三者位数必须一致全是 64 位。装完 Qt 后如果发现只有 MinGW 没有 MSVC 套件去 Qt Maintenance Tool 里补装 MSVC 编译工具链热搜里「qt 按照完 mingw 编译器后怎么安装 msvc 编译工具链」问的就是这一步。2.2 工程目录与关键文件解压后的工程大致是这样一个结构我按实际会碰到的文件列一下目录/文件作用是否要改RobotSim.proqmake 工程文件声明 Qt 模块和 OCCT 库要改库路径src/main.cpp程序入口初始化 QApplication一般不动src/MainWindow.*主窗口承载 3D 视图和控件按需改src/OCCView.*OpenCASCADE 视图封装负责显示和拾取核心慎改src/RobotModel.*机器人 DH 参数与连杆建模换机器人要改src/CollisionDetector.*碰撞检测封装调精度要改src/RrtPlanner.*RRT 路径规划实现调算法要改src/TcpClient.*TCP/IP 通讯下发轨迹改 IP 和端口models/ABB、ROKAE 的 STEP/IGES 模型可替换.pro文件里最关键的是 OpenCASCADE 的库声明常见写法是这样# RobotSim.pro 关键片段 QT core gui widgets opengl # OpenCASCADE 头文件与库路径按自己安装位置改 OCCT_DIR C:/OpenCASCADE-7.6.0 INCLUDEPATH $$OCCT_DIR/inc LIBS -L$$OCCT_DIR/win64/vc14/lib # 按需链接 OCCT 模块全链会拖慢编译 LIBS -lTKernel -lTKMath -lTKG2d -lTKG3d -lTKGeomBase LIBS -lTKBRep -lTKTopAlgo -lTKPrim -lTKBO -lTKBool LIBS -lTKOpenGl -lTKService -lTKV3d -lTKHLR这段配置的逻辑是INCLUDEPATH告诉编译器去哪找 OCCT 头文件LIBS的-L指定库目录后面一串-l是按模块链接。TKernel和TKMath是基础TKBRep和TKTopAlgo管拓扑和建模TKBO/TKBool是布尔运算碰撞检测会用到TKOpenGl/TKV3d负责显示。参数上唯一要改的是OCCT_DIR指向你自己的安装路径。如果链接时报cannot find -lTKxxx先确认win64/vc14/lib下有没有对应的.lib再确认位数是不是 64 位。2.3 编译与首次运行用 Qt Creator 打开.pro选 MSVC2019 64bit 套件直接构建。第一次编译大概三到五分钟。运行后如果 3D 视图是黑的但控件正常八成是 OpenGL 上下文没建起来检查显卡驱动或者在main.cpp里显式设置QSurfaceFormat// main.cpp 里设置 OpenGL 格式避免部分机器黑屏 QSurfaceFormat fmt; fmt.setDepthBufferSize(24); fmt.setStencilBufferSize(8); fmt.setVersion(3, 3); fmt.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(fmt);setDepthBufferSize(24)保证深度测试正常不然模型会前后穿插setVersion(3,3)和CoreProfile是让 OCCT 的TKOpenGl走现代管线。这一步不做在某些集显机器上就是黑屏或者花屏属于血泪经验。3. 机器人建模与碰撞检测DH 参数怎么填、碰撞对怎么配3.1 ABB 与 ROKAE 的建模差异这套系统对两类机器人的建模走的是同一条路用 DH 参数描述连杆关系再用 OpenCASCADE 把每个连杆的几何体STEP 或 IGES按 DH 变换摆到正确位置。ABB 的模型在models/abb/下ROKAE 在models/rokae/下。区别在于 DH 参数表和关节零位定义不同ABB 的零位和 ROKAE 的零位不能混用换机器人时必须同时换模型文件和 DH 参数。RobotModel里一般会有一个 DH 参数表长这样// 六轴机器人 DH 参数a/alpha/d/theta 单位分别为 mm 和 rad struct DHParam { double a, alpha, d, theta; }; std::vectorDHParam dh { { 0.0, -M_PI/2, 290.0, 0.0 }, // J1 { 270.0, 0.0, 0.0, -M_PI/2 }, // J2 { 70.0, -M_PI/2, 0.0, 0.0 }, // J3 { 0.0, M_PI/2, 302.0, 0.0 }, // J4 { 0.0, -M_PI/2, 0.0, 0.0 }, // J5 { 0.0, 0.0, 72.0, 0.0 } // J6 };每个DHParam的四个量对应标准 DH 约定a是连杆长度alpha是连杆扭角d是连杆偏距theta是关节角。前三个是机器人固有参数从手册查theta是变量由关节角驱动。这里填的是示例值实际用哪台机器人就照它的手册填填错了模型会歪碰撞检测也跟着错。常见做法是先用示教器把机器人摆到零位量一下各关节的实际角度反推 DH 参数是否对得上。3.2 碰撞检测的配置与精度碰撞检测用的是 OpenCASCADE 的布尔相交判断把两个形状做BRepAlgoAPI_Common如果结果非空就说明相交。核心代码大致是这样// CollisionDetector.cpp 判断两个 TopoDS_Shape 是否碰撞 bool CollisionDetector::isColliding(const TopoDS_Shape a, const TopoDS_Shape b) { BRepAlgoAPI_Common common(a, b); common.SetFuzzyValue(0.1); // 容差单位与模型一致 common.Build(); if (!common.IsDone()) return false; // 计算失败按不碰撞处理 return !common.Shape().IsNull(); // 有交集即碰撞 }SetFuzzyValue(0.1)是容差单位跟模型一致这里是 mm。容差太小两个面贴在一起会误判为碰撞太大本来该撞的又漏判。我一般从 0.1 开始试工件和夹具间隙在 1mm 以上时够用。IsDone()返回 false 说明布尔运算失败可能是形状本身有问题比如自相交这时候要回去检查 STEP 模型。碰撞对不是所有连杆两两都算那样太慢。常见做法是只检测「可能相撞」的组合相邻连杆不算它们本来就挨着末端工具和工件、工件和夹具、机器人和围栏这些才算。配置一般放在一个列表里// 碰撞对配置first/second 是形状索引 std::vectorstd::pairint,int pairs { {TOOL_ID, WORKPIECE_ID}, {WORKPIECE_ID, FIXTURE_ID}, {ROBOT_BASE_ID, FENCE_ID} };这样能把检测次数从几十次降到几次实时性才够。如果发现规划出来的路径明明会撞却没报先查这个列表有没有漏配。3.3 把模型摆到正确位置模型导入后默认在原点要按工件坐标系摆。用gp_Trsf做变换// 把工件按给定位姿摆到工作台 gp_Trsf trsf; trsf.SetTranslation(gp_Vec(x, y, z)); gp_Quaternion q(gp_Vec(1,0,0), angle); // 绕轴旋转 trsf.SetRotation(q); BRepBuilderAPI_Transform xform(workpiece, trsf, true); TopoDS_Shape placed xform.Shape();SetTranslation平移SetRotation旋转BRepBuilderAPI_Transform的第三个参数true表示复制不改原形状。位姿数据一般来自标定或者图纸摆错了后面全错。我习惯摆完之后在视图里量一下关键尺寸跟图纸对一遍再往下走。4. RRT 路径规划与 TCP/IP 下发从算法到真机的最后一公里4.1 RRT 在关节空间还是笛卡尔空间这套系统的 RRT 跑在关节空间也就是在六个关节角组成的六维空间里采样。为什么不用笛卡尔空间因为笛卡尔空间的碰撞检测要反复做逆解慢且容易碰到奇异点。关节空间直接采样关节角正解算末端位姿再做碰撞检测流程更顺。RRT 的核心是「随机采样 最近邻扩展 碰撞检查」// RrtPlanner.cpp 单次扩展 Node RrtPlanner::extend(const Node nearest, const Node rand) { // 朝随机点方向走一步步长 stepSize Node newNode steer(nearest, rand, stepSize); if (!isStateValid(newNode)) return nearest; // 无效就退回 tree.addNode(newNode); tree.addEdge(nearest, newNode); return newNode; } bool RrtPlanner::isStateValid(const Node n) { // 正解算末端再对所有碰撞对做检测 auto shapes forwardKinematics(n); for (auto p : collisionPairs) if (detector.isColliding(shapes[p.first], shapes[p.second])) return false; return true; }stepSize是每次扩展的步长关节空间里单位是弧度一般取 0.1 到 0.3。太小收敛慢太大容易跳过窄通道。isStateValid是性能瓶颈每次都要正解加碰撞检测所以碰撞对要精简。如果规划一直失败先看stepSize是不是太大再看碰撞对是不是配多了导致可行域被误判没了。4.2 双向 RRT 与路径平滑单向 RRT 在窄通道里收敛慢热搜里「双向 rrt」就是针对这个的改进从起点和终点各长一棵树交替扩展两棵树接上就停。这套系统里可以切换单向和双向双向的收敛速度在复杂场景下能快好几倍。规划出来的原始路径是折线关节角跳变直接下发会抖所以要做平滑// 对原始路径做 shortcut 平滑 Path RrtPlanner::smooth(const Path raw, int iters) { Path p raw; for (int i 0; i iters; i) { int a rand() % p.size(); int b rand() % p.size(); if (a b) std::swap(a, b); if (canConnect(p[a], p[b])) { // 两点间直线无碰撞 p.erase(p.begin()a1, p.begin()b); } } return p; }canConnect在两点之间插值采样逐点做碰撞检测全通过才删中间点。iters取 50 到 200越多越平滑但越慢。平滑完的路径关节角变化连续下发到真机才不抖。4.3 TCP/IP 下发到真实机器人下发走 TCP/IP机器人控制器当服务端这套系统当客户端。ABB 一般用 5000 端口具体看控制器配置ROKAE 的端口和协议要查它的通讯手册。核心代码// TcpClient.cpp 连接并下发轨迹 bool TcpClient::connectToRobot(const QString ip, quint16 port) { socket.connectToHost(ip, port); return socket.waitForConnected(3000); // 3 秒超时 } void TcpClient::sendTrajectory(const Path path) { QByteArray buf; for (const auto node : path) { for (double j : node.joints) { buf.append(QString::number(j, f, 4).toUtf8()); buf.append(,); } buf.append(;); } socket.write(buf); socket.flush(); }connectToHost后必须waitForConnected不然连没连上不知道。sendTrajectory把每个路径点的六个关节角拼成字符串点之间用;分隔关节角之间用,分隔。这个格式是自定义的真机端要写对应的解析。下发前一定要在仿真里把整条路径再跑一遍碰撞检测确认无碰撞再发不然真机撞了就是事故。我一般会先在低速模式下试跑第一条确认没问题再放开速度。5. 避坑与排查这几类问题我踩过不止一次5.1 编译期找不到 OCCT 库现象链接报cannot find -lTKernel或一堆undefined reference。原因LIBS里的库路径不对或者位数不匹配32 位库配 64 位工程。解决确认OCCT_DIR/win64/vc14/lib存在且是 64 位把-L路径写成绝对路径别用相对路径。如果还不行用dumpbin /headers xxx.lib看库的机器类型是不是 x64。5.2 运行后 3D 视图黑屏现象窗口出来了控件正常但三维区域全黑。原因OpenGL 上下文没建起来或者显卡驱动太旧。解决在main.cpp里显式设置QSurfaceFormat见 2.3 的代码更新显卡驱动。如果是远程桌面里跑某些 OpenGL 版本不支持换本地跑。5.3 碰撞检测误报或漏报现象明明没碰却报碰撞或者碰了却不报。原因SetFuzzyValue容差设得不合适或者碰撞对配错。解决容差从 0.1 开始调间隙大的场景可以到 0.5检查碰撞对列表确认该检测的组合都在里面不该检测的比如相邻连杆没在里面。5.4 RRT 规划一直失败现象跑很久都找不到路径。原因stepSize太大跳过窄通道或者碰撞对配多了把可行域误判没了或者起点终点本身就在碰撞状态。解决先把stepSize降到 0.1再检查起点终点的isStateValid是不是 true最后精简碰撞对。如果还不行换双向 RRT。5.5 下发后真机不动或报错现象仿真里跑得好好的发下去真机没反应或者报通讯错误。原因IP 或端口不对或者数据格式跟控制器要求的不一致。解决先用ping确认网络通再用调试工具比如nc或串口助手手动发一条测试指令看控制器回什么。数据格式一定要照控制器手册来别自己发明。6. 进阶把 RRT 换成双向 动态重规划的一个实用技巧前面讲的都是静态场景工件摆好规划一次下发。但实际现场经常有动态障碍比如变位机在动、另一个机器人也在同一工作区。这时候一次性规划不够用得做动态重规划。我的做法是在 RRT 外面套一层循环每隔固定时间比如 200ms重新检测当前路径是否还有效无效就以上一个有效路径点为起点重新规划。// 动态重规划循环 Path current planner.plan(start, goal); while (!reached(goal)) { QThread::msleep(200); if (!planner.pathStillValid(current)) { Node newStart current.front(); // 从当前点重新规划 current planner.plan(newStart, goal); } tcpClient.sendTrajectory(current); }pathStillValid对整条路径逐点做碰撞检测newStart取当前路径的第一个点保证重规划从机器人当前位置开始不会跳。QThread::msleep(200)是重规划周期太快浪费算力太慢反应不过来200ms 是个折中。这个循环要放在独立线程里别阻塞界面。验证方法很简单在仿真里放一个会动的障碍物看机器人能不能绕开。我一般会先让障碍物慢速移动确认重规划触发正常再加速。如果发现机器人卡住不动先看pathStillValid是不是一直返回 false可能容差太小再看重规划有没有真的执行加日志。从那以后我每次下发真机之前都强制走一遍「仿真全路径碰撞检测 低速试跑第一条」的流程不管多急都不跳。这套 Qt OpenCASCADE 的仿真系统把建模、碰撞、规划、通讯串成了一条线省掉的是现场反复示教的时间值不值得下看你有没有被真机撞过。希望帮到你。本文还有配套的精品资源点击获取