最近在學習ROSArduinobridge 中的PID程式,
程式中設定了一個引數值TargetTicksPerFrame,其注釋意思為設定的速度目標值(以每個回圈周期的編碼器脈沖數來表達)。
double TargetTicksPerFrame; // target speed in ticks per frame
我的疑問是這個回圈周期到底是什么周期?
程式里的Error的計算是:
p->TargetTicksPerFrame - input;
其中input 是前后兩次回圈周期的編碼器變化值(這個周期應該是PID的計算周期),那么TargetTicksPerFrame的值也應該是同周期的目標值才有意義吧?所以,按照我的理解來講,TargetTicksPerFrame的值應該是把設定速度轉化為PID的計算周期1/30秒內的編碼器脈沖數(PID_RATE=30 //HZ)。
然而,當我用"m 20 20 "命令,讓電機設定速度為20脈沖/秒的時候,這個值被直接賦予了20的值,也就是周期是1秒。
請大神解答疑惑。
相關的代碼:
PID計算部分:
double TargetTicksPerFrame; // target speed in ticks per frame 每個Frame目標速度對應的TICKS值
long Encoder; // encoder count 編碼器計數
long PrevEnc; // last encoder count 上個編碼器計數
int PrevInput; // last input 上一個輸入
int PrevErr; // last error 測驗用
int ITerm; //integrated term
long output; // last motor setting 輸出
input = p->Encoder - p->PrevEnc;
Perror = p->TargetTicksPerFrame - input;
output = (Kp * Perror - Kd * (input - p->PrevInput) + p->ITerm) / Ko;
p->PrevEnc = p->Encoder;
output += p->output;
void updatePID() { //更新PDD函式,包括編碼器采集、PID執行以及設定電機PWM。實際我們調這個函式即可。
leftPID.Encoder = readEncoder(LEFT);
rightPID.Encoder = readEncoder(RIGHT);
if (!moving){
if (leftPID.PrevInput != 0 || rightPID.PrevInput != 0) resetPID();
return;
}
/* Compute PID update for each motor */
doPID(&rightPID);
doPID(&leftPID);
/* Set the motor speeds accordingly */
setMotorSpeeds(leftPID.output, rightPID.output);
速度設定部分的代碼:
case MOTOR_SPEEDS://這里設定速度,對應命令格式是m arg1 arg2
/* Reset the auto stop timer */
lastMotorCommand = millis();
if (arg1 == 0 && arg2 == 0) {
setMotorSpeeds(0, 0);
resetPID();
moving = 0;
}
else moving = 1;
leftPID.TargetTicksPerFrame = arg1;
rightPID.TargetTicksPerFrame = arg2;
Serial.println("OK");
break;
uj5u.com熱心網友回復:
控制器一般都是回圈驅動while(true)
{
dowork();
}
一個回圈從紅色開始,到藍色位置,里面包含的代碼執行完畢就是一個回圈周期
單片機、PLC等基本都是這樣的邏輯
uj5u.com熱心網友回復:
void loop() {
while (Serial.available() > 0) {
// Read the next character
chr = Serial.read();
// Terminate a command with a CR
if (chr == 13) {
if (arg == 1) argv1[index] = NULL;
else if (arg == 2) argv2[index] = NULL;
runCommand();
resetCommand();
}
// Use spaces to delimit parts of the command
else if (chr == ' ') {
// Step through the arguments
if (arg == 0) arg = 1;
else if (arg == 1) {
argv1[index] = NULL;
arg = 2;
index = 0;
}
continue;
}
else {
if (arg == 0) {
// The first arg is the single-letter command
cmd = chr;
}
else if (arg == 1) {
// Subsequent arguments can be more than one character
argv1[index] = chr;
index++;
}
else if (arg == 2) {
argv2[index] = chr;
index++;
}
}
}
// If we are using base control, run a PID calculation at the appropriate intervals
#ifdef USE_BASE
if (millis() > nextPID) {
updatePID();
nextPID += PID_INTERVAL;
}
// Check to see if we have exceeded the auto-stop interval
if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {;
setMotorSpeeds(0, 0);
moving = 0;
}
#endif
代碼上看,這個回圈周期是PID_INTERVAL。
那么在PID演算法的程式里邊,計算Error,用1秒的目標值減去1/30秒的實際值,這么算也可以的?
uj5u.com熱心網友回復:
當然不可以,計算速度你必須計算編碼器器差值除于計時時刻差值,這才是速度值
uj5u.com熱心網友回復:
這就是我疑惑的地方。但這是ROSArduinobridge的原始碼里邊就是這么寫的。
我看了很多CSDN里的各種博客,沒有一個人提到這個問題,所以我一直懷疑是自己的理解有問題。
附上全部的代碼地址:
https://blog.csdn.net/qq_29735067/article/details/81561261
uj5u.com熱心網友回復:
if (millis() > nextPID) {updatePID();
nextPID += PID_INTERVAL;
}
紅色陳述句把updatePID的呼叫周期固定了,計算周期T可以不參與計算,只要是一個固定值就行,因為/T 最后會整定到PID系數里
uj5u.com熱心網友回復:
你說的這個,我也想過。不過我還是有疑問:
PID的演算法的原理是根據一系列ERROR的值,算出一個輸出值,通過這個輸出值最終使得這個ERROR為零,這么理解沒錯吧?
那么既然目標是ERROR趨于零,那input = p->Encoder - p->PrevEnc=TargetTicksPerFrame,那最終穩定的速度應該是30倍的設定速度了。
uj5u.com熱心網友回復:
input = p->Encoder - p->PrevEnc這個不是ERROR值,只是速度的等效值
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/29109.html
標籤:智能硬件
下一篇:掛載不上nfs怎么辦
