手把手教你用 MicroPython 玩转幻尔串口舵机,代码+教程全公开

原文链接:

FreakStudio的博客

摘要

MicroPython串口舵机库,支持幻尔科技全系列舵机,支持mpremote工具一键导入,28条指令全测试。

往期推荐:

学嵌入式的你,还不会面向对象??!

全网最适合入门的面向对象编程教程:00 面向对象设计方法导论

全网最适合入门的面向对象编程教程:01 面向对象编程的基本概念

全网最适合入门的面向对象编程教程:02 类和对象的 Python 实现-使用 Python 创建类

全网最适合入门的面向对象编程教程:03 类和对象的 Python 实现-为自定义类添加属性

全网最适合入门的面向对象编程教程:04 类和对象的Python实现-为自定义类添加方法

全网最适合入门的面向对象编程教程:05 类和对象的Python实现-PyCharm代码标签

全网最适合入门的面向对象编程教程:06 类和对象的Python实现-自定义类的数据封装

全网最适合入门的面向对象编程教程:07 类和对象的Python实现-类型注解

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系

全网最适合入门的面向对象编程教程:10 类和对象的Python实现-类的继承和里氏替换原则

全网最适合入门的面向对象编程教程:11 类和对象的Python实现-子类调用父类方法

全网最适合入门的面向对象编程教程:12 类和对象的Python实现-Python使用logging模块输出程序运行日志

全网最适合入门的面向对象编程教程:13 类和对象的Python实现-可视化阅读代码神器Sourcetrail的安装使用

全网最适合入门的面向对象编程教程:全网最适合入门的面向对象编程教程:14 类和对象的Python实现-类的静态方法和类方法

全网最适合入门的面向对象编程教程:15 类和对象的 Python 实现-__slots__魔法方法

全网最适合入门的面向对象编程教程:16 类和对象的Python实现-多态、方法重写与开闭原则

全网最适合入门的面向对象编程教程:17 类和对象的Python实现-鸭子类型与"file-like object"

全网最适合入门的面向对象编程教程:18 类和对象的Python实现-多重继承与PyQtGraph串口数据绘制曲线图

全网最适合入门的面向对象编程教程:19 类和对象的 Python 实现-使用 PyCharm 自动生成文件注释和函数注释

全网最适合入门的面向对象编程教程:20 类和对象的Python实现-组合关系的实现与CSV文件保存

全网最适合入门的面向对象编程教程:21 类和对象的Python实现-多文件的组织:模块module和包package

全网最适合入门的面向对象编程教程:22 类和对象的Python实现-异常和语法错误

全网最适合入门的面向对象编程教程:23 类和对象的Python实现-抛出异常

全网最适合入门的面向对象编程教程:24 类和对象的Python实现-异常的捕获与处理

全网最适合入门的面向对象编程教程:25 类和对象的Python实现-Python判断输入数据类型

全网最适合入门的面向对象编程教程:26 类和对象的Python实现-上下文管理器和with语句

全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

全网最适合入门的面向对象编程教程:28 类和对象的Python实现-Python编程原则、哲学和规范大汇总

全网最适合入门的面向对象编程教程:29 类和对象的Python实现-断言与防御性编程和help函数的使用

全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类

全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

全网最适合入门的面向对象编程教程:32 Python的内置数据类型-类Class和实例Instance

全网最适合入门的面向对象编程教程:33 Python的内置数据类型-对象Object和类型Type的关系

全网最适合入门的面向对象编程教程:34 Python的内置数据类型-Python常用复合数据类型:元组和命名元组

全网最适合入门的面向对象编程教程:35 Python的内置数据类型-文档字符串和__doc__属性

全网最适合入门的面向对象编程教程:36 Python的内置数据类型-字典

全网最适合入门的面向对象编程教程:37 Python常用复合数据类型-列表和列表推导式

全网最适合入门的面向对象编程教程:38 Python常用复合数据类型-使用列表实现堆栈、队列和双端队列

全网最适合入门的面向对象编程教程:39 Python常用复合数据类型-集合

全网最适合入门的面向对象编程教程:40 Python常用复合数据类型-枚举和enum模块的使用

全网最适合入门的面向对象编程教程:41 Python常用复合数据类型-队列(FIFO、LIFO、优先级队列、双端队列和环形队列)

全网最适合入门的面向对象编程教程:42 Python常用复合数据类型-collections容器数据类型

全网最适合入门的面向对象编程教程:43 Python常用复合数据类型-扩展内置数据类型

全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法

全网最适合入门的面向对象编程教程:45 Python实现常见数据结构-链表、树、哈希表、图和堆

全网最适合入门的面向对象编程教程:46 Python函数方法与接口-函数与事件驱动框架

全网最适合入门的面向对象编程教程:47 Python函数方法与接口-回调函数Callback

全网最适合入门的面向对象编程教程:48 Python函数方法与接口-位置参数、默认参数、可变参数和关键字参数

全网最适合入门的面向对象编程教程:49 Python函数方法与接口-函数与方法的区别和lamda匿名函数

全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类

全网最适合入门的面向对象编程教程:51 Python函数方法与接口-使用Zope实现接口

全网最适合入门的面向对象编程教程:52 Python函数方法与接口-Protocol协议与接口

全网最适合入门的面向对象编程教程:53 Python字符串与序列化-字符串与字符编码

全网最适合入门的面向对象编程教程:54 Python字符串与序列化-字符串格式化与format方法

全网最适合入门的面向对象编程教程:55 Python字符串与序列化-字节序列类型和可变字节字符串

全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用

全网最适合入门的面向对象编程教程:57 Python字符串与序列化-序列化与反序列化

全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现

全网最适合入门的面向对象编程教程:59 Python并行与并发-并行与并发和线程与进程

更多精彩内容可看:

给你的 Python 加加速:一文速通 Python 并行计算

一文搞懂 CM3 单片机调试原理

肝了半个月,嵌入式技术栈大汇总出炉

电子计算机类比赛的"武林秘籍"

一个MicroPython的开源项目集锦:awesome-micropython,包含各个方面的Micropython工具库

Avnet ZUBoard 1CG开发板---深度学习新选择

工程师不要迷信开源代码,还要注重基本功

什么?配色个性化的电机驱动模块?!!

什么?XIAO主控新出三款扩展板!

1.原先库存在的问题

这里,我们看厂家提供的MicroPython库中代码:


实际上,并没有很好的实现功能解耦和充分利用Python面向对象的特性。

可以看到,多个方法中间存在重复的收发逻辑:

同时,UART 波特率(115200)、超时时间(50ms)等硬编码在代码中,而非可配置:

并且,无 API 文档和示例代码,不利于用户快速上手,也缺乏必要的入口参数校验机制,如判断舵机ID、角度范围、速度范围是否合理:

因此,我决定自己写一个MicroPython版本的幻尔科技串口舵机库。

仓库地址为:
Freak嵌入式-MicroPython串口舵机库

我也将其发布到了PyPi上(虽然不适合发布到上面,只是方便后期讲解Python发布第三方库):
Freak嵌入式-MicroPython串口舵机库-PyPi

2.serial_servo库介绍

2.1 简介与主要特性

通过串口舵机库,用户可以控制多个舵机的角度、速度等参数,实现高效、灵活的舵机控制,程序中使用了串口通讯与舵机进行数据交互,提供了完整的控制命令和反馈解析功能。

推荐大家使用我们的串口舵机扩展板,感谢支持:
Freak嵌入式-多米诺系列-串口舵机驱动板

主要特性包括:

  • 使用UART串口与舵机通信,支持多舵机控制。
  • 支持舵机的角度、速度、工作模式等多种设置。
  • 支持舵机温度、电压、角度等实时读取。
  • 校验和机制确保数据传输的完整性,幻尔科技串口舵机28条指令全部实现,并且封装为类。
  • 完整的异常捕获机制,对入口参数进行详细检查。
  • 注释完善,所有方法和类均提供了类型注解。

该类封装了舵机控制相关的所有功能,包括生成和发送控制指令、接收舵机反馈、读取舵机状态等。

  • __init__(self, uart: UART) -> None:初始化串口舵机控制类。
  • calculate_checksum(data: list[int]) -> int:计算校验和,确保数据的完整性和正确性。
  • build_packet(servo_id: int, cmd: int, params: list[int]) -> bytearray:构建舵机控制指令包。
  • send_command(servo_id: int, cmd: int, params: list[int] = []) -> None:发送控制指令到指定舵机。
  • receive_command(expected_cmd: int, expected_data_len: int) -> list:接收并解析舵机返回的指令数据包。
  • move_servo_immediate(servo_id: int, angle: float, time_ms: int) -> None:立即控制舵机转动到指定角度。
  • get_servo_move_immediate(servo_id: int) -> tuple:获取舵机的预设角度和时间。
  • move_servo_with_time_delay(servo_id: int, angle: float, time_ms: int) -> None:控制舵机延迟转动到指定角度。
  • get_servo_move_with_time_delay(servo_id: int) -> tuple:获取舵机的延迟转动角度和时间。
  • start_servo(servo_id: int) -> None:启动舵机的转动。
  • stop_servo(servo_id: int) -> None:立即停止舵机转动并停在当前角度位置。
  • set_servo_id(servo_id: int, new_id: int) -> None:设置舵机的新 ID 值。
  • get_servo_id(servo_id: int) -> int:获取舵机的 ID。
  • set_servo_angle_offset(servo_id: int, angle: float, save_to_memory: bool = False) -> None:根据角度值调整舵机的偏差。
  • get_servo_angle_offset(servo_id: int) -> float:获取舵机的偏差角度。
  • set_servo_angle_range(servo_id: int, min_angle: float, max_angle: float) -> None:设置舵机的最小和最大角度限制。
  • get_servo_angle_range(servo_id: int) -> tuple:获取舵机的角度限位。
  • set_servo_vin_range(servo_id: int, min_vin: float, max_vin: float) -> None:设置舵机的最小和最大输入电压限制。
  • get_servo_vin_range(servo_id: int) -> tuple:获取舵机的电压限制值。
  • set_servo_temp_range(servo_id: int, max_temp: int) -> None:设置舵机的最高温度限制。
  • get_servo_temp_range(servo_id: int) -> int:获取舵机的内部最高温度限制值。
  • read_servo_temp(servo_id: int) -> int:获取舵机的实时温度。
  • read_servo_voltage(servo_id: int) -> float:获取舵机的实时输入电压。
  • read_servo_pos(servo_id: int) -> float:获取舵机的实时角度位置。
  • set_servo_mode_and_speed(servo_id: int, mode: int, speed: int) -> None:设置舵机的工作模式和电机转速。
  • get_servo_mode_and_speed(servo_id: int) -> tuple:获取舵机的工作模式和转动速度。
  • set_servo_motor_load(servo_id: int, unload: bool) -> None:设置舵机的电机是否卸载掉电。
  • get_servo_motor_load_status(servo_id: int) -> bool:获取舵机电机是否装载或卸载。
  • set_servo_led(servo_id: int, led_on: bool) -> None:设置舵机的 LED 灯的亮灭状态。
  • get_servo_led(servo_id: int) -> bool:获取舵机 LED 的亮灭状态。
  • set_servo_led_alarm(servo_id: int, alarm_code: int) -> None:设置舵机 LED 闪烁报警对应的故障值。
  • get_servo_led_alarm(servo_id: int) -> int:获取舵机 LED 故障报警状态。

2.2 核心方法介绍

该类的核心是通过 UART(串口通信)与舵机通信。类中的常量定义包括了多种控制命令和舵机相关的设置。这些常量包括了指令的编号、参数长度和返回数据长度。例如:

  • SERVO_MOVE_TIME_WRITESERVO_MOVE_TIME_READ 是与舵机位置控制相关的指令及其参数格式。
  • SERVO_ID_WRITESERVO_ID_READ 是与舵机ID相关的读写指令。

这些常量帮助类在进行通信时,能确保发送正确的指令和正确解析返回的数据。

READ_COMMANDS 集合定义了所有读取命令的编号,这些命令对应舵机的数据读取请求,例如,读取舵机的实时电压、角度、温度等信息。

这个集合便于在 receive_command() 方法中判断接收到的数据是否为期望的读取命令。

串口舵机类的核心方法为:

  • 构建数据包方法 build_packet :该方法用于构建舵机控制的指令包,指令包由以下部分组成:
    • 帧头:固定为 0x55, 0x55
    • 舵机ID:唯一标识每个舵机
    • 数据长度:包括指令和参数
    • 指令编号:具体的控制指令
    • 参数:控制指令的参数
    • 校验和:用于校验数据包的完整性
  • 发送指令方法 send_command :该方法构建指令包并通过 UART 发送给舵机,它调用了build_packet()来构造数据包,
    并通过self.uart.write()发送数据。
  • 接收指令方法 receive_commandreceive_command() 方法用于接收来自舵机的反馈数据,此方法的工作过程如下:
    1. 命令验证:确认接收到的是读取命令,而不是其他类型的命令。
    2. 数据检查:检查数据的帧头是否正确,命令编号是否匹配,数据长度是否符合预期。
    3. 校验和验证:验证接收到的数据包的校验和是否正确,确保数据未被篡改。
    4. 数据解析:根据返回的数据长度,解析并返回舵机的状态或数据(例如电压、角度等)。
    5. 如果数据包无效(如校验和错误、数据长度不符等),该方法将返回空列表。

SerialServo 类的设计通过封装舵机控制指令和数据包的构建逻辑,简化了舵机通信过程,核心思路是通过统一的数据包格式和校验机制确保指令的正确传输,

结合 UART 通信接口实现与舵机的高效交互。类内指令常量和参数处理使得操作更加清晰易懂,

同时通过校验和和数据长度的验证确保数据的完整性和可靠性。

3.如何使用

3.1 安装依赖

在运行示例程序之前,确保你的环境中安装了machinetime等模块。你可以通过MicroPython的包管理器安装依赖。

您可以使用如下语句和 mpremote 工具安装该库:

bash 复制代码
mpremote mip install https://github.com/leezisheng/freakstudio-micropython-libraries/tree/main/serial_servo

或者(推荐):

bash 复制代码
mpremote mip install github:leezisheng/freakstudio-micropython-libraries/serial_servo

安装进行中会显示:

bash 复制代码
(base) PS D:\lee\windows terminal\terminal-1.17.11461.0> mpremote mip install github:leezisheng/freakstudio-micropython-libraries/serial_servo
Install github:leezisheng/freakstudio-micropython-libraries/serial_servo
Installing github:leezisheng/freakstudio-micropython-libraries/serial_servo/package.json to /lib
Installing: /lib/serial_servo/__init__.py
Installing: /lib/serial_servo/serial_servo.py
Installing micropython-machine (latest) from https://micropython.org/pi/v2 to /lib
Package may be partially installed
mpremote: Package not found: https://micropython.org/pi/v2/package/6/micropython-machine/latest.json

安装完成后,通过mpremote工具,连接你的开发板,如果成功安装,会显示如下信息:

bash 复制代码
(base) PS D:\lee\windows terminal\terminal-1.17.11461.0> mpremote connect COM8
Connected to MicroPython at COM8
Use Ctrl-] or Ctrl-x to exit this shell

>>> import os
>>> os.listdir()
['lib']
>>> from serial_servo import SerialServo
>>>

如果通过 mpremote 安装失败,您可以选择手动安装库,即选择 Download ZIP,然后解压文件。

  1. 将该程序文件保存为 serial_servo.py
  2. 确保使用的主控板通过舵机驱动扩展板已连接好舵机和串口,接线供电无异常。
  3. 在MicroPython环境中,通过import serial_servo导入该模块。

3.2 使用示例

在使用前,我们需要注意:

  • 硬件连接:确保舵机的电源和控制线正确连接
  • 串口通信参数设置:串口通信的波特率必须与舵机的波特率匹配,为115200,数据位为8,无校验位,停止位为1。
  • 响应等待:每次发送指令后,最好等待舵机响应,避免指令丢失。

你可以像下面这样,去调用串口舵机控制类中方法控制舵机或者读取其状态:

python 复制代码
from machine import Pin, UART
from serial_servo import SerialServo

# 配置UART串口
uart = UART(1, baudrate=115200, tx=Pin(4), rx=Pin(5))

# 初始化串口舵机控制类
servo = SerialServo(uart)

# 控制舵机转到指定角度
servo.move_servo_immediate(servo_id=1, angle=90.0, time_ms=1000)

# 获取舵机的角度和时间设置
angle, time = servo.get_servo_move_immediate(servo_id=1)
print(f"Servo ID: 1, Angle: {angle}, Time: {time}")

下面是实测的相关图片:



如有任何问题或需要帮助,请通过 [email protected] 联系开发者。

相关推荐
橙色小博17 分钟前
利用Python 进行自动化操作: Pyautogui 库
开发语言·python·自动化·pyautogui·办公
fydw_71532 分钟前
深入解析 Flask 命令行工具与 flask run命令的使用
后端·python·flask
先做个垃圾出来………37 分钟前
Flask中secret_key设置解析
后端·python·flask
weixin_5176621440 分钟前
DAY 20 奇异值SVD分解
python
YYXZZ。。2 小时前
PyTorch——线性层及其他层介绍(6)
pytorch·python·深度学习
哆啦A梦的口袋呀2 小时前
基于Python学习《Head First设计模式》第三章 装饰者模式
python·学习·设计模式
哆啦A梦的口袋呀2 小时前
基于Python学习《Head First设计模式》第五章 单件模式
python·学习·设计模式
love530love2 小时前
【笔记】Windows 下载并安装 ChromeDriver
人工智能·windows·笔记·python·深度学习
Dxy12393102162 小时前
DrissionPage 异常处理实战指南:构建稳健的网页自动化防线
运维·爬虫·python·自动化·drissionpage
chao_7893 小时前
链表题解——反转链表【LeetCode】
开发语言·python·算法