1.为什么pid外环输出是内环速度的输入怎样理解 2.单环pid与双环pid分别适用哪种情况 3.双环pid代码C++写法

1.

在PID控制系统中,当使用双环(或称为级联、串联)PID结构时,通常将位置环(外环)的输出作为速度环(内环)的输入,这是为了实现更精确和稳定的控制。这种结构特别适用于需要同时控制位置和速度的应用,例如工业机器人、自动化设备、飞行控制系统等。

为什么PID外环输出是内环速度的输入?

  1. 精确控制:位置环负责确保系统最终达到设定的目标位置,而速度环则负责确保系统以期望的速度和加速度到达该位置。通过将位置环的输出作为速度环的输入,我们可以更精确地控制整个系统的动态行为。

  2. 稳定性和响应速度:速度环可以更快地响应系统内部的动态变化,如外部干扰或系统参数的改变。通过调整速度环的参数,我们可以提高系统的稳定性和响应速度,从而确保系统能够在各种情况下都保持较好的性能。

  3. 解耦:在某些情况下,系统的位置和速度可能相互耦合,即一个变量的变化会影响另一个变量。通过使用双环PID结构,我们可以将这两个变量解耦,从而分别控制它们。这可以简化控制器的设计,并提高系统的性能。

怎样理解?

我们可以将双环PID控制系统看作是一个层次结构,其中位置环是顶层,速度环是底层。顶层负责设定目标位置,并通过底层(速度环)来实现该目标。

  • 位置环(外环):它根据目标位置和实际位置的误差来计算出一个期望的速度(或称为速度指令)。这个速度指令代表了系统为了达到目标位置而应该具有的速度。
  • 速度环(内环):它接收来自位置环的速度指令,并根据实际速度和速度指令的误差来计算出一个控制输出(如电机的电压或电流)。这个控制输出直接作用于系统的执行机构(如电机),以调整系统的速度。

通过这种方式,双环PID控制系统能够同时控制系统的位置和速度,从而实现更精确和稳定的控制。在实际应用中,我们还需要根据系统的具体特性和要求来调整两个环的参数(如比例系数、积分系数和微分系数),以达到最佳的控制效果。

2.

单环PID(Position-only PID)和双环PID(Position-Velocity PID 或称为Cascade PID)在控制系统设计中各有其适用场景。以下是它们各自适用的常见情况:

单环PID(Position-only PID)

适用情况

  • 当系统只需要控制最终位置,而对中间过程(如速度、加速度)没有严格要求时。
  • 在系统模型相对简单,且没有强烈非线性或外部干扰的情况下。
  • 在成本、复杂性和性能之间需要权衡,且可以接受一定精度损失时。

示例

  • 简单的位置控制系统,如一些简单的伺服系统或机器人手臂。
  • 温控系统,只要最终温度达到设定值即可,不关心加热或冷却的速率。

双环PID(Position-Velocity PID 或 Cascade PID)

适用情况

  • 当系统需要精确控制最终位置,并对中间过程(如速度、加速度)有严格要求时。
  • 在系统模型复杂、存在非线性或外部干扰较大的情况下,双环PID可以提供更好的鲁棒性和性能。
  • 在对系统响应速度、稳定性和精度都有较高要求的应用中。

优势

  • 外环(位置环)负责控制最终位置,确保系统达到设定目标。
  • 内环(速度环)负责控制速度,使系统能够更快、更平稳地到达目标位置。
  • 通过合理调整内外环的参数,可以实现更精确的控制,并提高系统的稳定性和响应速度。

示例

  • 工业机器人和自动化设备,需要精确控制位置和速度。
  • 精密加工和测量设备,对位置和速度都有严格要求。
  • 飞行控制系统,如无人机或导弹,需要精确控制飞行轨迹和速度。

总之,单环PID和双环PID各有其优点和适用场景。在选择使用哪种方法时,需要根据具体的应用需求、系统特性和控制要求来进行权衡和选择。

3.

#include <iostream>  
#include <chrono>  
#include <thread>  
  
class PIDController {  
public:  
    PIDController(double kp, double ki, double kd)  
        : kp_(kp), ki_(ki), kd_(kd), prev_error_(0), integral_(0) {}  
  
    double update(double setpoint, double measured_value) {  
        double error = setpoint - measured_value;  
        double p = kp_ * error;  
        double i = ki_ * integral_;  
        double derivative = (error - prev_error_) / dt_; // dt_ 需要在外部设置  
        double d = kd_ * derivative;  
  
        // PID输出  
        double output = p + i + d;  
  
        // 更新误差积分和之前的误差  
        integral_ += error * dt_;  
        prev_error_ = error;  
  
        return output;  
    }  
  
    void setDt(double dt) { dt_ = dt; }  
  
private:  
    double kp_;  
    double ki_;  
    double kd_;  
    double prev_error_;  
    double integral_;  
    double dt_; // 时间间隔,需要在外部设置  
};  
  
// 双环PID控制函数  
double doubleLoopPIDControl(PIDController& positionPID, PIDController& velocityPID,  
                            double targetPosition, double currentPosition, double currentVelocity, double dt) {  
    // 位置环PID  
    double desiredVelocity = positionPID.update(targetPosition, currentPosition);  
  
    // 速度环PID  
    double controlOutput = velocityPID.update(desiredVelocity, currentVelocity);  
  
    // 应用控制输出到系统(这里只是一个示例,实际情况可能更复杂)  
    // ...  
  
    return controlOutput;  
}  
  
int main() {  
    // 初始化PID参数  
    double kp_position = 1.0, ki_position = 0.1, kd_position = 0.01;  
    double kp_velocity = 0.5, ki_velocity = 0.05, kd_velocity = 0.005;  
  
    // 创建PID控制器对象  
    PIDController positionPID(kp_position, ki_position, kd_position);  
    PIDController velocityPID(kp_velocity, ki_velocity, kd_velocity);  
  
    // 设置时间间隔(例如,每秒更新一次)  
    double dt = 1.0 / 1000.0; // 假设以毫秒为单位,所以这里是0.001秒  
    positionPID.setDt(dt);  
    velocityPID.setDt(dt);  
  
    // 假设的目标位置、当前位置和速度(这些值应该来自你的系统)  
    double targetPosition = 100.0;  
    double currentPosition = 0.0;  
    double currentVelocity = 0.0;  
  
    // 模拟控制循环  
    while (true) {  
        // 双环PID控制  
        double controlOutput = doubleLoopPIDControl(positionPID, velocityPID, targetPosition, currentPosition, currentVelocity, dt);  
  
        // 更新位置和速度(这些值应该来自你的系统或者基于controlOutput计算)  
        // 这里只是模拟更新  
        currentPosition += currentVelocity * dt;  
        // 假设速度由controlOutput直接控制(实际情况可能更复杂)  
        currentVelocity = controlOutput; // 注意:这里只是一个简化的示例  
  
        // 输出控制结果(可选)  
        std::cout << "Control Output: " << controlOutput << std::endl;  
  
        // 等待一段时间  
        std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(dt * 1000)));  
  
        // 退出条件(根据实际需求添加)  
        // if (/* some condition */) break;  
    }  
  
    return 0;  
}

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值