公司动态

基于二哈识图与麦昆小车的桌面二维码编程机:从视觉识别到机器人控制

📅 2026/7/28 9:41:40
基于二哈识图与麦昆小车的桌面二维码编程机:从视觉识别到机器人控制
1. 项目缘起当“二哈”遇见“麦昆”一场桌面上的智造革命最近在捣鼓一个特别有意思的玩意儿我把它叫做“桌面二维码编程机”。核心的硬件搭档是两位老朋友二哈识图HuskyLens和麦昆PlusMaQueen Plus。这个项目的灵感源于一个很实际的需求如何让一个简单的教育机器人能“看懂”并“执行”我们写在二维码里的指令从而实现一种无需复杂编程环境、所见即所得的物理世界交互方式想象一下这个场景你在一张纸上打印了几个不同的二维码分别代表“前进2秒”、“左转90度”、“播放音乐”。然后你只需要拿着这张纸让小车上的摄像头“扫一扫”对应的二维码小车就能立刻执行相应的动作。这听起来是不是有点像给实体机器人“扫码点餐”没错这个项目的核心魅力就在于此——它将虚拟的编程指令代码转化为物理世界可识别、可传递的二维码再通过视觉识别技术让机器自动读取并执行完成一个从“信息”到“动作”的闭环。二哈识图在这里扮演了“眼睛”和“大脑”的角色。它是一款集成了机器学习算法的人工智能视觉传感器开箱即用无需训练就能识别多种视觉标签其中就包括我们最熟悉的QR二维码。它的好处是把复杂的图像处理、特征提取和识别算法都封装在了一个小小的模块里我们通过简单的串口指令就能获取识别结果极大降低了开发门槛。麦昆Plus则是我们的“手脚”。这是一款基于micro:bit主控的可编程小车平台功能丰富集成电机、RGB灯、蜂鸣器、巡线传感器等扩展性强。更重要的是它可以通过串口与二哈识图进行通信接收指令并驱动电机做出动作。而将这两者连接起来的“桥梁”我选择了App Inventor 2。这是一个图形化的安卓应用开发工具非常适合快速搭建一个用于生成和管理指令二维码的控制器App。你可以在手机上选择或输入指令App瞬间生成对应的二维码打印出来或用另一块屏幕展示小车一扫任务就开始了。这个项目融合了机器视觉、嵌入式控制、移动应用开发等多个领域的有趣知识点但它并不复杂非常适合创客教育、兴趣开发或者仅仅是一次好玩的周末DIY。接下来我将从硬件连接、指令协议设计、App开发到系统联调完整地拆解这个“智控万物”小系统的构建过程。2. 硬件系统搭建让二哈与麦昆“握手”对话整个系统的物理基础是建立二哈识图与麦昆Plus之间稳定可靠的通信。这不仅仅是接线更涉及到电源管理和通信协议的理解。2.1 核心硬件清单与连接图首先清点一下我们需要的所有部件麦昆Plus小车主体包含micro:bit主板、电机驱动、电池盒等。二哈识图HuskyLensAI视觉传感器。micro:bit主板麦昆Plus的核心大脑我们将程序烧录在这里。USB数据线用于给micro:bit供电和下载程序。3.7V锂电池为麦昆Plus小车电机部分供电。若干杜邦线公对公用于连接二哈与micro:bit。关键的连接步骤在于二哈识图与micro:bit的对接。二哈识图支持UART串口和I2C两种通信方式这里我们选择更常用的UART串口通信。连接示意图如下二哈识图 (HuskyLens) micro:bit (麦昆Plus) [RX] -------------------- [P1] (TX) [TX] -------------------- [P2] (RX) [GND] -------------------- [GND] [VCC] -------------------- [3.3V] 或 [VCC]注意二哈识图的工作电压是3.3V-5V。micro:bit的3.3V引脚可以提供有限的电流。虽然二哈在识别时功耗不大但为了系统最稳定强烈建议将二哈的VCC连接到麦昆Plus主板上为舵机预留的VCC5V引脚如果麦昆Plus板载了5V输出或者使用一个外部的5V稳压模块。如果直接接micro:bit的3.3V在长时间运行时可能因电流不足导致二哈重启或识别不稳定。为什么选择P1和P2引脚在MakeCode或MicroPython编程环境中micro:bit的串口1Serial默认可以使用P1TX和P2RX引脚。这是一个软串口非常灵活。当然你也可以选择其他支持串口的引脚对但P1/P2是最常见且兼容性最好的选择。2.2 电源方案设计与避坑指南电源是嵌入式项目稳定的基石这个项目存在两个主要的耗电部分micro:bit主控和二哈识图传感器以及一个大的耗电部分麦昆Plus的两个直流电机。不推荐的方案单一电源供电。试图用一块电池同时为逻辑部分micro:bit、二哈和动力部分电机供电当电机启动或堵转时会产生很大的瞬时电流导致电压瞬间跌落称为“电压毛刺”。这极有可能造成micro:bit重启、二哈死机表现为程序“跑飞”或识别中断。这是新手最容易踩的坑。推荐的稳定方案双电源隔离。逻辑电源使用一块独立的3.7V锂电池或者通过移动电源/USB接口通过麦昆Plus的电池接口或扩展板上的VCC为micro:bit和二哈识图供电。确保电压稳定在3.3V-5V之间。动力电源麦昆Plus本身的电机驱动部分最好使用另一组电池如常见的4节AA电池盒供电。这样电机工作的剧烈电流波动就不会干扰到核心的控制电路。如果你只有一组电源比如一个大的锂电池那么必须在电机的电源输入线上增加一个大容量的电解电容例如470uF 16V它可以吸收电机产生的瞬间电流冲击起到缓冲和稳压的作用能在一定程度上缓解电压跌落问题。但这仍然不如物理隔离的双电源方案来得彻底可靠。3. 通信协议与指令集设计定义机器人的“语言”硬件连通后我们需要为二哈和麦昆定义一套它们都能理解的“语言”。核心流程是二哈识别二维码内容 - 通过串口发送给micro:bit - micro:bit解析内容并控制麦昆执行动作。3.1 二维码内容编码规则二维码里应该存储什么我们不能直接存储复杂的程序而应该存储一条条简洁的“指令”。我设计了一种简单的文本协议格式如下命令字:参数1,参数2,...例如MOVE:F,1000表示移动(MOVE)方向向前(F)时长1000毫秒。TURN:L,90表示转向(TURN)方向向左(L)角度90度。BEEP:1,500表示蜂鸣(BEEP)响一声(1)频率500或持续时间500ms。LED:255,0,0表示控制RGB灯(LED)颜色为红色 (R255, G0, B0)。STOP表示停止所有动作。为什么用文本协议因为它直观、易调试。在串口监视器里你能直接看到MOVE:F,1000这样的字符串非常容易判断识别和传输是否正确。二进制协议虽然效率高但可读性差不利于教学和快速调试。3.2 二哈识图的数据输出格式与解析二哈识图识别到二维码后会通过串口输出一帧数据。我们需要在micro:bit的程序里解析这帧数据提取出二维码的字符串内容。二哈的UART协议帧格式通常是这样的以文本模式为例ID:1, x:100, y:100, width:50, height:50, content:“MOVE:F,1000”我们需要的是content:后面的部分。在编程时我们不能简单地去寻找“content:”这个字符串因为二维码内容本身也可能包含这个单词。更可靠的方法是解析完整的JSON格式数据如果二哈固件支持或者使用字符串分割法利用引号作为边界来提取内容。一个健壮的解析思路在micro:bit的MakeCode或Python中等待串口数据直到收到完整的帧可以通过判断是否包含换行符\n或帧尾特定字符。在接收到的字符串中寻找第一个双引号的位置。从该位置之后寻找下一个双引号的位置。提取这两个引号之间的子字符串这就是二维码的原始内容。对这个内容进行二次解析按照我们定义的命令字:参数格式拆分并执行对应的函数。这个过程听起来有点绕但它是确保能从可能夹杂了其他信息的协议帧中准确提取出有效指令的关键。很多初学者会直接截取固定长度的字符串一旦二维码内容长度变化程序就会出错。4. 移动端指令工厂用App Inventor 2打造二维码生成器为了让生成指令二维码的过程更便捷我们不用每次都去电脑上打开一个二维码生成网站。用App Inventor 2AI2快速开发一个手机App是最佳选择。4.1 App界面与功能设计我们的App需要以下几个核心组件指令选择/输入区可以用按钮列表预设常用指令如“前进”、“左转”也可以提供一个文本输入框让用户输入自定义的指令字符串如LED:0,255,0。参数输入区对于某些指令需要输入参数。例如前进的“时长”、转向的“角度”。可以用数字选择器或文本框实现。生成按钮点击后将选择的命令字和输入的参数组合成完整的指令字符串如MOVE:F,1000。二维码显示区一个图像组件用于显示根据指令字符串实时生成的二维码图片。历史记录/指令集管理进阶功能可以保存常用的指令组合方便快速调用。4.2 利用AI2扩展实现二维码生成App Inventor 2本身没有内置的二维码生成组件但社区有强大的扩展。我们可以使用Barcode扩展或者ZXingZebra Crossing库的扩展。以使用一个常见的Barcode扩展为例操作步骤如下在AI2的设计视图中导入Barcode扩展通常在“扩展”功能中搜索添加。在逻辑设计Blocks中你会看到新的积木块例如调用 Barcode1.EncodeText 生成二维码。这个积木块需要两个输入text要编码的文本和format格式选择QR_CODE。它将返回一个图片image格式的数据。将这个返回的图片数据赋值给界面上的图像组件的图片属性二维码就显示出来了。核心逻辑积木示例当 按钮生成.被点击 时 执行 变量 指令文本 设为 拼接字符串“MOVE:F,” 和 文本框时长.文本 变量 二维码图片 设为 调用 Barcode1.EncodeText 文本 指令文本 格式 QR_CODE 图像二维码.图片 设为 二维码图片这样一个简单的指令二维码生成器就做好了。你可以把手机屏幕对准二哈识图或者将二维码打印在纸上进行测试。4.3 提升体验实时生成与错误处理为了让App更好用我们可以实现“实时生成”功能当用户选择指令或修改参数时二维码图像立即更新无需点击按钮。这可以通过为选择列表和文本框设置“当选择改变”或“当文本改变”事件监听器来实现。同时必须加入简单的错误处理。例如检查参数输入框是否为空、是否为数字。如果用户输入了非数字字符在生成二维码前应弹出提示而不是生成一个无效的、可能导致小车解析错误的二维码。5. micro:bit主控程序编写小车的大脑逻辑这是整个项目的核心控制程序运行在麦昆Plus的micro:bit上。我们需要完成串口通信、指令解析、动作执行三大功能。5.1 开发环境选择与初始化你可以选择MakeCode图形化或MicroPython代码。对于复杂逻辑和字符串处理MicroPython更具优势且更清晰。这里以MicroPython为例。首先初始化串口并设置好麦昆Plus的电机和舵机引脚。from microbit import * import music import neopixel # 如果控制RGB灯需要 # 初始化串口使用P1(TX), P2(RX)波特率9600需与二哈设置一致 uart.init(baudrate9600, txpin1, rxpin2) # 初始化麦昆Plus电机引脚 (以常见引脚为例具体需查阅麦昆Plus资料) # 假设左电机P13方向 P14速度右电机P15方向 P16速度 # 这里需要根据你的麦昆Plus实际驱动芯片型号调整 LEFT_MOTOR_P pin13 LEFT_MOTOR_S pin14 RIGHT_MOTOR_P pin15 RIGHT_MOTOR_S pin16 # 初始化RGB灯带如果有 # np neopixel.NeoPixel(pin12, 2) # 假设灯带接在P12有2颗灯 # 全局变量用于存储从串口接收的数据 received_data “”5.2 串口数据接收与帧解析我们需要编写一个函数负责从串口持续读取数据并拼接到一个缓冲区中直到检测到一帧数据的结束例如换行符\n。def read_uart_line(): global received_data if uart.any(): # 如果串口有数据 incoming uart.read() # 读取字节数据 if incoming: try: # 将字节转换为字符串 str_in str(incoming, ‘utf-8’) received_data str_in # 检查是否收到换行符一帧结束 if ‘\n’ in received_data: line, received_data received_data.split(‘\n’, 1) return line.strip() # 返回处理好的单行数据去除首尾空白 except: # 如果解码失败清空缓冲区 received_data “” return None5.3 指令解析与动作执行引擎这是最核心的部分一个command_executor函数它接收解析出来的二维码内容字符串并执行对应的动作。def command_executor(cmd_str): # 示例 cmd_str: “MOVE:F,1000” if not cmd_str or ‘:’ not in cmd_str: return parts cmd_str.split(‘:’) command parts[0] params parts[1].split(‘,’) if len(parts) 1 else [] if command “MOVE”: # 参数方向时间(ms) direction params[0] duration int(params[1]) if len(params) 1 else 1000 move_car(direction, duration) elif command “TURN”: # 参数方向角度 direction params[0] angle int(params[1]) if len(params) 1 else 90 turn_car(direction, angle) elif command “BEEP”: # 参数次数频率/时长 times int(params[0]) if len(params) 0 else 1 freq int(params[1]) if len(params) 1 else 440 for _ in range(times): music.pitch(freq, 200) sleep(200) elif command “LED”: # 参数R, G, B if len(params) 3: r int(params[0]) g int(params[1]) b int(params[2]) set_led_color(r, g, b) # 需要实现这个函数 elif command “STOP”: stop_car() # 可以继续添加其他命令... def move_car(dir, duration_ms): # 根据方向(dir’F’/’B’/’L’/’R’)设置电机引脚高低电平 # 这里需要根据你的电机驱动电路逻辑来写 # 例如向前左电机正转右电机正转 if dir ‘F’: LEFT_MOTOR_P.write_digital(1) # 假设1为正转 LEFT_MOTOR_S.write_analog(500) # PWM速度值 RIGHT_MOTOR_P.write_digital(1) RIGHT_MOTOR_S.write_analog(500) elif dir ‘B’: # 反转逻辑 pass sleep(duration_ms) stop_car() # 时间到停止 def stop_car(): LEFT_MOTOR_S.write_analog(0) # 速度PWM置0 RIGHT_MOTOR_S.write_analog(0)5.4 主循环与状态反馈最后在主循环中不断读取串口指令并执行同时可以通过micro:bit的LED点阵显示当前状态如笑脸表示就绪X表示出错。while True: line read_uart_line() if line: display.show(Image.HAPPY) # 收到指令显示笑脸 # 从二哈的数据帧中提取二维码内容 # 假设二哈输出为QRCode:1, x:0,y:0, data:“MOVE:F,1000” if ‘data:“’ in line and ‘”’ in line: start line.find(‘data:“’) len(‘data:“’) end line.find(‘”’, start) qr_content line[start:end] command_executor(qr_content) else: # 如果不是预期的二维码数据帧可能是其他识别结果忽略或做其他处理 pass sleep(100) # 短暂延时防止过于频繁刷新 display.clear() sleep(50) # 主循环延时6. 系统联调与实战避坑指南当硬件、App、主控程序都准备好后真正的挑战才开始把它们整合在一起并解决实际运行中出现的各种问题。6.1 分步调试法隔离问题源头不要试图一次性让整个系统跑通。采用分步调试能快速定位问题所在。第一步测试二哈识图本身。脱离小车用USB线将二哈直接连接到电脑使用厂家提供的上位机软件或串口调试助手观察它是否能正确识别并输出二维码信息。确保二哈的识别模式已切换到“二维码识别”。第二步测试micro:bit串口接收。将二哈按正确方式连接到micro:bit并将micro:bit通过USB连接电脑。在MicroPython的REPL环境或使用串口调试工具打印read_uart_line()函数接收到的原始字符串。手动展示一个二维码给二哈看micro:bit端能否打印出完整的、包含data:“...”的字符串。第三步测试指令解析与动作。在第二步的基础上修改程序不等待二哈数据而是直接模拟一个指令字符串如command_executor(“MOVE:F,1000”)看小车是否能正确执行前进动作。这一步验证了电机驱动和动作函数是否正确。第四步测试App生成的二维码。用App生成一个二维码用手机屏幕展示。用第二步中的micro:bit程序已包含解析逻辑来扫描这个二维码观察接收到的字符串是否与App中设定的完全一致。这里一个常见坑是手机屏幕反光或亮度不足导致二哈识别困难。尽量调高手机亮度并在光线均匀的环境下测试。第五步全系统集成。将以上所有步骤连接起来。从App生成二维码 - 二哈识别 - micro:bit接收并解析 - 小车动作。6.2 常见问题与解决方案问题1二哈识别不稳定时好时坏。可能原因A光照条件。二维码识别需要良好的对比度。环境光太暗、太亮或有强烈反光都会影响。确保光线均匀二维码图案清晰。可能原因B对焦距离。二哈有固定的焦距范围通常约10cm到无穷远。将二维码放在它清晰对焦的距离内不要太近或太远。可能原因C电源不稳。回顾2.2节的电源方案确保二哈的供电电压和电流充足。解决方案优化光照调整距离并确保使用稳定的电源。可以在程序中加入识别成功反馈比如让micro:bit的LED显示对勾便于观察。问题2小车动作与预期不符如转的角度不准、走不直。可能原因A电机差异与电池电量。即使是同一型号的两个电机其转速也有细微差异且电池电压下降会影响电机转速。这会导致小车无法走直线或转向角度不准。可能原因B地面摩擦力。在不同地面上如木地板、地毯摩擦力不同会影响小车的实际移动距离。解决方案这是开源小车平台的通病。可以通过软件校准来改善。例如为左右电机设置不同的PWM补偿值。更高级的做法是引入编码器或陀螺仪如micro:bit内置的加速度计/磁力计可粗略估算转向进行闭环控制但这会大大增加复杂度。对于本项目接受一定误差或通过实验为“前进1秒”、“左转90度”这样的指令找到在当前地面条件下最合适的PWM值和持续时间并将其固化为参数。问题3串口数据接收混乱或丢失。可能原因A波特率不匹配。确保二哈识图设置的串口波特率与micro:bit程序中uart.init的波特率完全一致常用9600或115200。可能原因B数据帧中断。程序处理一条指令的时间过长导致下一条指令的数据到来时上一条还没读完造成缓冲区数据混杂。解决方案检查并统一波特率。在read_uart_line函数中确保缓冲区处理逻辑健壮一旦收到完整帧就立即返回并清空缓冲区。在主循环中处理完一条指令后可以加入一个短暂的sleep(100)让串口缓冲区有足够时间接收下一帧数据的起始部分但这不是根本办法。根本在于提高代码执行效率或者让二哈降低发送频率如果可配置。问题4App生成的二维码二哈识别出的内容末尾有多余字符。可能原因二哈的二维码识别算法有时会将二维码周围的一些图案噪点也误识别为内容的一部分或者其协议帧本身有固定的后缀。解决方案在micro:bit的解析程序中不要完全相信二哈输出的整个content字段。可以基于我们指令的格式如以MOVE:、TURN:开头进行二次验证。只提取符合我们指令格式规则的部分。或者在App生成二维码时在指令文本的首尾加上特定的开始和结束标记如#MOVE:F,1000#在解析时只提取两个#之间的内容这样更可靠。7. 项目扩展与进阶玩法这个“二维码编程机”只是一个起点它的框架具有很强的可扩展性。一旦跑通你可以尝试以下更有趣的玩法1. 实现“编程卡片”或“任务卡”系统制作一系列二维码卡片每张卡片代表一个基础动作积木。让孩子或用户像玩拼图一样将这些卡片按顺序排列在地上然后用小车依次扫描执行直观地理解“顺序执行”的编程概念。2. 引入流程控制逻辑升级你的指令协议。例如设计一个LOOP:3循环开始和ENDLOOP循环结束的二维码。当小车扫描到LOOP:3时将之后直到ENDLOOP的所有指令存入一个列表并重复执行3次。这就实现了循环结构。3. 结合其他传感器实现条件判断让二维码指令不再是简单的动作而是触发一个“模式”。例如扫描一个FOLLOW_LINE二维码小车就进入巡线模式直到扫描到STOP二维码才退出。或者扫描AVOID_OBSTACLE二维码小车启动自动避障功能。这需要你在micro:bit程序中实现更复杂的状态机。4. 创建图形化编程界面将App Inventor 2的App升级为一个真正的图形化编程界面。用户可以在手机上拖拽“前进”、“转向”、“亮灯”等图形积木块组合成程序流程图App后台自动将这些图形序列翻译成我们定义的指令字符串并生成一个总控二维码。小车只需扫描这个总控二维码就能依次执行整个程序序列的所有步骤。这相当于实现了一个超简化的、实体化的Scratch。5. 多车协作与通信如果你有两套甚至多套这样的设备可以设计更复杂的游戏。例如一辆车是“指挥车”它扫描的二维码指令可以通过无线方式如micro:bit的无线电功能发送给另一辆“执行车”。或者设计一个“接力赛”每辆车负责一段路程扫描自己的启动二维码后开始运行到达终点后亮起灯提示下一辆车可以扫描它的二维码出发。这个项目的魅力在于它用非常直观的方式将抽象的代码、具体的动作和物理世界连接了起来。无论是用于教学还是作为个人创意项目它都能带来满满的成就感。从最基础的“扫一扫动一动”到后来设计复杂的交互逻辑整个过程就像在给一个电子宠物设计行为模式乐趣无穷。我自己的小车在调试阶段经常满地乱跑或者对着一个二维码发呆这些“翻车”现场现在回想起来都是解决问题过程中最宝贵的记忆。