feat: 舵机控制模块

This commit is contained in:
DongShengWu 2026-01-01 14:27:05 +08:00
parent d96a7dc599
commit 92f40c1cf4
2 changed files with 187 additions and 0 deletions

46
k230/02test_servo.py Normal file
View File

@ -0,0 +1,46 @@
# 02test_servo.py
# 舵机测试程序:最大 -> 最小 -> 中间
# 适用于庐山派 K230-CanMV 开发板
from servo_module import ServoController
import time
import sys
sys.path.append("/sdcard")
# 创建舵机对象 (GPIO47, 角度范围0-270度)
servo = ServoController(gpio_pin=47, min_angle=0, max_angle=360, servo_range=360)
print("舵机测试开始...")
# try:
# # 1. 移动到最大角度
# print("移动到最大角度")
# servo.set_angle(360)
# time.sleep(1)
# # 2. 移动到最小角度 (0度)
# print("移动到最小角度: 0")
# servo.set_angle(0)
# time.sleep(1)
# # 3. 回到中间位置 (135度)
# print("回到中间位置: 135")
# servo.center()
# time.sleep(1)
# print("测试完成!")
# except KeyboardInterrupt:
# print("用户停止")
# finally:
# servo.deinit()
# print("舵机资源已释放")
# 360度舵机需要一直发 sg90。 0-180为顺(速度变小) 180-360为逆速度变大
while True:
servo.set_angle(360)
time.sleep(1)

141
k230/servo_module.py Normal file
View File

@ -0,0 +1,141 @@
# servo_module.py
# 舵机控制模块
# 适用于庐山派 K230-CanMV 开发板
from machine import PWM, FPIOA
# GPIO引脚与PWM通道的固定映射 (40PIN排针可用)
# 排针引脚号 | 芯片引脚号 | PWM通道号
# 12 | GPIO 47 | PWM3
# 26 | GPIO 61 | PWM1
# 32 | GPIO 46 | PWM2
# 33 | GPIO 52 | PWM4
# 35 | GPIO 42 | PWM0
GPIO_PWM_MAP = {
42: 0, # GPIO42 -> PWM0 (排针35)
46: 2, # GPIO46 -> PWM2 (排针32)
47: 3, # GPIO47 -> PWM3 (排针12)
52: 4, # GPIO52 -> PWM4 (排针33)
61: 1, # GPIO61 -> PWM1 (排针26)
}
# PWM通道对应的FPIOA功能
PWM_FPIOA_MAP = {
0: FPIOA.PWM0,
1: FPIOA.PWM1,
2: FPIOA.PWM2,
3: FPIOA.PWM3,
4: FPIOA.PWM4,
}
class ServoController:
"""舵机控制类,支持角度控制和增量控制"""
def __init__(self, gpio_pin, min_angle=0, max_angle=270, servo_range=None):
"""
初始化舵机控制器
参数:
gpio_pin: GPIO引脚号 (42, 46, 47, 52, 61)
min_angle: 软件最小角度限制 (默认0)
max_angle: 软件最大角度限制 (默认270)
servo_range: 舵机物理最大角度范围 (默认与max_angle相同)
用于脉宽计算如180度舵机填180270度舵机填270
"""
# 检查引脚是否支持
if gpio_pin not in GPIO_PWM_MAP:
raise ValueError("不支持的GPIO引脚请使用42, 46, 47, 52, 61")
self._gpio_pin = gpio_pin
self._pwm_channel = GPIO_PWM_MAP[gpio_pin]
self._min_angle = min_angle
self._max_angle = max_angle
# 舵机物理角度范围,用于脉宽计算
self._servo_range = servo_range if servo_range is not None else max_angle
self._current_angle = (min_angle + max_angle) / 2 # 默认中间位置
# 配置GPIO为PWM功能
self._fpioa = FPIOA()
self._fpioa.set_function(gpio_pin, PWM_FPIOA_MAP[self._pwm_channel])
# 初始化PWM频率50Hz
self._pwm = PWM(self._pwm_channel)
self._pwm.freq(50)
# 移动到初始位置
self._update_pwm()
def _angle_to_duty(self, angle):
"""
将角度转换为PWM占空比值
舵机PWM信号: 周期20ms
- 0.5ms脉宽 -> 0
- 2.5ms脉宽 -> 舵机最大角度
根据servo_range动态计算
"""
# 脉宽范围: 0.5ms - 2.5ms,根据舵机物理范围计算
pulse_ms = 0.5 + (angle / self._servo_range) * 2.0
# 占空比: pulse_ms / 20ms * 65535
duty = int((pulse_ms / 20.0) * 65535)
return duty
def _clamp_angle(self, angle):
"""限制角度在有效范围内"""
if angle < self._min_angle:
return self._min_angle
if angle > self._max_angle:
return self._max_angle
return angle
def _update_pwm(self):
"""更新PWM输出"""
duty = self._angle_to_duty(self._current_angle)
self._pwm.duty_u16(duty)
def set_angle(self, angle):
"""
设置舵机到指定角度
参数:
angle: 目标角度
"""
self._current_angle = self._clamp_angle(angle)
self._update_pwm()
def get_angle(self):
"""
获取当前角度
返回:
当前角度值
"""
return self._current_angle
def rotate(self, direction, step):
"""
增量控制舵机
参数:
direction: 方向1为顺时针(角度增大)-1为逆时针(角度减小)
step: 步进角度 (如0.1, 1, 5)
返回:
转动后的角度
"""
new_angle = self._current_angle + (direction * step)
self._current_angle = self._clamp_angle(new_angle)
self._update_pwm()
return self._current_angle
def center(self):
"""舵机归中,移动到角度范围的中间位置"""
center_angle = (self._min_angle + self._max_angle) / 2
self.set_angle(center_angle)
def deinit(self):
"""释放PWM资源"""
if self._pwm:
self._pwm.deinit()
self._pwm = None