openpnp - 接入西门子二手飞达

news2024/10/6 16:19:40

文章目录

    • openpnp - 接入西门子二手飞达
    • 概述
    • 笔记
    • 编译生产用的飞达控制板工程
    • 建立飞达控制板GCode驱动
    • create actuators
    • create actuators - GetID
    • create actuators - PrePick
    • create actuators - PostPick
    • create actuators - AdvIgnoreErr
    • create actuators - GetCount
    • create actuators - ClearCount
    • create actuators - GetPitch
    • create actuators - TogglePitch
    • create actuators - GetStatus
    • 在飞达控制板的gcode驱动中添加G码
    • 在openpnp中添加西门子电动飞达
    • 为西门子飞达上面每一位子飞达都建立一个基准点封装
    • 飞达的子飞达号码的判断
    • 飞达ID的约定
    • 为这个测试飞达的子飞达0添加一个openpnp飞达
    • 先手工添加一个SlotSchultzFeeder
    • 设置取料的位置
    • 补充 - 轴的移动范围可以跨零点
    • 补充 - 如果料盘摆歪了会导致送料错误
    • 补充 - 飞达的物料在编带内的旋转角度和散料飞达不一样
    • 子飞达1的添加
    • 备注
    • 备注
    • END

openpnp - 接入西门子二手飞达

概述

SchultzFeeders官方直接给的例子, 让新手用户直接将作者给的配置贴到machine.xml中.
如果以后opepnp升级了, 配置文件格式变了, 这么硬改, 可能会有问题. 因为无法确定自己用的openpnp版本, 是否认得这些xml字段
有些UID字段, 让openpnp自动生成好一些, 万一重复了呢?

我的想法是将作者给的例子整理出来, 看明白了, 然后用openpnp界面填入, 这样等openpnp升级了(或者在不同版本的openpnp中接入二手西门子飞达), 也不会有任何问题.

官方文档给的操作步骤也可以优化, 要不小白有点晕.
最开始时(设备都没调试好, 处于最初的小白状态), 自己按照SchultzFeeders官方配置过西门子电动飞达, 配置的效果都不对, 也不知道哪里做错了.
现在接触了openpnp有一段时间了, 看着官方给的文档, 只要看个大概, 自己就能知道怎么活学活用.

笔记

如果在openpnp中改了内容, 在切换到其他UI之前, 一定要保存(当前页面右小角有应用按钮), 否则再回到此页面, 参数就丢了.

编译生产用的飞达控制板工程

将工程中的DEBUG宏去掉, 重新编译上传.
保证串口收发不会有多余的内容.
将飞达控制板连接到PC机USB串口.

建立飞达控制板GCode驱动

在这里插入图片描述
手工取得固件版本信息, 等于是执行了M115
在这里插入图片描述
现在一个空的飞达控制板驱动就建立好了

发现有时通讯超时, 将等待时间改长一些, 如果飞达控制板处于空闲状态, 可以很快回包. 如果飞达控制板正在重启或忙于其他任务, 也可以等待回包, 不至于让openpnp操作飞达控制板时报错. 将进给速度改慢点, 因为通讯速度没那么快. 看情况调整.
在这里插入图片描述

create actuators

作者给的例子一共有9个actuator, 逐个整理, 然后在openpnp中逐个手工添加动作.
actuator的名字, 将动作放在前面, Schultz放在后面, 防止手工操作动作时, 看不全名称, e.g. GetID_Schultz
每个添加的西门子飞达动作, 用到的驱动, 都选择上面自己建立的实际飞达控制板串口GCode驱动Schultz_Driver.

create actuators - GetID

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzGetID" 
name="SchultzGetID" 
value-type="Double" 
value-type-confirmed="true" 
default-on-double="0.0" 
default-on-string="" 
default-off-double="0.0" 
default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 

coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 

enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">

       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

看到要建立的Actuator类型是ReferenceActuator
Actuator建立的位置是设备树根目录下的Actuator
值类型是Double, 默认值是0
coordinated-before-actuate=“false”
coordinated-after-actuate=“false”
coordinated-before-read=“false”

enabled-actuation=“LeaveAsIs”
homed-actuation=“LeaveAsIs”
disabled-actuation=“LeaveAsIs”
这6个和UI上都对的上

index = 0

将以上整理后看到的内容填入UI

在这里插入图片描述

create actuators - PrePick

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzPrePick" name="SchultzPrePick" 
value-type="Double" 
value-type-confirmed="true" 
default-on-double="0.0" 
default-on-string="" 
default-off-double="0.0" 
default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">

       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>
    

在这里插入图片描述

create actuators - PostPick

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzPostPick" 
name="SchultzPostPick" // PostPick_Schultz
value-type="Double" 
value-type-confirmed="true" 
default-on-double="0.0" 
default-on-string="" 
default-off-double="0.0" 
default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述
现在按照官方资料加了3个动作, 可以看到这些动作只有名称不一样.

create actuators - AdvIgnoreErr

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzAdvIgnorErr" 
name="SchultzAdvIgnoreErr" // AdvIgnoreErr_Schultz
value-type="Double" 
value-type-confirmed="true" 
default-on-double="0.0" 
default-on-string="" 
default-off-double="0.0" 
default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

create actuators - GetCount

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzGetCount" 
name="SchultzGetCount" // GetCount_Schultz
value-type="Double" 
value-type-confirmed="true" 
default-on-double="0.0" 
default-on-string="" 
default-off-double="0.0" 
default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">

       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

create actuators - ClearCount

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzClearCount" name="SchultzClearCount" // ClearCount_Schultz
value-type="Double" value-type-confirmed="true" default-on-double="0.0" default-on-string="" default-off-double="0.0" default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

create actuators - GetPitch

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzGetPitch" name="SchultzGetPitch" // GetPitch_Schultz
value-type="Double" value-type-confirmed="true" default-on-double="0.0" default-on-string="" default-off-double="0.0" default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" 
coordinated-after-actuate="false" 
coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" 
homed-actuation="LeaveAsIs" 
disabled-actuation="LeaveAsIs" 
index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

create actuators - TogglePitch

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzTogglePitch" 
name="SchultzTogglePitch" // TogglePitch_Schultz
value-type="Double" value-type-confirmed="true" default-on-double="0.0" default-on-string="" default-off-double="0.0" default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" coordinated-after-actuate="false" coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" homed-actuation="LeaveAsIs" disabled-actuation="LeaveAsIs" 
index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

create actuators - GetStatus

<actuator 
class="org.openpnp.machine.reference.ReferenceActuator" 
id="actSchultzGetStatus" name="SchultzGetStatus" // GetStatus_Schultz
value-type="Double" value-type-confirmed="true" default-on-double="0.0" default-on-string="" default-off-double="0.0" default-off-string="" 
interlock-actuator="false" 
driver-id="DRV1685dcff7c76eec8" 
coordinated-before-actuate="false" coordinated-after-actuate="false" coordinated-before-read="false" 
enabled-actuation="LeaveAsIs" homed-actuation="LeaveAsIs" disabled-actuation="LeaveAsIs" 
index="0">
       <head-offsets units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>
    </actuator>

在这里插入图片描述

在飞达控制板的gcode驱动中添加G码

也是将官方例子整理好, 然后通过UI来添加.

<driver class="org.openpnp.machine.reference.driver.GcodeDriver" 
id="DRV1685dcff7c76eec8" name="Schultz" 
motion-control-type="ToolpathFeedRate" 
communications="serial" connection-keep-alive="false" 
units="Millimeters" max-feed-rate="1000" 
backlash-offset-x="-1.0" backlash-offset-y="-1.0" backlash-offset-z="0.0" backlash-offset-r="0.0" 
non-squareness-factor="0.0" 
backlash-feed-rate-factor="0.1" timeout-milliseconds="5000" connect-wait-time-milliseconds="3000" visual-homing-enabled="true" 
backslash-escaped-characters-enabled="false" remove-comments="true" 
compress-gcode="false" logging-gcode="false" supporting-pre-move="false" using-letter-variables="true" infinity-timeout-milliseconds="60000">
       <serial line-ending-type="LF" port-name="COM3" baud="115200" flow-control="RtsCts" data-bits="Eight" stop-bits="One" parity="None" set-dtr="false" set-rts="false" name="SerialPortCommunications"/>
       <tcp line-ending-type="LF" ip-address="127.0.0.1" port="23" name="TcpCommunications"/>

       // 以上就是一个GCode串口驱动, 说明以下G码是在飞达控制板中添加的

       
       <simulated line-ending-type="LF"/>
       <homing-fiducial-location units="Millimeters" x="0.0" y="0.0" z="0.0" rotation="0.0"/>

       <detected-firmware><![CDATA[FIRMWARE_NAME: Schultz Feeder Controller, FIRMWARE_VERSION: 2.0]]></detected-firmware>

      // 驱动默认的命令响应正则内容

         // COMMAND_CONFIRM_REGEX 内容为 ^ok.*
       <command type="COMMAND_CONFIRM_REGEX">
          <text><![CDATA[^ok.*]]></text> 
       </command>

         // COMMAND_ERROR_REGEX 内容为 ^error.*
       <command type="COMMAND_ERROR_REGEX">
          <text><![CDATA[^error.*]]></text>
       </command>


      // 动作命令对应的G码

      // GetID => ACTUATOR_READ_COMMAND => M610N{IntegerValue}
       <command head-mountable-id="actSchultzGetID" type="ACTUATOR_READ_COMMAND">
          <text><![CDATA[M610N{IntegerValue}]]></text>
       </command>


      // GetID => ACTUATOR_READ_REGEX => ^ok.*ID: (?<Value>.+)
       <command head-mountable-id="actSchultzGetID" type="ACTUATOR_READ_REGEX">
          <text><![CDATA[^ok.*ID: (?<Value>.+)]]></text>
       </command>

       // PrePick => ACTUATE_DOUBLE_COMMAND => M600N{IntegerValue}
       <command head-mountable-id="actSchultzPrePick" type="ACTUATE_DOUBLE_COMMAND">
          <text><![CDATA[M600N{IntegerValue}]]></text>
       </command>

       // PostPick => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}
       <command head-mountable-id="actSchultzPostPick" type="ACTUATE_DOUBLE_COMMAND">
          <text><![CDATA[M601N{IntegerValue}]]></text>
       </command>

       // AdvIgnorErr => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}X1
       <command head-mountable-id="actSchultzAdvIgnorErr" type="ACTUATE_DOUBLE_COMMAND">
          <text><![CDATA[M601N{IntegerValue}X1]]></text>
       </command>

       // GetCount => ACTUATOR_READ_COMMAND => M603N{IntegerValue}
       <command head-mountable-id="actSchultzGetCount" type="ACTUATOR_READ_COMMAND">
          <text><![CDATA[M603N{IntegerValue}]]></text>
       </command>

       // GetCount => ACTUATOR_READ_REGEX => ^ok.*count: (?<Value>\d+).*
       <command head-mountable-id="actSchultzGetCount" type="ACTUATOR_READ_REGEX">
          <text><![CDATA[^ok.*count: (?<Value>\d+).*]]></text>
       </command>

       // ClearCount => ACTUATE_DOUBLE_COMMAND => M623N{IntegerValue}
       <command head-mountable-id="actSchultzClearCount" type="ACTUATE_DOUBLE_COMMAND">
          <text><![CDATA[M623N{IntegerValue}]]></text>
       </command>

       // GetPitch => ACTUATOR_READ_COMMAND => M608N{IntegerValue}
       <command head-mountable-id="actSchultzGetPitch" type="ACTUATOR_READ_COMMAND">
          <text><![CDATA[M608N{IntegerValue}]]></text>
       </command>

       // GetPitch => ACTUATOR_READ_REGEX => ^ok.(?<Value>.+)
       <command head-mountable-id="actSchultzGetPitch" type="ACTUATOR_READ_REGEX">
          <text><![CDATA[^ok.(?<Value>.+)]]></text>
       </command>

       // TogglePitch => ACTUATE_DOUBLE_COMMAND => M628N{IntegerValue}
       <command head-mountable-id="actSchultzTogglePitch" type="ACTUATE_DOUBLE_COMMAND">
          <text><![CDATA[M628N{IntegerValue}]]></text>
       </command>

       // GetStatus => ACTUATOR_READ_REGEX => ^ok.*Status: (?<Value>.+)
       <command head-mountable-id="actSchultzGetStatus" type="ACTUATOR_READ_REGEX">
          <text><![CDATA[^ok.*Status: (?<Value>.+)]]></text>
       </command>

       // GetStatus => ACTUATOR_READ_COMMAND => M602N{IntegerValue}
       <command head-mountable-id="actSchultzGetStatus" type="ACTUATOR_READ_COMMAND">
          <text><![CDATA[M602N{IntegerValue}]]></text>
       </command>

    </driver>

进一步整理, 将具体要在飞达控制板驱动中添加的内容整理出来.

      // 驱动默认的命令响应正则内容

         // COMMAND_CONFIRM_REGEX 内容为 ^ok.*
         // COMMAND_ERROR_REGEX 内容为 ^error.*

      // 动作命令对应的G码

      // GetID => ACTUATOR_READ_COMMAND => M610N{IntegerValue}
      // GetID => ACTUATOR_READ_REGEX => ^ok.*ID: (?<Value>.+)
       // PrePick => ACTUATE_DOUBLE_COMMAND => M600N{IntegerValue}
       // PostPick => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}
       // AdvIgnorErr => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}X1
       // GetCount => ACTUATOR_READ_COMMAND => M603N{IntegerValue}
       // GetCount => ACTUATOR_READ_REGEX => ^ok.*count: (?<Value>\d+).*
       // ClearCount => ACTUATE_DOUBLE_COMMAND => M623N{IntegerValue}
       // GetPitch => ACTUATOR_READ_COMMAND => M608N{IntegerValue}
       // GetPitch => ACTUATOR_READ_REGEX => ^ok.(?<Value>.+)
       // TogglePitch => ACTUATE_DOUBLE_COMMAND => M628N{IntegerValue}
       // GetStatus => ACTUATOR_READ_REGEX => ^ok.*Status: (?<Value>.+)
       // GetStatus => ACTUATOR_READ_COMMAND => M602N{IntegerValue}

看到, 如果只是为了知道回包是对是错, 就用驱动默认的COMMAND_CONFIRM_REGEX/COMMAND_ERROR_REGEX
如果要从回包中知道对错, 还要知道错误码/计数值之类的内容, 就需要实现动作的命令ACTUATOR_READ_REGEX, 定义正则, e.g. ^ok.count: (?\d+). 如果回包是对的, 就将值从回包中拿出来用.

根据上面最终整理出来要添加的动作和命令, 向上面建立的空飞达控制板串口驱动中添加.
添加的过程没啥要记录的, 添加完的截图如下:

COMMAND_CONFIRM_REGEX 内容为 ^ok.*

在这里插入图片描述

COMMAND_ERROR_REGEX 内容为 ^error.*

在这里插入图片描述

GetID => ACTUATOR_READ_COMMAND => M610N{IntegerValue}

在这里插入图片描述

GetID => ACTUATOR_READ_REGEX => ^ok.*ID: (?<Value>.+)

在这里插入图片描述

PrePick => ACTUATE_DOUBLE_COMMAND => M600N{IntegerValue}

在这里插入图片描述

PostPick => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}

在这里插入图片描述

AdvIgnorErr => ACTUATE_DOUBLE_COMMAND => M601N{IntegerValue}X1

在这里插入图片描述

GetCount => ACTUATOR_READ_COMMAND => M603N{IntegerValue}

在这里插入图片描述

GetCount => ACTUATOR_READ_REGEX => ^ok.*count: (?<Value>\d+).*

在这里插入图片描述

ClearCount => ACTUATE_DOUBLE_COMMAND => M623N{IntegerValue}

在这里插入图片描述

GetPitch => ACTUATOR_READ_COMMAND => M608N{IntegerValue}

在这里插入图片描述

GetPitch => ACTUATOR_READ_REGEX => ^ok.(?<Value>.+)

在这里插入图片描述

TogglePitch => ACTUATE_DOUBLE_COMMAND => M628N{IntegerValue}

在这里插入图片描述

GetStatus => ACTUATOR_READ_COMMAND => M602N{IntegerValue}

在这里插入图片描述

GetStatus => ACTUATOR_READ_REGEX => ^ok.*Status: (?<Value>.+)

在这里插入图片描述

此时, 要保证飞达已经安装到了设备上的飞达安装位置, 已经和PC机建立了正常的串口通讯(openpnp - 二手西门子电动飞达的测试).
并且物料已经正常载入到了子飞达(openpnp - 二手西门子电动飞达 - 物料编带安装的正确姿势), 且飞达物理错误指示灯是灭的.

在openpnp中添加西门子电动飞达

西门子电动飞达有多个子飞达(e.g. 8mm x 2位, 8mm x 3位, 12mm x 2位).
在openpnp中对应的飞达类型为SlotSchultzFeeder, 为每一个子飞达都添加一个openpnp用的飞达.

为西门子飞达上面每一位子飞达都建立一个基准点封装

在这里插入图片描述

https://github.com/openpnp/openpnp/wiki/Fiducials#creating-a-fiducial-package

在这里插入图片描述
按照官方说明, 手工添加一个飞达上用的取料的基准点, 封装名字为 Fiducial_SlotSchultz
在这里插入图片描述
在这里插入图片描述
封装的单位为mm, 外形尺寸都设置为0. 我这里默认就是这样, 这就是官方要求的.
添加一个焊盘, 基准点一般就是一个焊盘就够了.
在这里插入图片描述
将焊盘名称改为1
将顶部相机挪到飞达的对应子飞达前部的飞达取料基准点
在这里插入图片描述
让飞达上的基准点孔在顶部相机十字中间.
将基准点焊盘位置X,Y改为0,0, 圆度改为100(就是一个圆形焊盘)
修改焊盘的长宽, 因为这时已经选中了基准点焊盘. 修改基准点长宽后, 在顶部相机上会有封装的预览黄圈, 让预览的黄圈准确套住飞达基准孔的形状. 我这里实验的结果是1.2mm直径的圆.

在这里插入图片描述
测试一下, 基准点视觉是否好使, 应该能识别到基准点图形才行.
将这个视觉专门给这个基准点用.
在这里插入图片描述
默认的视觉选项比较少.
整理官方给的视觉选项, 尝试添加官方推荐的选项.
官方原版的基准点视觉管道设置如下:

<entry>
           <string>FIDUCIAL-FEEDER</string>
           <part-settings enabled="false">
              <pipeline>
                 <stages>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.CreateFootprintTemplateImage" name="template" enabled="true"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_template" enabled="true" prefix="fidloc_template_" suffix=".png"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="template_gray" enabled="true" conversion="Bgr2Gray"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageCapture" name="image" enabled="true" settle-first="true" count="1"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="image_gray" enabled="true" conversion="Bgr2Gray"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.Threshold" name="2" enabled="true" threshold="190" auto="false" invert="true"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_original" enabled="true" prefix="fidloc_original_" suffix=".png"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.MatchTemplate" name="match_template" enabled="true" template-stage-name="template_gray" threshold="0.699999988079071" corr="0.8500000238418579" normalize="true"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageRecall" name="recall_image" enabled="true" image-stage-name="image"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.DrawTemplateMatches" name="draw_matches" enabled="true" template-matches-stage-name="match_template"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertModelToKeyPoints" name="results" enabled="true" model-stage-name="match_template"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.DrawKeyPoints" name="draw_keypoints" enabled="true" key-points-stage-name="results"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_results" enabled="true" prefix="fidloc_results_" suffix=".png"/>
                 </stages>
              </pipeline>
           </part-settings>
        </entry>

整理后如下:

                                        // 调试用的, 不用加
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_template" enabled="true" prefix="fidloc_template_" suffix=".png"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_results" enabled="true" prefix="fidloc_results_" suffix=".png"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageWriteDebug" name="debug_original" enabled="true" prefix="fidloc_original_" suffix=".png"/>


                     // 需要加的opencv选项
                    <cv-stage class="org.openpnp.vision.pipeline.stages.CreateFootprintTemplateImage" name="template" enabled="true"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="template_gray" enabled="true" conversion="Bgr2Gray"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="image_gray" enabled="true" conversion="Bgr2Gray"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageCapture" name="image" enabled="true" settle-first="true" count="1"/>
                    <cv-stage class="org.openpnp.vision.pipeline.stages.Threshold" name="2" enabled="true" threshold="190" auto="false" invert="true"/>

                    <cv-stage class="org.openpnp.vision.pipeline.stages.MatchTemplate" name="match_template" enabled="true" 
                    template-stage-name="template_gray" threshold="0.699999988079071" corr="0.8500000238418579" normalize="true"/>
                    
                    
                    <cv-stage class="org.openpnp.vision.pipeline.stages.ImageRecall" name="recall_image" enabled="true" image-stage-name="image"/>

                    <cv-stage class="org.openpnp.vision.pipeline.stages.DrawTemplateMatches" name="draw_matches" enabled="true" template-matches-stage-name="match_template"/>



                    <cv-stage class="org.openpnp.vision.pipeline.stages.ConvertModelToKeyPoints" name="results" enabled="true" model-stage-name="match_template"/>


                    
                    <cv-stage class="org.openpnp.vision.pipeline.stages.DrawKeyPoints" name="draw_keypoints" enabled="true" key-points-stage-name="results"/>

视觉这块, 添加的都是opencv选项. 编辑视觉管道, 然后添加视觉属性.
在这里插入图片描述
在这里插入图片描述
单击想要编辑参数的opencv选项, 在属性列表中看看有没有可以改的选项(有的是填写值, 有些是从下拉框中选择)
为啥添加这些opencv管道, 现在还没概念, 以后有机会再研究, 估计用默认的管道也可以.

添加后的这些官方选项截图如下:
选项总览:
在这里插入图片描述
第一列是Enable, 没勾上的就无效.
默认选项是7项, 只有3项有效.
将全部够了Enable的选项截图保存参考.
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ImageCapture选项在默认选项中就有, 删掉重复添加的选项.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
opencv处理选项有的参数是上面的选项处理的结果, 如果依赖的选项的实例名字写错了, 在该选项的提示区就有异常, 那这个opencv处理就会出错导致不生效. 我们手工改一个错误的依赖的选项实例名字看看错误现象.
在这里插入图片描述
所有选项的提示区都要没有错误提示才说明opencv选项生效了.
在这里插入图片描述
选项设置完, 退出后, 保存设置.

再测试基准点的识别, 现在是在定位孔中心画了一个小圈.
在这里插入图片描述

建立一个基准点元件(e.g. Part_Fiducial_SlotSchultz), 将封装选为Fiducial_SlotSchultz. 这个元件给西门子飞达SlotSchultzFeeder用.

在这里插入图片描述

飞达的子飞达号码的判断

从通讯协议可知, 飞达的子飞达号码不是0, 就是1, 没有其他值(这是对应的2位的飞达. e.g. 8mm x2, 如果是8mm x3, 可能子飞达号码就是0,1,2, 等有了新类型的飞达再实验不迟)

子飞达在母飞达上的位置, 可以从实际通讯协议效果来看, 正常固定飞达后, 从飞达尾部向飞达头部看, 左边是子飞达0, 右边是子飞达1.

飞达ID的约定

飞达ID可以改为任意4位数字.
现在我这把飞达只是测试用, 我就约定测试用的飞达ID, 一律改为9999.
如果不是9999, 就是正式生产的飞达.
那么就可以根据飞达ID, 知道这个飞达在设备上的安装位置.
e.g. 设备正面是1000, 设备背面是2000, 设备左面是1, 设备右边是26.
如果飞达装在设备正面, 从左往右数第6个, 那么这个飞达的ID就要实现改为1006, 然后再接入openpnp

为这个测试飞达的子飞达0添加一个openpnp飞达

先手工添加一个SlotSchultzFeeder

在这里插入图片描述
先建立一个BANK
每个openpnpd的飞达的数据, 都存在一个唯一的BANK中.
一旦开始添加数据, 这个BANK就不能变了, 否则我们添加的数据就会丢失, 飞达数据就无效了.
在这里插入图片描述
现在我们还不知道这个飞达的ID, 先不用改这个BANK的名字, 等知道飞达ID了, 就将BANK名称改为和唯一的飞达ID关联的名称, 易于管理和识别.

如果BANK列表中有测试时新建出来的没用的BANK, 删掉, 只保留已经存在的和当前正在添加的这个子飞达的BANK
在这里插入图片描述

将动作都选上, 这样就可以发具体动作来操作飞达控制板来间接的操作物理子飞达.
在这里插入图片描述
这时, 我们还不知道要操作那个飞达, 最好在添加openpnp飞达时, 就在飞达控制板上挂一个物理飞达. 等每一个物理飞达都添加完了, 再全部将所有openpnp飞达都挂到飞达控制板上.

只挂一个飞达时, 我们取飞达ID, 就能知道当前挂的飞达的具体飞达ID. 即使我们拿到一个不知道飞达ID的物理飞达, 也可以正常添加openpnp飞达.

将没用的飞达ID(不在openpnp中注册的西门子飞达)从列表中删除
在这里插入图片描述
填写子飞达号码为0(因为现在想设置飞达左边的子飞达)
在这里插入图片描述

读取当前唯一挂在飞达控制板上的一把飞达ID
在这里插入图片描述
点击load, 在飞达ID列表中选择9999L这把openpnp飞达.
在这里插入图片描述
将BANK名称和openpnp飞达名称, 都改为和子飞达ID相关的名称, 易于识别.
那么我们再看到列表中出现的杂色的名字, 就知道是没用的名称.
在这里插入图片描述
用动作取参数
在这里插入图片描述
如果步进值不对, 就改为和实际物料编带相同的步进值.
如果飞达状态不是OK, 就要求检查物理飞达是否正确载入了物料编带.

填写基准点部件名称
先去看一眼前面建立的基准点部件叫啥.
在这里插入图片描述
可知, 前面新建的西门子飞达基准点部件叫做 Part_Fiducial_SlotSchultz
将名字贴到UI对应的基准点名称处.
在这里插入图片描述
选择这个子飞达对应的物料名称, 我这里上的是测试料, 0603的. 我就选以前载入板子时的0603_10K的元件.
这个物料, 根据载入的实际板子, 可以更换选择, 但是这种料, 就应该只出现在一个飞达上, 不能有多个飞达同时都是一种料.
在这里插入图片描述
设置子飞达基准点的位置
将顶部相机移动到飞达基准点(孔)中心.
在这里插入图片描述
因为当前设置的是这个飞达的子飞达0, 那么这个基准孔就在子飞达0的前部, 唯一的一个定位孔.
在这里插入图片描述
定位点的Z在Z轴0点, 不用改, 旋转角度也和做定位点封装时一样, 是0度. 所以取顶部相机位置就行.

设置取料的位置

为了防止崩料, 取料位置应该为取料窗的第一颗料(离自动扒开封皮最近的那颗料).
在这里插入图片描述
在这里插入图片描述
在物料位置保存顶部相机坐标
物料的Z坐标, 需要切到到吸嘴, 自己1mm1mm的下降去量, 我已经测量过了, -23mm就挺好.
openpnp有点bug, 像这种坐标参数变了之后, 居然保存按钮是灰的.
变通的方法, 重新在下拉列表中选同样的元件(e.g. 0603_10K), 右下角的应用按钮就可以点击了.

飞达编带中物料的原始角度
因为我用散料飞达试过, 物料的进料方向, 如果是从设备背面向设备正面垂直的走, 角度就是-90.
这里, 就将物料的角度设置为-90.
在这里插入图片描述
让此飞达生效, 就可以让贴片任务来用了.
在这里插入图片描述
至此, 将实际的西门子二手飞达接入openpnp的添加工作就完成了.
其他子飞达同理. 需要注意的是, 每个子飞达的BANK必须是唯一的, 否则数据就乱了.

补充 - 轴的移动范围可以跨零点

当设备归零后, 用顶部相机到飞达的基准点和取料位置都是正常的.
在这里插入图片描述
但是, 用飞达上面的工具, 尝试将吸嘴落到取料窗中的料上, 想看看吸嘴能不能正常怼到待取的料上, 此时报错如下:
在这里插入图片描述
刚开始看这个错误提示挺蒙的.
莫非是我的Y轴坐标范围有限制? 还是啥参数没设置?
我标定设备时, Y的范围是 0 ~ -520mm. Y是不能有正值的.
在这里插入图片描述

相机是在N1/N2的背面, 是不是相机可以够到取料窗, 但是N1/N2移动到取料窗时, 相机就出了Y轴范围了?

验证一下.
将设备归零后, 直接移动X轴到飞达上面, 然后看看是不是吸嘴离够不到料窗?

直接移动X, 让顶部相机到达飞达料位上方, 然后1mm1mm的移动Y, 向Y=0靠拢, 出现一下报错提示时, Y差不多为0.5mm
在这里插入图片描述
现在去看看N1/N2离取料窗中的料还有多远?
在这里插入图片描述
感觉是差点, 好像有不到5mm的样子.
想了一会, 那唯一可以解决这个问题的方法, 就是将Y轴可移动范围改为负数.
去看了一下Y轴从零点还可以向负方向移动大约20mm.
在这里插入图片描述
那理论上, 可以尝试将Y轴改为10 ~ -530mm, 不过接触openpnp后, 一直就将(X = 0, Y = 0)作为移动的起点, 没跨过界.
有点因为未知而害怕, 这整不好会出现事故啊.
又想了一会, 如果不改Y范围, 我只有去重新做顶部相机支架, 那又得2周…
算了, 还是改Y轴从0 ~ -520, 改为 10 ~ -520, 操作的时候, 如果不对劲了, 赶紧用设备上的关机按钮给设备断电.
在这里插入图片描述
因为N1挪过去的时候, 报错是Y不到10, 那我这么改应该是可以的.
用JLOG面板, 将Y移动到 Y = 9.5, 然后先试试, Y > 0时, 是否可以正常归零, 试了一下, 听到Y轴的轴承座撞了一下, ++.
然后主板通讯就报错了, Y轴的位置也是在>0的位置
设备的行程紧张啊.

将设备/主板 都断电, 将贴头推到 Y = 0 ~ -520的范围内, 将设备/主板 都重新上电, 用openpnp重新归零.

我有点明白为啥设备在Y轴方向撞了, 应该是主板配置的归位方式是从坐标小到坐标大.

# 限位开关 - Y轴归零方向
beta_homing_direction                        home_to_max

而且归零的这个坐标方向home_to_max, 主板是靠电机方向去判断的, 如果在Y > 0时, 归零时, 还是会向Y+的方向移动, 所以会撞设备.

当Y坐标 > 0时, 归位时就会大概率撞设备.
从这里能看出, 如果是正常使用, 就使用一个象限的坐标系, 轴坐标不要跨零点才是安全的.

看来这么改, 如果在 Y > 0的位置归零, 有危险啊.

我也没招啊, 只能暂时自己记得, 归位时, 要回到设备中间的正常P点后, 再归零.
等重新做顶部相机支架后(将支架的中心距离做小点), 然后再用一个象限的坐标.

将跨零点的距离改为够用就行, 改为5吧. 担心撞设备.
在这里插入图片描述
吸嘴了一下元件, 能看到零件自动进料了, 但是没看到吸嘴吸取到元件.
将吸嘴落到元件上, 因为飞达安装位置变了, 昨天量的料位的Z坐标不够. 应该是我的飞达安装版不平引起的.
那就得每个西门子飞达都要量料位的Z坐标.
在这里插入图片描述
在这里插入图片描述
放一张小纸条到料上面, 逐步降低吸嘴, 量取料位的Z坐标.
在这里插入图片描述
将Z下降了0.8mm, 改为-23.8mm后, 吸取元件正常, 用原来做好的0603封装的视觉检测也好使.

补充 - 如果料盘摆歪了会导致送料错误

料盘摆歪, 最后导致编带受力不能被飞达拉动, 导致错误.
从openpnp中, 用飞达取状态, 也能看到错误码.
此时, 飞达上的错误指示灯也在频闪.
此时, 需要将料盘摆正, 手头进一次料, 错误消失.
另外, 如果发生这种因为编带阻力产生的错误, openpnp中定义的物料位置就变了, 需要重新捕捉保存一下.(因为手工进料, 消除错误后, 发现每次吸嘴都吸取不到物料, 才发现取物料的坐标变了, 莫非飞达因为固定不牢靠被编带阻力拉动了位置?)

补充 - 飞达的物料在编带内的旋转角度和散料飞达不一样

试贴后发现, 物料在板子上被旋转了-90度.
在这里插入图片描述
那么说明, 物料在飞达内的旋转角度是0度, 和物料厂家定义的旋转角度是一样的.
在这里插入图片描述
试了好使, 果真西门子二手飞达和散料飞达的物料角度定义不一样.

子飞达1的添加

子飞达1和子飞达0的区别就是飞达号码, 改成1就行, 其他一样.
另外, BANK要唯一的.
添加完子飞达1, 试过了好使, 截图如下:
在这里插入图片描述
添加一个子飞达, 5分钟不到.

备注

官方有脚本可以自动加西门子电动飞达的openpnp飞达, 不过自动添加完, 也需要自己修改(e.g. 基准点坐标, 物料坐标, 步进值).
看个人喜好, 都行.
我是比较喜欢手工弄, 细节清晰, 不容易搞错. 除非我自己写的东西, 或者我自己真搞不定, 或者成本接受不了, 我才会用工具.

备注

现在一个西门子二手飞达已经添加到了openpnp, 试过了好使. 比散料飞达好用多了, 花钱就是好.
多个飞达添加后, 一起运行时, 如果发现啥问题, 再记录. 估计还会有细节问题.

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1005157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

八股文学习二(spring boot + mybatis)

三. 架构 1. spring boot Spring Boot是一个依靠大量注解实现自动化配置的全新框架。约定优于配置&#xff1b;独立运行的 Spring 项目&#xff0c;内嵌servlet容器&#xff1b;Spring Boot 框架内部已经实现了与Spring以及其他常用第三方库的整合连接&#xff0c;并提供了默…

2011-2015年西双版纳热带季节雨林碳水通量观测数据集

摘要 中国“双碳”目标的提出立足于应对气候变化的科学基础之上,增加碳汇、减少碳源成为实施气候治理的必需。陆地生态系统是重要的大气碳汇,而热带季节雨林生态系统作为中国陆地生态系统的组成部分,具有生物量丰富、生产力旺盛等特征,发挥着不可或缺的固碳功能。自2002年建…

选择(使用)数据库

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法格式: use 数据库名称;大家应该知道,在对数据库进行操作的时候,要制定数据库的操作对象,也就是说操作哪一个数据库 案列:选择testing数据库 …

Cesium 加载gltf

imageBasedLightingFactor&#xff1a;指定基于漫射和高光图像的照明因子参数 let position Cesium.Cartesian3.fromDegrees(104.17401, 30.65793, 10);const heading Cesium.Math.toRadians(135);const pitch 0;const roll 0;const hpr new Cesium.HeadingPitchRoll(head…

Java实现合并多个excel操作

涉及较多封装的工具类&#xff0c;所有依赖的工具类均提供代码&#xff0c;根据名称新建对应的类&#xff0c;在每个工具类中再引入相应的依赖即可 首先需要明确的是&#xff0c;需要合并的每个excel的表头名称必须是相同的&#xff0c; 针对表头&#xff0c;建立传输的dto&a…

数据结构:树的概念和结构

文章目录 1. 树的概念2. 树的结构3. 树的相关概念4. 树的表示孩子表示法双亲表示法孩子兄弟表示法 5. 树在实际中的应用5. 树在实际中的应用 1. 树的概念 树是一种非线性的数据结构,它是由 n (n > 0)个有限结点组成一个具有层次关系的. 把它叫做树是因为它看起来像一棵倒挂的…

vue基础知识八:为什么data属性是一个函数而不是一个对象?

一、实例和组件定义data的区别 vue实例的时候定义data属性既可以是一个对象&#xff0c;也可以是一个函数 const app new Vue({el:"#app",// 对象格式data:{foo:"foo"},// 函数格式data(){return {foo:"foo"}} })组件中定义data属性&#xff…

学习day59

昨天学了插槽&#xff0c;但是没有即笔记了 今天的是vuex 总体来说&#xff0c;vuex就是一个共享单车&#xff0c;每个人都可以使用他&#xff0c;也可也对他进行反馈。即把一个数据列为vuex&#xff0c;然后每个组件可以使用这个对象&#xff0c;也可也反过来反馈他 这一个设…

VScode在服务器上远程调试python代码的工作目录问题

背景&#xff1a; 当前很多写代码都习惯使用相对路径&#xff0c;即以当前的py文件为工作目录去寻找其他的py文件。所以如果工作目录不是以当前的py文件为起始的话&#xff0c;这将导致去跑一些开源代码的时候运行不起来。 现在我遇到的问题就是&#xff0c;在远程服务器上&…

【MFC】tab控件 仿任务管理器 枚举窗口和进程

界面和关联变量设置 创建一个基于对话框的MFC项目&#xff0c;给主对话框添加一个tab控件&#xff08;设置关联变量 类型&#xff1a;CTabCtrl 名称&#xff1a;m_tab&#xff09;&#xff0c;添加两个子对话框&#xff08;IDC_PAGE1和IDC_PAGE2&#xff09;&#xff0c;给子对…

对IMU的认识

参数标定&#xff1a; 良率检测 内参标定过程 1.线性误差模型 零偏&#xff1a;静止时的误差 尺度偏差&#xff1a;每个轴上电压到实际值之间的比例差值 1->1.5 或者 1->1.3(直线的斜率) 轴偏差&#xff1a; 如下图 2.标定过程&#xff1a; 2.1角加速度标定 重…

84 # koa 实现文件上传功能

下面使用实现文件上传功能&#xff0c;先新建文件夹&#xff0c;结构如下&#xff1a; index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-…

EtsyAI评论分析工具:让你的店铺运营更省心!

Etsy 是一个在线市场平台&#xff0c;成立于 2005 年&#xff0c;总部位于美国纽约。Etsy 的主要特点是它专注于手工艺品、独立设计、艺术品、古董物品和特色商品的销售。 Etsy是一个知名的电商平台&#xff0c;它专注于手工艺品、创意设计和独特商品的售卖&#xff0c;相信大家…

【自动化测试】如何提高自动化脚本的健壮性和稳定性?

自动化脚本可能出错的原因&#xff1f; 配置环境引起 自动化测试脚本的配置。对测试程序进行配置。如&#xff1a;是否还原初始设置、是否删除某些数据。对浏览器进行配置。对与测试程序有关的程序或影响脚本稳定性的程序进行配置。 非配置环境引起 网络延时&#xff0c;识…

python 爬虫的开发环境配置

1、新建一个python项目 2、在控制台中分别安装下面三个包 pip install requests pip install beautifulsoup4 pip install selenium/ 如果安装时报以下错误&#xff1a; raise ReadTimeoutError(self._pool, None, "Read timed out.") pip._vendor.urllib3.exceptio…

SegGPT: Segmenting Everything In Context论文笔记

论文https://arxiv.org/pdf/2304.03284.pdfCodehttps://github.com/baaivision/Painter 文章目录 1. 背景2. Motivation3. Method3.1 In-Context Coloring3.2 Context Ensemble3.3 In-Context Tuning 1. 背景 在Painter中&#xff0c;将各种密集预测任务视为一种着色问题。 在…

实用前端调试技巧

调试是项目开发中非常重要的环节。掌握一些调试技巧&#xff0c;不仅能帮助我们定位到问题&#xff0c;还能提升我们的开发效率。本文从两个场景来介绍调试技巧&#xff1a; 代码报错。 逻辑出错。 调试代码报错的技巧 技巧1: 读懂报错信息 大部分情况下&#xff0c;能读懂…

day5_C++

day5_C 继承 代码思维导图 继承 代码 #include <iostream>#define PI 3.14using namespace std;class Shape {protected:double perimeter;double area;public:Shape() {cout<<"Shape::无参构造"<<endl;}Shape(double perimeter,double area):per…

21 搜索二维矩阵 II

搜索二维矩阵 II 题解1 对角线上下循环搜索&#xff08;超时&#xff09; 生气&#xff01;&#xff01;无脑循环都不超时题解2 无脑循环题解3 学习STL(二分查找) 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行…

通过Power Platform自定义D365 CE 业务需求 - 3. 使用Microsoft Power应用程序

Microsoft Power Apps是一个用于开发应用程序的无代码、无代码平台。Power应用程序可以在Dataverse之上配置为数据库。尽管您可以连接Salesforce、OneDrive、Dropbox等多种云源,但Dataverse也可以用作内部数据库来构建应用程序,并通过连接器连接其他数据源进行集成。 Power应…