You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用操纵杆控制Arduino舵机时实现平滑运动的技术求助

解决Arduino摇杆控制舵机运动不流畅的问题

问题分析

原代码直接将摇杆读取的数值转换为舵机角度并立即写入,既没有做平滑过渡处理,也没过滤摇杆本身的信号噪声,导致舵机出现跳变、卡顿。用delay()不仅无法解决平滑问题,还会阻塞程序,影响摇杆的实时响应。

解决方案:实现角度插值(平滑过渡)

核心思路:

  • 跟踪舵机的当前角度和目标角度
  • 每次循环只让舵机向目标角度移动1-2度(可调整步长)
  • 增加摇杆死区,过滤中心附近的微小波动

修改后的完整代码

#include <Servo.h>

#define GROUND_JOY_PIN A3
#define VOUT_JOY_PIN A2
#define XJOY_PIN A1
#define YJOY_PIN A0

Servo myservoX;
Servo myservoY;

// 存储当前角度与目标角度
int currentAngleX = 90;  // 初始角度设为舵机中心位置
int targetAngleX = 90;
int currentAngleY = 90;
int targetAngleY = 90;

// 平滑步长:值越小越平滑,响应稍慢;值越大响应越快,平滑度降低
const int smoothStep = 1;
// 摇杆死区:过滤中心附近的波动,避免舵机小幅抖动
const int deadZone = 20;

void setup() {
  Serial.begin(9600);
  pinMode(VOUT_JOY_PIN, OUTPUT);
  pinMode(GROUND_JOY_PIN, OUTPUT);
  digitalWrite(VOUT_JOY_PIN, HIGH);
  digitalWrite(GROUND_JOY_PIN, LOW);
  myservoX.attach(9);
  myservoY.attach(6);
  // 初始化舵机到中心位置
  myservoX.write(currentAngleX);
  myservoY.write(currentAngleY);
}

void loop() {
  // 处理X轴摇杆与舵机
  int joystickXVal = analogRead(XJOY_PIN);
  int newTargetX = map(joystickXVal, 0, 1023, 0, 180);
  
  // 应用死区:中心附近(512±deadZone)时保持当前目标角度
  if (abs(joystickXVal - 512) > deadZone) {
    targetAngleX = newTargetX;
  }
  
  // 平滑过渡到目标角度
  if (currentAngleX != targetAngleX) {
    currentAngleX += (currentAngleX < targetAngleX) ? smoothStep : -smoothStep;
    // 防止超过目标值
    currentAngleX = constrain(currentAngleX, min(targetAngleX, currentAngleX), max(targetAngleX, currentAngleX));
    myservoX.write(currentAngleX);
  }

  // 处理Y轴摇杆与舵机(逻辑与X轴一致)
  int joystickYVal = analogRead(YJOY_PIN);
  int newTargetY = map(joystickYVal, 0, 1023, 0, 180);
  
  if (abs(joystickYVal - 512) > deadZone) {
    targetAngleY = newTargetY;
  }
  
  if (currentAngleY != targetAngleY) {
    currentAngleY += (currentAngleY < targetAngleY) ? smoothStep : -smoothStep;
    currentAngleY = constrain(currentAngleY, min(targetAngleY, currentAngleY), max(targetAngleY, currentAngleY));
    myservoY.write(currentAngleY);
  }

  // 可选调试输出(不需要可注释,减少串口开销)
  Serial.print("X: 当前=");
  Serial.print(currentAngleX);
  Serial.print(" 目标=");
  Serial.print(targetAngleX);
  Serial.print(" | Y: 当前=");
  Serial.print(currentAngleY);
  Serial.print(" 目标=");
  Serial.println(targetAngleY);

  // 微小延迟,避免循环过快导致舵机频繁触发
  delay(10);
}

关键修改说明

  1. 角度跟踪机制:用currentAngle和targetAngle分离摇杆输入与舵机实际位置,避免直接将波动的摇杆值写入舵机。
  2. 平滑步长控制:每次循环只移动固定小角度,保证运动连续顺滑,步长可根据需求在1-3之间调整。
  3. 摇杆死区处理:过滤中心区域的微小信号波动,防止舵机在中心位置无意义抖动。
  4. 精准角度映射:用map()替代原代码的手动计算,直接将0-1023的摇杆值映射到0-180的舵机角度范围,更准确直观。
  5. 轻量延迟:仅用delay(10)给舵机留足小角度移动时间,不会阻塞摇杆的实时响应。

内容的提问来源于stack exchange,提问作者csomos eliza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:53:16