news 2026/8/31 13:11:40

STM32+OpenMV六轴机械臂视觉分拣系统实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32+OpenMV六轴机械臂视觉分拣系统实战

简介:本资源是一套完整的基于STM32的六轴机械臂智能分拣系统实现方案,面向本科毕业设计、自动化/机器人方向课程设计及期末大作业需求,解决多色物块识别与精准抓取分放的核心控制问题。压缩包含841个文件,总大小23.11MB,主体为516个C源文件与183个H头文件构成的MDK工程(基于STM32F103C8T6+HAL库),辅以27个OpenMV Python脚本实现颜色识别逻辑,另有编译中间文件、链接脚本、调试配置及文档说明等,结构清晰、模块解耦,便于移植适配不同6轴机械臂平台。已有114人学习下载,资源提供完整可运行代码、详细硬件连接说明、舵机驱动参数配置及系统联调要点,涵盖从OpenMV图像采集、HSV阈值标定、坐标映射到STM32运动学解算与PWM舵机控制的全链路实现,是少有的兼顾嵌入式控制与机器视觉的实战型教学项目。 我这个项目做了挺长时间,市面上不少机械臂教学套件都是给厂家自己的上位机在用,调参数、改逻辑全被绑定死,想接自己的传感器和视觉模块非常费劲。所以干脆从底层自己搞一套控制方案,用STM32做主机算轨迹、发脉宽,用OpenMV做视觉定位和颜色分类,两者之间就通过串口通信,把结果变成动作。做完之后发现这套组合的性价比和可玩性非常高,整套源码和文档我也整理出来了,下面把整个项目从硬件选型到联调排错的过程全部拆开讲清楚,希望对打算做机械臂控制、视觉识别或者只是想把手头舵机玩明白的朋友有帮助。

1. 项目全景:目标、架构与方案选型逻辑

1.1 这套系统最终实现了什么

先说功能——给六轴机械臂装上一只"眼睛",让它能从一堆混杂的物块中间识别出不同颜色的目标,按预设位置分门别类地放到指定区域。物块是三种颜色(红、绿、蓝),OpenMV摄像头拍到物块后,STM32控制机械臂启动运动序列:从初始位置出发,到取料点抓取,抬升过渡,再到对应颜色的放料点松开,最后回到初始位置等待下一个物块。

整个流程展开是这样的:

  • OpenMV连续采集图像,检测画面中是否出现目标颜色色块。
  • 检测到之后,把物块的类别(颜色)和位置坐标通过串口发送给STM32。
  • STM32收到完整且有校验的数据帧后,解析出颜色ID和坐标。
  • 根据颜色ID映射到放料区域坐标,调用逆运动学解算函数,生成每一路舵机需要转到的角度目标值。
  • 逐关节执行角度插值过渡,控制舵机平滑运动,完成"抓取-搬运-释放"的整个流程。
  • 完成后回到初始位,流程重新开始。

这个流程听上去不复杂,但实际做起来,各个环节之间的时序配合、通信可靠性、机械臂运动平稳性都会冒出一堆问题,后面我会逐个展开。

1.2 为什么选STM32加OpenMV而不是单芯片方案

有人可能会问:OpenMV本身就是一个带MCU的视觉模块,能不能让它直接把机械臂控制也干了?答案是可以,但不推荐。原因有三点:

第一,机械臂控制需要多个定时器同时输出不同占空比的PWM波,还需要持续处理中断和状态机,OpenMV主控的实时性不如STM32的HAL库加硬件定时器那样得心应手。

第二,六轴机械臂的运动学解算如果用高语言写没问题,但如果要一步步调试每路舵机的角度、速度、加减速曲线,用STM32直接对着寄存器级和标准库操作更顺手。OpenMV端我只需要关心"看见什么",不关心"什么时候发角度",各司其职。

第三,从扩展性考虑,STM32作为主控,以后可以在不改变视觉逻辑的前提下,把OpenMV换成其他传感器模块(比如超声波、激光测距),或者给机械臂加力传感器、夹爪舵机,都只是在STM32端加代码,不需要再把所有数据包格式重新协调一遍。

架构采用主从分离还有一个好处,就是两个模块可以分开调试。OpenMV单独用IDE跑识别脚本,STM32则可以通过串口调试助手直接模拟视觉输入,观察机械臂动作是否正确。联调时如果出了问题,双方都能快速定位是自己这一侧还是通信的问题。

1.3 整体数据流与状态机设计

六轴机械臂的工作流程本质上是一个状态机,我在STM32端定义了这几个状态:

  • S_IDLE(待机):机械臂在初始位,等待串口数据。
  • S_VIS_RECEIVED(视觉接收):已经收到颜色ID和坐标,准备开始动作序列。
  • S_MOVE_TO_PICK(移动到取料位):从初始点到取料点的过渡轨迹。
  • S_GRAB(夹取):到达取料点后,夹爪舵机闭合的过渡。
  • S_MOVE_TO_PLACE(移动到放料位):夹取到物块后抬升、移动到目标放料点。
  • S_RELEASE(释放):夹爪张开,物块放下。
  • S_MOVE_HOME(回初始):回到初始位,状态回S_IDLE。

状态机的核心价值在于,把复杂的时序拆成了单步逻辑。比如"移动到取料位"这个状态里,只需要做逆运动学解算、生成各关节的角度序列,不需要关心视觉识别和抓取动作是不是已经完成;真正跳到下一步,等到"是否到达目标角度"的条件满足后再触发。

为了保证视觉信息不丢失,我还在STM32中维护了一个小的数据缓冲区。OpenMV发送数据最快可能几十毫秒一帧,但STM32处理一个完整机械臂动作需要两三秒。这样高频发送没有意义,我在协议上做了设计——OpenMV识别到物块后只持续发送几次,发送完就停,避免长时间占用串口总线,让机械臂在动作执行期间不会反复收到新任务而打断流程。

2. 硬件选型:从机械臂本体到控制板、电源的匹配原则

2.1 六轴机械臂的结构与舵机选择

先明确一点:市面上标"六轴机械臂"的套件很多,但舵机类型、臂长、负载差别很大。我用的是一台小型桌面级六轴机械臂,整体臂展在30厘米左右,每关节都是一个塑料舵机加金属齿轮组构成,末端是两指夹爪。这种套件的优点是结构紧凑、价格可控、维护简单,缺点是负载很小,只能夹取轻的物块(比如3厘米见方、重量在20克以内的木块或塑料块),不适合做重负载抓取。

对舵机的选择,我建议重点关注两个参数:扭矩和工作电压。六轴机械臂每个关节承担的力矩不同,靠近基座的关节(腰部、大臂)需要大扭矩舵机,末端关节(手腕旋转、夹爪)用小舵机即可。我的套件里,一轴到四轴用的都是扭矩在20千克力·厘米以上的舵机,五轴和六轴用9克级别的微型舵机。实际运行中,如果发现某个关节在搬运过程中有抖动或者堵转发热,大概率就是扭矩不够或者电压不足。

关于舵机信号,我强烈建议选数字舵机,不要选模拟舵机。数字舵机的PWM频率可以工作在333Hz甚至更高,响应快,抖动小;模拟舵机在50Hz下摇臂来回摆,很容易让机械臂产生共振。同一套机械臂,数字舵机的控制效果会明显稳定。

2.2 STM32型号怎么定:其实F103够用

很多人在选STM32时容易陷入"参数焦虑",觉得型号越高越好。就拿我们这个项目来说,核心需求就是串口接收、解析数据、开多个定时器输出PWM、跑一个逆运动学解算,这些都是最基本的。我用的是STM32F103C8T6,主频72MHz,64KB Flash,20KB RAM,跑完这些绰绰有余。

唯一要提前考虑的是定时器通道数。六轴机械臂加一个夹爪舵机,总共需要7路PWM输出。F103C8T6的TIM1、TIM2、TIM3、TIM4各有4个通道,挑几个定时器组合完全够用。如果你计划以后加更多执行器(比如两个夹爪、一个旋转台),建议选F103RCT6或者F407系列,反正从F103C8T6升级过去,代码几乎不用大改。

2.3 OpenMV型号与镜头的选择细节

OpenMV系列我建议直接上OpenMV H7,它的处理器性能比M7强不少,在做图像处理时帧率更高,阈值查找和色块识别也会更流畅。当然,如果你手头只有M7,跑单色块识别也够用,但多颜色识别加坐标计算会吃力一些。

镜头选标准广角镜头即可,视场角大,能覆盖更大的工作台。需要注意的是,镜头和物块之间的距离、工作台光照条件直接决定了识别效果。我的工作台是30cm乘40cm,OpenMV倒挂在取料点上方大约40厘米高的支架上,物块在画面中大约占60到100像素见方,识别和坐标计算都足够稳定。

2.4 电源设计:这个问题直接决定机械臂能不能稳定工作

这里必须着重强调——舵机驱动电路和主控电路一定要隔离供电。舵机启动瞬间电流很大,尤其是六轴机械臂多个舵机同时动作时,瞬时电流能到2到3安培甚至更高。如果直接用同一个稳压芯片给STM32和舵机供电,电压跌落会导致STM32复位,严重时直接烧掉控制板。

我的做法是:

  • 舵机供电用7.4V 2S锂电池,经过UBEC(可调降压模块)降压到6V,给舵机供电。
  • 控制板供电独立用一块5V USB线从充电宝或USB口取电,专门给STM32和OpenMV供电。
  • 两套供电只在GND上共地,这样串口电平才能保持一致。

如果你手头没有单独的电源,也可以用大电流降压模块,比如LM2596或者降压型DC-DC,选能持续输出3A以上的型号。但无论如何,千万不要用开发板自带的LDO去带动多个舵机,那是必炸的坑。

3. OpenMV颜色识别:从颜色空间、阈值到串口协议

3.1 为什么用LAB色彩空间做颜色判断

OpenMV官方给的例程大部分是基于RGB色彩空间做颜色阈值,但RGB在自然光照下极不稳定:同一种颜色,阳光直射和阴影里完全不一样,白色物块上的高光反射直接让RGB值跑飞。我实际测试下来,改用LAB色彩空间之后,准确率提升非常明显。

LAB色彩空间把亮度信息放在L通道,颜色信息放在a通道(红绿)和b通道(黄蓝)。这样在做颜色区分时,可以把L通道的影响降得比较低,只针对a、b通道设阈值。例如:

  • 红色:L一般不用太严格,a通道较高(例如20到100),b通道适中(约120到220)。
  • 绿色:a通道较低(例如0到60),b通道也偏低(约80到160)。
  • 蓝色:b通道明显低于绿色,且a通道接近中间值。

实际调试时,用OpenMV IDE里的"阈值编辑器"工具,打开素材图片,拖Lab滑块,观察哪个颜色区域的RGB图像被选中,就能快速找到合适的阈值区间。如果环境光会变化,建议用auto_whitebal设为False,这样白平衡不会自动漂移,颜色阈值相对稳定。

3.2 识别流程:预处理、色块提取、干扰过滤

图像处理流程我拆成四步:

  1. sensor.snapshot()采集一帧图像。
  2. find_blobs(thresholds)查找所有在目标颜色范围内的色块,返回每个色块的外接矩形、面积和重心坐标。
  3. 对每个色块做过滤:面积大于一定像素(比如blob.area() > 500),宽高比合理(不能是一个细长条),而且重心坐标在图像有效区域内。
  4. 如果有多个同色色块,取面积最大的那个作为最终目标;不同颜色之间,以优先级最高(比如红色优先于蓝色)或者最近原则决定先处理哪一个。

这四步看上去简单,但每一步都有细节。比如在过滤的时候,我遇到一个情况:工作台上一块黑色的垫布,在某些光照下被识别成近似蓝色的色块。原因是LAB中b通道在黑色区域噪声很大。解决方法是加上亮度约束:blob.mean() > 30只保留平均亮度大于一定值的色块。这一条比单纯调阈值效果还好。

3.3 坐标计算与串口发送协议

OpenMV识别到物块后,返回的是图像坐标系中的像素坐标(cx, cy),范围大约在0到320、0到240之间。这个坐标不能直接给机械臂用,因为机械臂的取料点是三维空间坐标。我这里做了一种简化处理:让物块只出现在一个平面工作台面上,OpenMV固定高度悬挂,那么像素坐标和台面物理坐标之间就构成了一个固定的单应性映射。

可以通过三个已知摆放位置的标定点来求映射矩阵,我在OpenMV脚本里预先存了三个像素坐标和对应的物理坐标,用OpenMV的find_homography或手动解一个仿射变换(六参数模型)都能算出来。公式大概是:

  • 物理x = a0 + a1 * 像素x + a2 * 像素y
  • 物理y = b0 + b1 * 像素x + b2 * 像素y

已知三对坐标,就可以解出a0、a1、a2、b0、b1、b2。有了仿射变换参数,每次识别出的像素坐标就能转换为台面上物理坐标(单位毫米),然后用这两个值加上固定的Z高度,作为机械臂末端的取料目标点。这个方案的精度大约在10毫米以内,对抓取3厘米大小的物块来说够用了。

串口通信协议我定义成定长帧,每帧6个字节:

  • 帧头1:0xAA
  • 帧头2:0x55
  • 数据类型:0x01表示颜色识别结果
  • 颜色ID:1红、2绿、3蓝、0表示未识别
  • 物理坐标X:单字节(映射范围0到255,方便直接拼包)
  • 校验:前5字节累加和低8位

每次识别成功,OpenMV连续发送这个帧3次,每次间隔30毫秒,然后在未来2秒内不再重复发送。STM32端只要在一帧时间内收到完整数据,校验通过就认为有效。这种设计大大降低了串口丢包带来的偶发问题。

颜色阈值区间的维护也是一项重要工作。OpenMV跑几天之后,环境光可能有细微变化,我习惯把阈值保存成文件,启动时加载。如果发现某天识别率下降,用IDE重新跑一次阈值编辑器,把三组区间更新后重新保存,不用改主逻辑代码。这些细节在源码里都有体现。

4. STM32控制层:串口解析、运动学解算与PWM输出

4.1 串口DMA接收:不丢字节的可靠通信

STM32端接收OpenMV数据,我用的是串口空闲中断加DMA的方式。简单说,就是让DMA把串口收到的数据自动搬到一个环形缓冲区,当串口总线空闲(即一帧数据传输完毕)时触发空闲中断,然后在中断里解析缓冲区数据。

对比传统的中断逐字节接收,DMA接收有个明显优势:不管OpenMV发送多少数据,CPU不用每个字节都停一下,而是完全由硬件搬运,解析的时候一次性处理。这样即使OpenMV偶尔连续发多帧,也不会漏字节。

具体配置要点:

  • 串口初始化配置:波特率115200、8位数据、无校验、1位停止。
  • DMA配置:使用DMA1通道5(USART2_RX),模式为循环模式,数据宽度为字节。
  • 接收缓冲区:定义长度64字节的一维数组。
  • 空闲中断:使能USART_IT_IDLE,在中断回调里读取USARTx->SRDR清除状态,然后处理缓冲区。

解析函数在收到0xAA 0x55帧头后,按协议提取颜色ID和坐标,做累加和校验。如果校验不通过,直接把缓冲区清空,不执行后续动作,避免错误数据导致机械臂乱动。

4.2 逆运动学:六轴解算的简化实现

六轴机械臂的逆运动学在纸面上是一大堆矩阵变换,但实际项目中我们通常只关心末端执行器(夹爪)要到达的位置和姿态。我采用的方案是:六轴结构中前三个关节主要决定末端位置,后三个关节决定姿态。因为我们的任务是抓取一个放在平面上的物块,夹爪的姿态基本固定(竖直向下夹取),所以可以直接用解析法求解前三轴的角度,后三轴保持固定角度,最后用夹爪舵机控制开合。

以我的机械臂构型为例(这是很常见的六轴关节结构):

  • 关节1(腰部):控制机械臂左右回转。末端X坐标和Y坐标的反正切就是关节1角度,atan2(y, x)。
  • 关节2(大臂):控制上臂俯仰。根据末端Z坐标和关节1解算后的半径R,结合大臂和小臂长度,用余弦定理求夹角。
  • 关节3(小臂):根据大臂角度和末端位置,算出小臂相对水平面的角度。

两连杆机构的角度求解非常经典:

设大臂长度L1,小臂长度L2,末端在平面内的投影距离为r,Z方向高度为z,则末端到基座的距离为:

  • R = sqrt(x^2 + y^2)
  • D = (R^2 + z^2 - L1^2 - L2^2) / (2 * L1 * L2)
  • 关节3角度(小臂) = acos(D) 的补角
  • 关节2角度(大臂) = atan2(z, R) - atan2(L2 * sin(关节3角度), L1 + L2 * cos(关节3角度))

三个角度都出来了,再加上固定的后三轴角度,就得到六轴舵机的目标角度。具体角度值到PWM脉宽的转换公式是:

  • 脉宽 = 500 + (角度 / 180.0) * 2000(单位微秒)

也就是说,0度对应0.5毫秒脉宽,180度对应2.5毫秒脉宽。每个舵机的中位(90度)对应1.5毫秒。

但这里有个很重要的细节——机械臂的连杆长度和关节零点偏移必须校准。我一开始直接用厂家标称长度解算,结果末端位置偏离实际位置好几厘米。后来我在源码里留了一个"机械臂参数校准函数",通过手动调整关节零点偏移量和连杆长度,让机械臂实际到达位置和理论坐标尽量吻合。这是整个项目里最花时间的一步,但校准好了就一劳永逸。

4.3 多路PWM输出与运动平滑

PWM输出用STM32的定时器,我选用TIM1和TIM2的组合,TIM1输出通道1到4,TIM2输出通道1到3,共7路。定时器配置成PWM模式1,预分频器设置为72-1,计数周期设置为20000-1,这样PWM频率就是50Hz,脉宽控制范围0到20000对应0到20000微秒。假设舵机中位1.5毫秒,就设置比较寄存器为1500,脉宽为1500微秒。

需要注意的是,不同舵机的PWM频率上限不同。数字舵机虽然能工作在333Hz,但50Hz也能正常工作,差别只是响应速度。为了保证主控逻辑简单和兼容性,我用50Hz。

运动平滑是另一个关键点。直接让舵机从当前角度跳到目标角度,机械臂会猛地甩动,夹爪里的物块可能被甩飞,关节齿轮也容易打齿。我用了简单的梯形速度规划:将目标角度和当前角度之差分为多个小步,每一步间隔10到20毫秒,每步递增角度,形成一个加速-匀速-减速的位移曲线。STM32端用一个简单的增量式PID控制角度逼近速度:

  • 误差 = 目标角度 - 当前角度
  • 速度增量 = Kp * 误差 + Ki * 误差积分 + Kd * 误差变化率
  • 当前角度 = 当前角度 + 限幅后的速度增量 * 时间步长

实际测试中,Kp取0.3,Ki取0.0001,Kd取0.05,效果已经很平滑。如果机械臂抖动,多半是Kp太大或者步长太短,适当降低Kp和步长即可。

4.4 夹爪控制:夹取力度的经验值

夹爪舵机控制有几个经验值可以直接用:

  • 待机状态:夹爪张开,保持半开状态,避免物块意外掉落。
  • 抓取状态:夹爪舵机先快速闭合到接近物块的大小,再缓慢增加力度,到达设定阈值后停止,避免夹坏物块或舵机堵转过热。
  • 空载状态:夹爪闭合力度可以减小,减少舵机功耗,延长寿命。

我通过一个简单的电流检测或者角度反馈来实现力度控制——如果舵机在闭合过程中到达指定脉宽后,电流突然增大,说明已经被物块卡住,就停止继续加大力度。在Stm32源码中我留了一个gripper_force_session()函数,开发者可以自己调整夹取力度参数。

5. 联调排错:从识别乱跳到机械臂抖动的完整排查链路

5.1 问题一:OpenMV识别率低,红色和橙色分不清

这是联调时最让人头大的问题。刚开始装好,我发现OpenMV经常把橙色的物块误判成红色,或者把红色物块在暗光下当成棕色直接忽略。

排查过程:

  1. 首先排除物块本身问题。我拿标准红色色卡和橙色色卡在相同光照下分别拍图,发现LAB的a通道红色和橙色差别确实不大,单纯调阈值区间很难区分。
  2. 于是我在算法层面做了改进:不仅依靠颜色阈值,还加上了"色相一致性"判断。红色物块在LAB空间中,b通道通常接近零,而橙色物块的b通道明显偏正。这样通过a和b两个通道的组合条件,就能把红色和橙色区分开。
  3. 另外,我还发现OpenMV的自动白平衡导致颜色漂移。在image初始化时关闭自动白平衡和自动增益,用固定参数,颜色识别稳定了很多。

最终,颜色识别准确率从大概70%提升到了95%以上。剩下的5%误判,是因为环境光线的极端变化,这套项目目前的处理方式是如果颜色置信度低于阈值,就输出"未识别",机械臂不执行动作,等待下一帧。

5.2 问题二:机械臂运动中抖得厉害,甚至舵机咔咔响

机械臂抖动这个问题几乎一定会遇到。最开始我还以为是舵机本身质量问题,后来测试发现关掉机械臂电源、只用手掰动关节时舵机没有明显卡顿,问题出在控制逻辑上。

排查过程:

  1. 第一步,检查PWM频率。如果频率选的太低(比如40Hz),数字舵机的响应速度跟不上,一帧一帧地跳,导致抖动。把频率提升到标准数字舵机支持的333Hz,现象有所缓解。
  2. 第二步,检查舵机供电电压。用万用表测舵机供电端,发现舵机同时动作时电压降到5.4V,明显偏低。换了一个能稳定输出6V、峰值5A的UBEC后,抖动基本消失。
  3. 第三步,检查运动插值算法。由于我一开始采用的大角度跳变被拆成若干小步,但每步的间隔和角度增量是均匀的,造成机械臂先加速后急停,产生冲击。改成梯形速度规划,每步的角度增量按先加后减的方式分配后,整个运动柔和了很多。

5.3 问题三:串口数据丢帧,机械臂偶尔不响应

这个问题的排查有点玄学。OpenMV发送数据正常,STM32的串口也配置正常,但偶尔一次完整动作执行完后,机械臂没有回到待机状态,而是卡死。

排查过程:

  1. 用逻辑分析仪抓串口波形,发现OpenMV确实连续发了3帧数据,但STM32只完整解析出了1帧。
  2. 检查STM32串口中断,发现用的是"逐字节接收+帧结束判断"的方式,导致在高负载状态下串口中断容易被堵住,丢字节。
  3. 改成DMA接收+空闲中断后,丢帧率降为零。另外,在协议中增加帧校验,即使偶尔有错帧也会被直接丢弃,不会产生错误动作。

这里有一个重要的经验:能不用中断逐字节接收的,就别用。DMA加空闲中断是STM32串口接收的标准姿势,几乎所有网络通信和传感器数据接收场景都适用。

5.4 问题四:机械臂动作顺序偶发错误,把物块放到了错误位置

这个问题的根源不是机械臂本身,而是"状态同步"的问题。原本的设计是OpenMV识别到物块就发数据,STM32在动作执行过程中如果收到下一个物块的数据,会直接改变当前状态机的目标位置,导致机械臂还没放完手里的物块,就被新任务打断。

解决办法是给状态机加了一个"忙标志位":

  • STM32在进入S_MOVE_TO_PICK状态时,置busy_flag = 1
  • OpenMV发送数据时,STM32先检查busy_flag,如果是1,就先缓存起来,等当前动作执行完毕、回到S_IDLE后再处理缓存的任务。
  • 这样不仅解决了误动作问题,还自然实现了"排队处理"功能,之后就算工作台上有多个不同颜色的物块,机械臂也能依次处理完。

从串口协议的设计上说,这也说明一个问题:不是所有数据都要立刻响应,有时需要引入"节拍"和"缓冲"的概念。

6. 源码工程结构与二次开发建议

6.1 OpenMV端脚本的文件组织

OpenMV端我拆成了三个文件:

  • main.py:主循环,调用识别函数和通信函数。
  • color_thresholds.py:保存三组颜色阈值区间和识别参数。
  • homography.py:仿射变换标定参数,标定点坐标和转换函数。

主循环的逻辑大概是:

import sensor, image, time from color_thresholds import COLOR_THRESHOLDS from homography import pixel_to_physical sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time=2000) sensor.set_auto_whitebal(False) sensor.set_auto_gain(False) while True: img = sensor.snapshot() for color_id, threshold in COLOR_THRESHOLDS.items(): blobs = img.find_blobs([threshold], pixels_threshold=500, area_threshold=500) if blobs: blob = max(blobs, key=lambda b: b.area()) phys_x, phys_y = pixel_to_physical(blob.cx(), blob.cy()) send_serial_frame(color_id, phys_x, phys_y) time.sleep_ms(200) time.sleep_ms(50)

关键优化点:

  • find_blobs的参数pixels_thresholdarea_threshold不能设太大,否则小物块识别不到;也不能设太小,否则噪声色块会被算进去。我一般设500到1000。
  • merge=True参数可以把相邻的同一颜色色块合并成一个,适合物块被部分遮挡的情况。

6.2 STM32端代码结构

STM32端按照模块划分,采用HAL库和标准库结合的方式编写,文件结构如下:

  • main.c:初始化硬件、状态机主循环。
  • serial.c:串口DMA接收、数据帧解析、数据缓冲。
  • arm_kinematics.c:逆运动学解算、机械臂参数设置。
  • servo_pwm.c:PWM初始化、舵机角度控制、梯形速度规划。
  • task_state.c:状态机逻辑,定义各状态之间的切换和处理。

主循环大致是:

while (1) { if (parse_serial_frame(&color_id, &pos_x, &pos_y)) { arm_task_set_target(color_id, pos_x, pos_y); } arm_task_tick(); // 根据状态机执行当前动作 delay(10); }

开发者拿到源码后,需要根据自己的机械臂尺寸修改三个地方:

  • arm_kinematics.c中的连杆长度L1、L2。
  • servo_pwm.c中各路舵机的PWM脉宽范围(0度、180度对应值)。
  • task_state.c中的放料区坐标(用你自己的工作台尺寸标定)。

6.3 如何适配你自己的机械臂

不同厂商的机械臂结构参数差异很大,但适配方法基本一致:

  1. 先用尺子量出机械臂的大臂长度、小臂长度和肩高。
  2. 让机械臂回到一个已知姿态(比如所有舵机90度),记下此时末端位置。
  3. 逐关节手动微调零点偏移,让机械臂的末端能到达你工作台上几个标定点的物理坐标。这个过程需要反复试,一般十几分钟到半小时。
  4. 把参数写进源码,编译烧录,验证基座坐标和末端坐标是否对应。

如果你的机械臂不是传统的六轴串联结构(比如有平行连杆结构),逆运动学解算公式可能需要改一下。不过大多数桌面级六轴机械臂都是标准串联构型,改参数就能直接跑通。

6.4 从单色块到多颜色、传送带、自动循环的扩展思路

当前项目已经实现了三色(红、绿、蓝)物块的分类分放,如果想做更复杂的分拣应用,可以考虑这几个方向:

  • 增加更多颜色识别:在color_thresholds.py里再加几组阈值,STM32端在状态机里增加对应的放料区映射即可。
  • 增加物块掉落检测:在夹爪上装一个红外对射或霍尔传感器,判断夹爪是否真的抓到了物块。如果没抓到,机械臂返回初始位重试,而不是直接去放料点空放。
  • 引入传送带:OpenMV负责检测传送带上经过的物块,测出物块到达取料点的时间,STM32控制机械臂在固定的取料窗口执行抓取。这个需要处理更精确的时间同步。
  • 如果物块是堆叠的,可以加入深度摄像头或激光测距,确定物块的Z坐标,不再假设物块都在同一平面上,这样机械臂的抓取会更灵活。

源码在GitHub上做了整理,包含OpenMV端脚本、STM32工程、硬件接线图、标定说明文档以及拍摄的演示视频链接。文档里把每个模块的接口、参数含义、烧录步骤都写清楚了,即使你之前没玩过OpenMV或者对STM32不熟,按文档走一遍也能把项目跑起来。

我做这个项目最大的感受就是:机械臂控制加视觉识别,真正的门槛不在于某一个环节有多难,而在于把多个模块可靠地协同起来。串口协议、状态机、运动学这些单独拎出来都是大学课程里的老知识,但放到一个真实系统里,每一步都有细节需要打磨。希望这篇拆解和源码能帮你少走一些弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 13:10:12

GEO生成式引擎优化:跨境企业AI搜索可见性提升指南

2026年,一个跨境企业老板最典型的困惑可能是这样的:他的官网在 Google 和 Bing 上排名不错,投了不少广告,但当他让 AI 助手“推荐一家跨境营销服务商”时,AI 的回答里根本没有他,甚至在列举的三五家名单里全…

作者头像 李华
网站建设 2026/8/31 13:05:41

2026年北京刑事律师警醒严重环境污染标准的3个认定点

企业生产过程中排放废水废气被环保部门查处,本以为罚款了事,几个月后却收到公安机关的立案通知;或者因为无资质处置危险废物、随意倾倒废料垃圾被追究刑责——污染环境罪是近年来北京及周边地区多发的涉企犯罪,也是让企业主和家属…

作者头像 李华
网站建设 2026/8/31 13:05:18

输入法导致游戏掉帧?从TSF原理到彻底解决微软拼音卡顿

很多玩家都遇到过这样的场景:电脑配置明明不低,显卡驱动也是最新的,但游戏运行起来就是偶尔掉帧,甚至按下 WASD 时突然蹦出一个中文输入法候选框。这个时候,大多数人会把问题归咎于显卡、内存、散热,甚至网…

作者头像 李华
网站建设 2026/8/31 13:01:28

【爱马仕】Hermes 本地工具 Windows 安装指南,避开 Python 依赖与路径报错

告别环境配置难题!Windows 快速部署 Hermes Agent 实操指南 不少想要体验 Hermes 本地智能体的用户,都会被繁琐的部署流程劝退。传统部署方式需要手动配置运行环境、安装各类依赖组件、调试文件路径,过程中极易出现命令行报错、系统拦截、文…

作者头像 李华
网站建设 2026/8/31 13:00:45

OpenViking ovpack 打包:导出/导入整套上下文数据的完整指南

OpenViking ovpack 打包:导出/导入整套上下文数据的完整指南 【免费下载链接】OpenViking Self-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills. 项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking Op…

作者头像 李华