C 电机PI调节器结构代码

C 电机PI调节器结构代码,c,embedded,nucleo,pid-controller,C,Embedded,Nucleo,Pid Controller,我实际上在做一个基于freeRTOS的机器人项目。我在控制机器人车轮速度的PI控制器方面遇到了一些问题。 #定义为100//100毫秒 #定义Te 5//5 ms #定义Kp 0.01 #将Ti 10//0.1*定义为 #定义Ki 0.05/10//Te/ti void corrNum(int-vitesse)//以速度为参数 { int eL,eR=0;左右错误 浮动cdeL=0; 浮点UpL=0; int-dutyL=0; 浮点数cdeR=0; 浮动UpR=0; int dutyR=0;

我实际上在做一个基于freeRTOS的机器人项目。我在控制机器人车轮速度的PI控制器方面遇到了一些问题。

#定义为100//100毫秒
#定义Te 5//5 ms
#定义Kp 0.01
#将Ti 10//0.1*定义为
#定义Ki 0.05/10//Te/ti
void corrNum(int-vitesse)//以速度为参数
{
int eL,eR=0;左右错误
浮动cdeL=0;
浮点UpL=0;
int-dutyL=0;
浮点数cdeR=0;
浮动UpR=0;
int dutyR=0;
浮点数UiL=0;
浮点数UiR=0;
如果(委托人)
{
tickL=quadEncoder_GetSpeedL();
tickR=quadEncoder_GetSpeedR();
eL=(int)(委托人-滴答声);
eR=(int)(收货人-滴答声);
UpL=Kp*eL;
UpR=Kp*eR;
UiL=UiL+Kp*Ki*eL;
UiR=UiR+Kp*Ki*eR;
UiL_prev=UiL;
UiR_prev=UiR;
cdeL=UpL+UiL;
cdeR=UpR+UiR;
dutyL=cdeL<100&&cdeL>-100?(int)cdeL+100:200;
dutyR=cdeR<100&&cdeR>-100?(int)cdeR+100:200;
电动左置占空比(dutyL);
机动车辆权利义务(dutyR);
HAL_延迟(5);//采样周期5ms
term_printf(“电机左:指令:%d速度:%d错误:%d责任:%d\n\r”,发货日期、勾号、eL、dutyL‘在此处输入代码’);
术语_printf(“电机右侧:指令:%d速度:%d错误:%d责任:%d\n\r”,收货人,滴答,呃,dutyR);;
tickL=0;
滴答=0;
}
其他的
{
电动左置(100);
驾驶权(100);
}
}`
问题是,当误差达到0.0而不是稳定时,开始振荡。

不清楚您在这个解决方案中是如何使用FreeRTOS的-片段中没有FreeRTOS调用,非RTOS
HAL_delay()
和时间关键型控制循环中的终端输出将没有帮助-您可以在5毫秒内只输出57个字符-您没有时间输出文本

您的错误信号计算不正确,编码器提供的是相对位置而不是速度;你必须根据位置随时间的变化来计算速度

您应该将一个任务专用于控制循环,并使用RTOS计时来确保高效和准确的调度。相对于其他任务,任务应以足够高的优先级运行,以确保无抖动计时

以下内容应视为伪代码;我不熟悉FreeRTOS API,因此操作系统调用不是真实的,我没有处理任务本身的实例化,也没有处理扩展和其他您没有提供足够信息的微妙问题-您应该从中获取建议的控制器结构-而不是实际的代码逐字:

typedef enum
{
  LEFT = 0,
  RIGHT = 1
} tMotorId

volatile static struct
{
  float integral ;
  int speed ;
  int previous_position ;
} motor_ctrl_data[2] = {{0,0},{0,0}} ;

void setSpeed( tMotorId id, int speed )
{
  motor_ctrl_data[id] = speed ;
}

void motor_ctrl_task()
{
  // Configure RTOS time for 5ms update period
  OS_TIMER timer = creatTimer( 5 ) ;
  startTimer( timer ) ;

  // Get initial encoder counts
  motor_ctrl_data[LEFT].previous_position = getEncoder(LEFT) ;
  motor_ctrl_data[RIGHT].previous_position = getEncoder(RIGHT) ;

  // PI control loop
  for(;;)
  {
    // Loop update timer wait
    waitTimer( timer ) ;

    // For each motor
    for( int m = 0; m < 2; m++ )
    {
      // Calculate speed
      int speed = getEncoder[m] - motor_ctrl_data[m].previous_position ;

      // Calculate speed error
      int error = motor_ctrl_data[m].speed - speed[m] ;

      // Calculate error integral
      motor_ctrl_data[m].integral += error[m] ;

      motorDuty( LEFT, Kp * error +  Ki * motor_ctrl_data[m].integral ) ;
    }
  }
}
typedef枚举
{
左=0,
右=1
}运动神经元
易失性静态结构
{
浮点积分;
整数速度;
int以前的位置;
}马达控制数据[2]={0,0},{0,0};
无效设置速度(t电机id,内部速度)
{
电机控制数据[id]=速度;
}
无效电机控制任务()
{
//为5ms更新周期配置RTOS时间
OS_定时器=创建定时器(5);
启动定时器;
//获取初始编码器计数
电机控制数据[左]。上一个位置=getEncoder(左);
电机控制数据[右]。上一个位置=getEncoder(右);
//PI控制回路
对于(;;)
{
//循环更新计时器等待
等待计时器(计时器);
//对于每个电机
对于(int m=0;m<2;m++)
{
//计算速度
int speed=getEncoder[m]-电机控制数据[m]。上一个位置;
//计算速度误差
int error=电机控制数据[m]。速度-速度[m];
//计算误差积分
电机控制数据[m]。积分+=错误[m];
motorDuty(左,Kp*错误+Ki*电机控制数据[m]。整数);
}
}
}
当然,这本身并不能解决振荡问题,但至少是一种控制器结构,能够在给定适当系数的情况下进行控制。调整回路设置Ki=0并增加Kp,直到电机尽可能快地移动,但无振荡。这不会使您达到目标速度,因为目标上的错误为零,因此仅Kp无法工作。然后开始增加Ki,直到达到目标速度。即使是很小的Ki,最终也会达到目标速度,但动态响应会很滞后。太多,你会得到过冲或振荡

根据电机的动态响应,您可能需要其他调整,如积分限制或死区补偿。您甚至可能受益于微分项,但对于简单的速度控制器来说,这通常是不必要的,而且通常很难调整

如果需要输出调试数据,请让循环将调试数据写入共享变量(例如,如果使用上述建议的结构,则在
motor\u ctrl\u data
中),并以终端输出可以支持的速率从低优先级任务异步打印它们


Tim Wescott的文章“”可能是一篇有用的文章。

详细说明您遇到的情况以及您所做的工作。这些神秘的变量名。。。即使你知道PI调节器是如何工作的,这也是很难理解的。什么类型是“嘀嗒”等?总的来说,您的代码的类型非常松散,混合了int和float,并且首先使用int而不是stdint.h类型。您似乎没有将整型部分保存到任何地方?如果在PI调节器调用之间不保存它,调节器将永远无法工作。您应该有类似于
UiL=UiL\u prev+eL
,假设错误为
eL
。必须调整PID回路。如果收益太高,它们就会振荡。当它们不能按可预测的时间间隔执行时,它们也会变得脆弱,这实际上改变了收益。请注意,HAL_Del
typedef enum
{
  LEFT = 0,
  RIGHT = 1
} tMotorId

volatile static struct
{
  float integral ;
  int speed ;
  int previous_position ;
} motor_ctrl_data[2] = {{0,0},{0,0}} ;

void setSpeed( tMotorId id, int speed )
{
  motor_ctrl_data[id] = speed ;
}

void motor_ctrl_task()
{
  // Configure RTOS time for 5ms update period
  OS_TIMER timer = creatTimer( 5 ) ;
  startTimer( timer ) ;

  // Get initial encoder counts
  motor_ctrl_data[LEFT].previous_position = getEncoder(LEFT) ;
  motor_ctrl_data[RIGHT].previous_position = getEncoder(RIGHT) ;

  // PI control loop
  for(;;)
  {
    // Loop update timer wait
    waitTimer( timer ) ;

    // For each motor
    for( int m = 0; m < 2; m++ )
    {
      // Calculate speed
      int speed = getEncoder[m] - motor_ctrl_data[m].previous_position ;

      // Calculate speed error
      int error = motor_ctrl_data[m].speed - speed[m] ;

      // Calculate error integral
      motor_ctrl_data[m].integral += error[m] ;

      motorDuty( LEFT, Kp * error +  Ki * motor_ctrl_data[m].integral ) ;
    }
  }
}