4、差速驱动AGV运动学:正逆解算与速度控制

差速驱动,说白了就是两个轮子各自独立转动,靠速度差来实现转向。这是AGV里最经典、最基础的结构。我最早接触AGV时,用的就是这种底盘。当时觉得挺简单,后来才发现——嗯,里面的坑还真不少。

今天咱们就把差速驱动的运动学彻底讲透。包括正解、逆解、线速度角速度控制,最后我会给出一套完整的C++代码。你跟着走一遍,基本就能上手了。

4.1 差速驱动模型长什么样?

先看结构。两个驱动轮,左右各一个,中间有个万向轮(或从动轮)撑着。两个轮子同轴,轴距记为L,轮子半径记为r

控制输入是什么?左右轮转速 ω_Lω_R,单位 rad/s。输出呢?车体的线速度 v 和角速度 ω

这里有个关键点:差速驱动不能独立控制 vω 吗?其实可以。但它的控制自由度只有2,所以 vω 就是完全的状态描述。你想想看,给定 vω,就能唯一确定左右轮速度。反过来也一样。

核心公式(先记住这两个):

正运动学:从轮速 → 车体速度

逆运动学:从车体速度 → 轮速

我习惯把正运动学叫做“传感器解算”,逆运动学叫做“控制指令分配”。为什么?因为实际项目中,编码器测到的是轮速,你要算车体走了多远,就得用正解。而你要给电机发指令,就得用逆解。

4.2 正运动学解算

正运动学,就是已知左右轮转速 ω_Lω_R,求车体线速度 v 和角速度 ω

公式推导其实不复杂。左右轮线速度分别是:

v_L = ω_L * r
v_R = ω_R * r

车体线速度是左右轮速度的平均值:

v = (v_L + v_R) / 2

角速度呢?靠速度差。两个轮子速度不一样,车体就会绕中心旋转。角速度公式:

ω = (v_R - v_L) / L

这里 L 是轮距(两个轮子中心的距离)。

合起来就是:

v = r * (ω_R + ω_L) / 2
ω = r * (ω_R - ω_L) / L

我在项目中遇到过一个问题:编码器分辨率不够,导致 v_Lv_R 算出来抖动很大。后来加了低通滤波,才把速度曲线稳住。所以正解算虽然公式简单,但实际工程里滤波和标定才是大头。

4.3 逆运动学解算

逆运动学,就是已知目标线速度 v 和角速度 ω,求左右轮转速 ω_Lω_R

从正解公式反推:

ω_R = (2*v + ω*L) / (2*r)
ω_L = (2*v - ω*L) / (2*r)

这个公式在ROS里用得特别多。比如你发一个 cmd_vel 话题,里面包含 vω,底层驱动就要用逆解算出左右轮目标转速,然后发给电机控制器。

个人经验:逆解算时,一定要做限幅。左右轮转速不能超过电机最大转速。我曾经遇到过,上位机发了一个急转弯指令,角速度设得很大,结果逆解算出来的轮速直接爆表,电机过流保护跳了。从那以后,我每次做逆解都会加一句:

ω_L = clamp(ω_L, -ω_max, ω_max);
ω_R = clamp(ω_R, -ω_max, ω_max);

4.4 线速度与角速度控制

有了正逆解,控制就好办了。典型的控制流程是这样的:

  1. 上位机下发目标 v_targetω_target
  2. 逆解算得到左右轮目标转速
  3. 左右轮各自做PID闭环控制
  4. 编码器反馈实际轮速
  5. 正解算得到实际 vω,用于里程计

这里有个细节:线速度和角速度的控制周期可以不一样。我一般把线速度控制周期设在20ms,角速度设在10ms。为什么?因为角速度响应更快,转弯时如果控制周期太长,车体会晃。

你想想看,AGV在狭窄通道里转弯,角速度控制稍微慢一点,就可能撞墙。所以角速度的PID参数也要单独调,不能跟线速度共用一套。

注意:差速驱动有一个天然限制——它不能原地横向移动。只能前进、后退、转弯。所以路径规划时要考虑这个约束。我曾经见过有人用差速AGV做侧向泊车,结果怎么都停不进去,最后发现是运动学模型选错了。

4.5 实例代码实现

下面给出一套完整的C++实现。代码我实际在STM32和ROS上都跑过,可以直接移植。

// differential_drive_kinematics.h
#pragma once

class DifferentialDriveKinematics {
public:
    // 构造函数:传入轮距L和轮半径r
    DifferentialDriveKinematics(double wheel_distance, double wheel_radius)
        : L_(wheel_distance), r_(wheel_radius) {}

    // 正运动学:轮速 → 车体速度
    void forwardKinematics(double omega_L, double omega_R,
                           double& v, double& omega) {
        double v_L = omega_L * r_;
        double v_R = omega_R * r_;
        v = (v_L + v_R) / 2.0;
        omega = (v_R - v_L) / L_;
    }

    // 逆运动学:车体速度 → 轮速
    void inverseKinematics(double v, double omega,
                           double& omega_L, double& omega_R) {
        omega_R = (2.0 * v + omega * L_) / (2.0 * r_);
        omega_L = (2.0 * v - omega * L_) / (2.0 * r_);
    }

    // 带限幅的逆运动学
    void inverseKinematicsClamped(double v, double omega,
                                  double omega_max,
                                  double& omega_L, double& omega_R) {
        inverseKinematics(v, omega, omega_L, omega_R);
        omega_L = clamp(omega_L, -omega_max, omega_max);
        omega_R = clamp(omega_R, -omega_max, omega_max);
    }

private:
    double L_;  // 轮距 (m)
    double r_;  // 轮半径 (m)

    double clamp(double value, double min, double max) {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }
};

使用示例:

#include "differential_drive_kinematics.h"
#include <iostream>

int main() {
    // 假设轮距0.5m,轮半径0.1m
    DifferentialDriveKinematics kin(0.5, 0.1);

    // 逆解:目标线速度0.5m/s,角速度0.3rad/s
    double omega_L, omega_R;
    kin.inverseKinematicsClamped(0.5, 0.3, 10.0, omega_L, omega_R);
    std::cout << "左轮转速: " << omega_L << " rad/s" << std::endl;
    std::cout << "右轮转速: " << omega_R << " rad/s" << std::endl;

    // 正解:验证一下
    double v, omega;
    kin.forwardKinematics(omega_L, omega_R, v, omega);
    std::cout << "解算回线速度: " << v << " m/s" << std::endl;
    std::cout << "解算回角速度: " << omega << " rad/s" << std::endl;

    return 0;
}

这段代码我建议你直接复制到你的项目里。注意轮距和轮半径一定要标定准确,差1mm都会导致里程计漂移。我曾经吃过这个亏,AGV走直线走了10米,偏了30厘米,最后发现是轮距量错了5mm。

4.6 知识体系总览

下面这张图把差速驱动运动学的核心逻辑串起来了。你看一遍,应该能对整个流程有个全局认识。

差速驱动AGV运动学知识体系 输入:v_target, ω_target 逆运动学解算 输出:ω_L, ω_R (带限幅) 电机PID控制 编码器反馈 正运动学解算 输出:v_actual, ω_actual (用于里程计) 闭环反馈控制 核心算法模块 输入/输出数据 反馈控制回路 数据流向

这张图把整个流程分成了三块:逆解算(控制指令下发)、电机控制与反馈、正解算(里程计)。闭环反馈从里程计回到输入,形成一个完整的控制回路。你实际做项目时,这个框架可以直接套用。


好了,差速驱动的运动学就讲到这里。正解和逆解是基础,线速度角速度控制是核心,代码实现是落地。你把这几个点吃透了,差速AGV的运动控制基本就稳了。

公众号:蓝海资料掘金营,微信deep3321