当您获得本文档时,可至 RVS 开发者社区下载 unstacking_runtime.zip 拆垛教程配套数据。解压后其内容应包括:

image-20240415152204406

  • data 包含了本案例中所使用的Elite机器人模型,如果您需要其他模型请前往 RVS 软件发布模型网站下载。

  • group_xml 中提供了常用的一些 Group 组,包含保存、加载等Group,根据需要进行导入。

  • MaskRCNN适用于AI。

    • train_data :包含了 AI 训练所录制的图像和已经训练好的 pth 和 annotations.json 文件,用户直接加载 AI 所需文件时注意路径。

    • ty_ai_savedata.xml:适用于AI图像录制。

    • ty_ai_train.xml:适用于AI训练。

  • unstacking_data 为拆垛程序离线模式数据的加载,使用时请注意路径正确。

  • rgb2tcp.txt 为本案例中 Elite 机器人EyeInHand的手眼标定结果。

  • ty_color/depth_calib.txt为本案例中相机的彩色图标定参数与深度图标定参数 。

  • unstacking.xml 适用于拆垛程序,可做参考,当加载离线数据时,请先确定TyCameraSimResource 与 LoadLocalTCP Group中离线数据的路径是否正确。

案例所有使用到的文件均保存在 unstacking_runtime 下,请放在 RVS 安装目录下运行。

说明:如不想调整 XML 中的文件路径。可以将 unstacking_runtime 重命名为 runtime 。

注意:本文档所使用 RVS 软件版本为 1.7.374 ,若在使用中出现问题或版本不兼容问题,请及时与我们反馈,发送邮件 rvs-support@percipio.xyz !

拆垛流程

拆垛流程概览

自动拆垛的实际目标是:1.找到箱型几何中点 2.根据一定顺序进行抓取。具体拆垛流程可分为以下步骤:

  • 通讯接收:根据机器人发送的通讯指令触发工程。本案例使用的通讯字符串格式为“ROBOT_TCP,X,Y,Z,RX,RY,RZ#”。X,Y,Z,RX,RY,RZ为拍照时的机器人TCP位置。

  • 加载本地数据:本案例中使用离线数据完成拆垛项目。

  • 坐标系转换:将相机坐标系下的点云转到机器人坐标系下。

  • AI推理分割点云:箱子摆放紧密时使用AI推理并将箱子点云进行分割。

  • 筛选定位:识别到目标点云进行筛选排序后进行定位。

  • 通讯发送:将目标定位的位姿发送至机器人。发送的字符串格式为““ROBOT_TCP,X,Y,Z,RX,RY,RZ#”。X,Y,Z,RX,RY,RZ为目标的定位位姿。

  • 机器人抓取:使用机器人仿真进行顺序拆垛抓取。

拆垛工程演示

操作流程

  1. 加载工程。

    • 点击加载按钮,选择unstacking.xml并打开。

      load_xml

  2. 运行工程。

    • 击RVS运行按钮。

      run_xml

  3. 触发工程。

    • 离线触发。

      • 点击交互面板上离线触发按钮进行触发。

        offline_trigger

    • 在线触发。

      • 在 Resource Group 中连接图漾相机。

        说明:自动启动:运行工程自动连接图漾相机。 启动:运行工程后手动连接相机。

        connect_camera

      • 在交互面板中调整模式,刷新组合框,选择图漾相机资源。

        mode

      • 机器人发送“ROBOT_TCP,X,Y,Z,RX,RY,RZ#”。X,Y,Z,RX,RY,RZ为拍照时的机器人TCP位置。

        online_trigger

  4. 运行结果。

    • 离线模式下,每点击一次离线触发,机器人进行顺序拆垛。可以从3D视图中看出仿真机器人的抓取姿态。在交互面板中查看AI结果已经具体位姿信息。

      run_result

拆垛工程搭建

通讯接收

本案例工程通过机器人发送的通讯指令触发工程。此案例为眼在手上模式,需要发送当前的拍照位姿进行计算。

操作流程

  1. 新建工程项目并保存为 unstacking.xml。

  2. 添加 TCPServerConnectionResource 算子至 Resource Group 。(用于建立TCP通讯服务端)

    • 设置TCPServerConnectionResource算子参数:

      • 自动启动→是

      • 端口→7000

  3. 添加 TCPServerReceive 算子至算子图。(用于通讯指令触发工程运行)

    • 右击 TCPServerReceive 算子,打开算子面板:

      • 点击”+”

      • 指令→ROBOT_TCP

      • 指令分隔符→,

      • 包含数据→pose

      • 数据分隔符→,

      • 后缀→#

        TCPServerReceive算子面板配置如下:

        receive_panel

离线/在线数据

此案例中,离线数据在 unstacking_data 文件夹下,数据内容包含点云、joints、2d 图像、tcp。在线数据需要连接图漾相机以及机器人通讯来实时获取。

说明:若需要根据现场的实际情况进行拆垛流程,可连接相机与相机资源完成在线拆垛。

操作流程:

  1. 添加 两个Trigger 算子至算子图。(用于触发离线/在线工程运行)

    • 设置 Trigger 算子参数:

      • 算子名称 → 离线触发

    • 设置 Trigger_1 算子参数:

      • 算子名称 → 在线触发

  2. 从 group_xml 中导入 LoadLocalTCP.group.xml。(用于离线遍历离线机器人TCP数据)

    • 设置 LoadLocalTCP.group 的参数:

      • 父目录→unstacking_data

        说明:注意此工程的运行路径。

  3. 添加 Selector 算子至算子图。(用于选择离线或在线机器人TCP数据作为后续计算)

    • 设置 Selector 算子参数:

      • 算子名称→Selector_TCP

      • 类型→坐标

  4. 添加 TyCameraResource、TyCameraSimResource 算子至 Resource Group。(TyCameraResource 用于连接图漾相机。TyCameraSimResource 用于遍历离线点云、彩色图、深度图等数据)

    • 设置 TyCameraSimResource 算子参数:

      • 自动启动→是

      • 加载模式→目录

      • 目录→unstacking_data

      • 彩色图像文件→rgb.png

      • 深度图像文件→depth.png

      • 点云文件→cloud.pcd

      • 深度图标定文件→ty_depth_calib.txt

      • 彩色图标定文件→ty_color_calib.txt

        说明:注意此工程的运行路径。

    • 设置TyCameraResource算子参数:

      • 根据实际的图漾相机进行设置

  5. 添加 TyCameraAccess 算子至算子图。(用于输出点云、彩色图、深度图等数据)

    • 设置 TyCameraAccess 算子参数:

      • 相机资源→TyCameraSimResource

  6. 添加 Load 算子至算子图。(用于加载手眼标定结果)

    • 设置 Load 算子参数:

      • 算子名称→Load_HandEyeResult

      • 类型→坐标

      • 文件→rgb2tcp.txt

        说明:注意此工程的运行路径。

  7. 连接算子

    • 算子图连接如下图所示:

      online_offline_node

坐标系转换

加载数据后,需进行坐标系转换,将点云所处的坐标系—-相机 rgb 镜头坐标系转换至机器人坐标系。这一转换涉及相机外参及手眼标定结果。

请参考手眼标定在线文档获得实际标定结果。

离线标定结果数据存在 rgb2tcp.txt 中。

操作流程:

  1. 在算子图空白处右键选择“在这里创建新 Group 。(用于将点云转换至机器人坐标系。)

    • 设置新建 Group 参数:

      • 算子名称→点云转换至机器人坐标系

    • 连接算子端口:

      • 连接 TyCameraAccess 的结束端口Group 的开始端口

      • 连接TyCameraAccess 的点云端口Group Input 区域

      • 连接Selector_TCP 的坐标端口Group Input 区域,右击Group内侧的坐标端口进行重命名,重命名为 tcp2robot

      • 连接 Load_HandEyeResult 的坐标端口Group Input 区域,右击Group内侧的坐标端口进行重命名,重命名为rgb2tcp

        算子图连接如下图所示:

        cloud2robot_port0

  2. 添加眼在手上坐标转换、transform 至点云转换至机器人坐标系 Group 中。(眼在手上坐标转换用于计算转换矩阵。transform用于根据计算出的转换矩阵进行点云转换)

    • 设置 Transform 算子参数:

      • 类型→点云

      • 点云→ icon_visOn 可视 → icon_color -2

    • 连接算子端口:

      • 连接 Group 的启动端口眼在手上坐标转换的启动端口

      • 连接眼在手上坐标转换的结束端口Transform 的启动端口

      • 连接 Transform 的结束端口Group 的结束端口

      • 连接 Group的点云端口Transform的点云端口

      • 连接 Group的彩色图标定参数端口眼在手上坐标转换的彩色图标定参数端口

      • 连接 Group的 tcp2robot 端口眼在手上坐标转换的 tcp2robot 端口

      • 连接 Group的 rgb2tcp 端口眼在手上坐标转换的 rgb2tcp 端口

      • 连接眼在手上坐标转换的 depth2robot 端口Transform 的坐标端口

      • 连接Transform 的点云端口Group Output 区域

      • 连接眼在手上坐标转换的 rgb2robot 端口Group Output 区域

      • 连接Group的彩色图标定参数端口Group Output 区域

        算子图连接如下图所示:(双击 Group 空白处可进行折叠)

        cloud2robot_port1

AI推理分割点云

实际工作中箱型摆放较为紧密,多个箱子的上表面点云会连在一起变成不易分割的一大块点云。针对这个问题,可训练 AI 模型,在此基础上进行 AI 推理,便可获取箱子的点云列表。由于AI训练需要一定配置(详情参考 RVS 安装教程),如果未能满足配置要求,可以根据 unstacking_runtime 文件夹内提供的 pth 文件直接进行推理。总的流程将分为录制、标注、训练、推理。 采集训练图像、标注训练图像、训练AI模型教程放在 AI训练章节中。

操作流程:

  1. 添加 AI推理分割点云 至算子图中。(用于彩色图 AI 识别并将相应识别区域的点云分割为点云列表)

    • 设置 AI推理分割点云算子参数:

      • 使用设备→gpu(根据实际配置进行设置)

      • 类名文件路径→MaskRCNN/train_data/class_name.txt

      • 权重文件路径→MaskRCNN/train_data/train_output/model_final.pth

      • 配置文件路径→MaskRCNN/train_data/train_output/config.yaml

      • 物体得分阈值→0.8

        说明:注意此工程的运行路径。若算子已运行过,修改上述参数后,需要勾选重置才会将修改后的参数生效。

    • 连接算子端口:

      • 连接 点云转换至机器人坐标系的结束端口AI推理分割点云的启动端口

      • 连接 TyCameraAccess算子的彩色图端口AI推理分割点云的彩色图端口

      • 连接 点云转换至机器人坐标系的rgb2robot端口AI推理分割点云的相机坐标端口

      • 连接 点云转换至机器人坐标系的彩色图标定参数端口AI推理分割点云的彩色图标定参数端口

        算子图连接如下图所示:

        AI_node

筛选定位

通过 AI 推理获得机器人坐标系下所有检测目标的点云列表后,需获得点云中心坐标。

操作流程:

  1. 在算子图空白处右键选择“在这里创建新Group 。(用于对箱子进行筛选排序后并进行定位)

    • 设置新建 Group 参数:

      • 算子名称→筛选定位

    • 连接算子端口:

      • 连接 AI推理分割点云的结束端口Group 的开始端口

      • 连接AI推理分割点云的结束端口的点云列表端口Group Input 区域

        算子图连接如下图所示:

        FilterBox_node0

  2. 添加 FilterBoxList 算子至筛选箱子 Group 中。(用于将 Z 值最上层的箱子筛选处理,同时将筛选出的箱子按 Y 轴进行排序)

    • 设置 FilterBoxList 算子参数:

      • 类型→ByAxisZ

      • 选择模式→Z_MAX

      • 选择阈值→0.07

      • X权重→0

      • Y权重→-1

    • 连接算子端口:

      • 连接 Group 的启动端口FilterBoxList的启动端口

      • 连接 Group 的点云列表端口FilterBoxList的点云列表端口

        算子图连接如下:

        FilterBox_node1

  3. 添加 AtList 算子至筛选箱子 Group 中。(用于将排序完的箱子提取第一个目标进行定位)

    • 设置 AtList 算子参数:

      • 算子名称→GetFirstInList

      • 类型→点云

      • 模式→单个索引提取

      • 索引→0

    • 连接算子端口:

      • 连接 FilterBoxList的结束端口GetFirstInList的启动端口

      • 连接 FilterBoxList的点云列表端口GetFirstInList的点云列表端口

        算子图连接如下:

        FilterBox_node2
  4. 添加 FindElement 算子至筛选箱子 Group 中。用于(对点云进行查找平面)

    • 设置 FindElement 算子参数:

      • 算子名称→FindPlane

      • 类型→平面

      • 距离阈值→0.003

    • 连接算子端口:

      • 连接 GetFirstInList的结束端口FindPlane的启动端口

      • 连接 GetFirstInList的点云端口FindPlane的点云端口

        算子图连接如下:

        FilterBox_node3

  5. 添加 MinimumBoundingBox 算子至筛选箱子 Group 中(用于对点云进行最小包围盒定位中心)

    • 设置 MinimumBoundingBox 算子参数:

      • 算子名称→FindPlane

      • 类型→快速

      • 模式→X > Y > Z

      • 距离阈值→0.003

      • Z 轴朝向→世界坐标系 Z 轴负向

      • X 轴朝向→世界坐标系 X 轴正向

      • RX参考值→0

    • 连接算子端口:

      • 连接 FindPlane的结束端口MinimumBoundingBox的启动端口

      • 连接 FindPlane的点云端口MinimumBoundingBox的点云端口

      • 连接 MinimumBoundingBox的结束端口Group的结束端口

      • 连接 MinimumBoundingBox的包围立方体中心坐标端口Group的Output区域

        算子图连接如下:

        FilterBox_node4

通讯发送

操作流程

  1. 添加 TCPServerSend 算子至算子图。(用于将定位出的位姿发送至机器人)

    • 右击 TCPServerSend 算子,打开算子面板:

      • 点击”+”

      • 端口名→ROBOT_TCP

      • 数据类型→Pose

      • 前缀→ROBOT_TCP,

      • 数据分隔符→,

      • 后缀→#

        TCPServerReceive算子面板配置如下:

        send_panel

        说明:通讯字符串格式可自定义。本案例格式为:“ROBOT_TCP,X,Y,Z,RX,RY,RZ#” 。

  2. 连接算子。

    • 算子图连接如下图所示:send_node

机器人仿真抓取

在完成上述操作后,获得了目标点坐标,需要通过加载机器人模型,模拟抓取。

操作流程

  1. 添加 SimulatedRobotResource 至 Resource Group中。(用于加载仿真机器人模型)

    • 设置 SimulatedRobotResource 算子参数:

      • 自动启动→是

      • 机器人模型文件→data/EC66/EC66.rob

      • 工具模型文件→data/Tool/EliteRobotSucker2.tool.xml

      • 机器人→ icon_visOn 可视

  2. 添加 Trigger 算子至算子图。(用于初始化触发运行)

    • 设置 Trigger 算子参数:

      • 算子名称→InitTrigger

      • 类型→初始化触发器

  3. 添加 RobotMovement 算子至算子图。(用于仿真机器人移动关节,通过自定义关节值运行至初始位姿)

    • 设置 RobotMovement 算子参数:

      • 算子名称 → MoveToJoints

      • 类型 → 移动关节

      • 关节 → 0 -1.495489955 1.512199998 -1.627550006 1.499660015 -0.04329660162

    • 连接算子端口。

      • 连接 InitTrigger 的结束端口MoveToJoints 的开始端口

        算子连接如下:

        movetojoint_node

  4. 添加 RobotMovement 算子至算子图。(用于仿真机器人移动 TCP,通过定位位姿将仿真机器人进行运动)

    • 设置 RobotMovement 算子参数:

      • 算子名称 → MoveToPose

      • 类型 → 移动TCP

      • 关节 → 0 -1.495489955 1.512199998 -1.627550006 1.499660015 -0.04329660162

      • 作为工具坐标→是

    • 连接算子端口。

      • 连接 筛选定位的结束端口MoveToPose的开始端口

      • 连接 筛选定位的包围立方体中心坐标端口MoveToPose的goal_pose端口

      • 连接 MoveToJoints的关节端口MoveToPose的参照关节端口

        连接算子图如下:

        movetopose_node

完整的 XML 已提供 在unstacking_runtime/unstacking.xml 路径下。

交互面板创建

交互面板中的工具可以与算子图中算子属性的曝光和输出进行绑定,输入工具可以快速修改算子属性参数,输出工具可以快速查看算子的输出结果。

  1. 编辑交互面板

    • 右击交互面板,选择解锁,此时交互面板进入编辑状态

  2. 添加输入工具的 标签组合框至交互面板中

    • 标签

      • 双击”label”,修改名称为“模式:”

    • 组合框

      • 在算子图中找到 TyCameraAccess 算子,在属性面板中将相机资源的曝光light打开

      • 右击组合框,选择显示控件面板

      • 在曝光参数中选择 MainGroup/TyCameraAccess 参数框,点击绑定icon按钮

      • 点击确定,该算子参数与该控件绑定成功

  3. 添加输入工具按钮(两个)

    • 按钮

      • 双击”button”,修改名称为“离线触发”

      • 在算子图中找到 离线触发算子,在属性面板中将触发器的曝光light打开

      • 右击按钮,选择显示控件面板

      • 在曝光参数中选择 MainGroup/离线触发参数框,点击绑定icon按钮

      • 点击确定,该算子参数与该控件绑定成功

    • 按钮

      • 双击”button”,修改名称为“在线触发”

      • 在算子图中找到 在线触发算子,在属性面板中将触发器的曝光light打开

      • 右击按钮,选择显示控件面板

      • 在曝光参数中选择 MainGroup/在线触发参数框,点击绑定icon按钮

      • 点击确定,该算子参数与该控件绑定成功

  4. 添加输入工具的 标签、输出工具的2D图片至交互面板中

    • 标签

      • 双击”label”,修改名称为“AI结果:”

    • 2D图片

      • 在算子图中找到 AI推理分割点云,在属性面板中将show_result_visibility的可视化打开

      • 右击2D图片,选择显示控件面板

      • 在曝光参数中选择 MainGroup/AI推理分割点云/AIDetect 参数框,点击绑定icon按钮

      • 点击确定,该算子参数与该控件绑定成功

  5. 添加输入工具的 表格至交互面板中

    • 表格

      • 在算子图中找到 MinimumBoundingBox 算子,在属性面板中将包围立方体中心坐标的可视化icon_visOn打开

      • 右击表格,选择显示控件面板

      • 在曝光参数中选择 MainGroup/筛选定位./MinimumBoundingBox 参数框,点击绑定icon按钮

      • 点击确定,该算子参数与该控件绑定成功

    交互面板创建如下:

    dashboard

AI训练

本章节主要目标为讲解采集训练图像、标注训练图像、训练AI模型。总的流程将分为采集、标注、训练。

说明:AI训练需要一定配置,详情参考下载与安装RVS

采集训练图像

打开 unstacking_runtime/MaskRCNN/ty_ai_savedata.xml,内容基本与录制 RGB 图像一致,在这里我们只需要调整 Emit 中的 string 参数,设置为我们想要的路径即可。点击 Capture 按钮录制图像。录制图像数量保证在 10 张以上,越多越好。

ai

在图像采集时,我们应注意以下几点:

  1. 背景光照

    • 单一稳定光源,亮暗适宜且没有过多反光。

    • 户外光照情况变化过大,不建议。

  2. 复杂工况考虑:尽量使得采样样本对实际运行的全局样本有足够的代表性而不仅仅是全局样本的一种特例

    • 目标物件多样化,尽量不选用固定单一目标物体。如果当前可供使用的样本数目比较少,可以考虑将样本正反两个面(两个面一样)都使用来倍增样本。

    • 工况多样化,对于目标物体,尽可能多的考虑其在工况中出现的情形,多情况拍摄:

      • 如果项目中垛车大小、垛车姿态、目标在垛车中的姿态、目标外形外观等有多种情形,则我们采集的训练数据应该把这些多样化的情形都囊括到。

      • 要充分考虑训练样本同实际运行样本的偏差余量。比如垛车只有水平摆放一种姿态,我们在训练数据的时候也要考虑到给垛车增加小角度的倾斜,因为实际中不可能完美水平。再比如实际运行的都是机器摆放,目标两两比较贴近,在我们在录制训练集数据的时候,如果用的是人为摆放,则一定要保证目标两两比较贴近,而不是随意摆放导致目标两两之间间隙松散。

      • 对于少部分的可能出现的目标破损褶皱等情况,虽然很少出现,但是如果项目实际有识别的需要,则要专门寻找较多的破损目标进行数据采集,虽然最后在训练样本中破损目标占的比例大于破损目标在实际样本中占有的比例,但是这也很有意义。

  3. 图像质量

    • 人眼需清晰可见目标边缘,尤其是距离相机最远的那层目标,否则考虑更换相机具体图像录制可以参考 unstacking_runtime/MaskRCNN/train_data 中的rgb 图像

为训练图像进行标注

点击菜单栏image-20231020182747977图像标注工具即可打开标注工具。

标注前准备

  1. 首先确定任务目标,明确在检测过程中什么物体需要被检测,什么物体不需要被检测,从而有针对性的进行标注。

  2. 给定的标注条件无需过分苛刻,不要按照人的思维去考虑,而是按照自己主观设定的标注思路是否便于落实代码。

标注图像

  1. 打开labelme软件,点击 OpenDir按钮,选择标注的路径。

    labme

  2. 点击 Create Polygons按钮,为箱子绘制红色的边框,绘制完成后如下图所示。

    说明:支持 Create Polygons 、Create Circle、Create Rectangle 三种标注方式。

    openlabelme

  3. 完成后会弹出命名框,第一次命名为:box,后续同类直接选择即可。

    box

  4. 当图像内所有箱子标注完成后,点击 Save 进行保存,默认当前文件夹,默认名称即可,随后选择 Next Image 切换到下一个图像。

    next_image

在标注过程中应当注意以下几点:

  1. 标记物体可见区域的边界框(不是估计的物体总范围)。

  2. 标注画框结束,注意做边界检查,比如确保框坐标不在图像边界上。

  3. 质量较差的图像(例如过度运动模糊),部分遮挡的目标,结合项目目标需求选择标注或舍弃。

应尽量避免以下问题:

  • 边界标注不准

    label1

  • 遗漏

label2

  • 被遮挡部分不应该标注

label3

训练AI模型

打开 unstacking_runtime/MaskRCNN/ty_ai_train.xml ,这里我们只需要调整数据目录类名文件路径路径。触发 generate_jsonfile 开始训练。 最终会生成一个 train_output 文件夹,在这个文件夹中有命名为 model_final.pth(默认可更改),是我们所需要的权重文件。

注意:AITrain 算子数据目录和类名文件路径中不支持中文与空格。

aiTrain