diff --git a/k230/02test_servo.py b/k230/02test_servo.py new file mode 100644 index 0000000..f3820ba --- /dev/null +++ b/k230/02test_servo.py @@ -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) diff --git a/k230/servo_module.py b/k230/servo_module.py new file mode 100644 index 0000000..84fcc9f --- /dev/null +++ b/k230/servo_module.py @@ -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度舵机填180,270度舵机填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