การควบคุม PID: การเพิ่มการหน่วงเวลาก่อนการวนรอบถัดไปเป็นความคิดที่ดีหรือไม่?
ฉันใช้การควบคุม PID ใน c ++ เพื่อทำให้หุ่นยนต์ขับเคลื่อนส่วนต่างเปลี่ยนจำนวนองศาที่แม่นยำ แต่ฉันมีปัญหามากมาย
การออกจากลูปควบคุมก่อนกำหนดเนื่องจากรันไทม์ลูปเร็ว
หากหุ่นยนต์วัดความผิดพลาดได้น้อยกว่า. 5 องศาหุ่นยนต์จะออกจากลูปควบคุมและถือว่าการเลี้ยว "เสร็จสิ้น" (.5 เป็นค่าสุ่มที่ฉันอาจเปลี่ยนแปลงได้ในบางจุด) ดูเหมือนว่าลูปควบคุมกำลังทำงานอย่างรวดเร็วจนหุ่นยนต์สามารถหมุนด้วยความเร็วสูงมากเลี้ยวเลยจุดที่ตั้งไว้และออกจากลูป / ตัดมอเตอร์เพราะมันอยู่ที่ setpoint ชั่วขณะสั้น ๆ ฉันรู้ว่านี่คือจุดประสงค์ทั้งหมดของการควบคุม PID เพื่อให้ไปถึงจุดที่กำหนดได้อย่างแม่นยำโดยไม่ต้องถ่ายภาพมากเกินไป แต่ปัญหานี้ทำให้การปรับค่าคงที่ของ PID เป็นเรื่องยากมาก ตัวอย่างเช่นฉันพยายามหาค่า kp เพื่อให้มีการสั่นคงที่ แต่ไม่เคยมีการสั่นเพราะหุ่นยนต์คิดว่ามัน "เสร็จสิ้น" เมื่อมันผ่าน setpoint ไปแล้ว เพื่อแก้ไขปัญหานี้ฉันได้ติดตั้งระบบที่หุ่นยนต์ต้องอยู่ที่ setpoint เป็นระยะเวลาหนึ่งก่อนที่จะออกและสิ่งนี้ได้ผลทำให้การสั่นเกิดขึ้นได้ แต่ปัญหาของการออกจากลูปก่อนกำหนดดูเหมือนจะเป็นปัญหาที่ผิดปกติและวิธีแก้ปัญหาของฉัน อาจไม่ถูกต้อง
ระยะ D ไม่มีผลเนื่องจากรันไทม์ที่รวดเร็ว
เมื่อฉันมีหุ่นยนต์สั่นในลักษณะควบคุมโดยใช้ P เพียงอย่างเดียวฉันพยายามเพิ่ม D เพื่อป้องกันการยิงเกิน อย่างไรก็ตามสิ่งนี้ไม่มีผลในช่วงเวลาส่วนใหญ่เนื่องจากลูปควบคุมทำงานเร็วมากจน 19 ลูปจาก 20 ลูปอัตราการเปลี่ยนแปลงของข้อผิดพลาดคือ 0: หุ่นยนต์ไม่เคลื่อนที่หรือไม่เคลื่อนที่เพียงพอสำหรับมัน ที่จะวัดในช่วงเวลานั้น ฉันพิมพ์การเปลี่ยนแปลงข้อผิดพลาดและคำอนุพันธ์แต่ละลูปเพื่อยืนยันสิ่งนี้และฉันเห็นว่าทั้งคู่จะเป็น 0 สำหรับรอบ 20 รอบก่อนที่จะหาค่าที่เหมาะสมจากนั้นกลับไปที่ 0 อีก 20 รอบ อย่างที่ฉันพูดไปฉันคิดว่านี่เป็นเพราะวงจรการวนซ้ำเร็วมากจนหุ่นยนต์ไม่ได้เคลื่อนไหวเพียงพอสำหรับการเปลี่ยนแปลงที่เห็นได้ชัดเจนในข้อผิดพลาดใด ๆนี่เป็นปัญหาใหญ่เพราะมันหมายความว่าคำศัพท์ D ไม่มีผลต่อการเคลื่อนที่ของหุ่นยนต์เป็นหลักเพราะมันเกือบตลอดเวลาเพื่อแก้ไขปัญหานี้ฉันลองใช้ค่าสุดท้ายที่ไม่ใช่ศูนย์ของอนุพันธ์แทนค่า 0 ใด ๆ แต่สิ่งนี้ไม่ได้ผลและหุ่นยนต์จะแกว่งแบบสุ่มหากอนุพันธ์สุดท้ายไม่ได้แสดงถึงอัตราการเปลี่ยนแปลงของข้อผิดพลาดในปัจจุบัน
หมายเหตุ: ฉันยังใช้ feedforward ขนาดเล็กสำหรับค่าสัมประสิทธิ์แรงเสียดทานสถิตและเรียกสิ่งนี้ว่า "f"
ฉันควรเพิ่มความล่าช้าหรือไม่?
ฉันตระหนักว่าฉันคิดว่าต้นตอของปัญหาทั้งสองนี้คือลูปที่ทำงานเร็วมากดังนั้นสิ่งที่ฉันคิดไว้คือการเพิ่มคำสั่ง wait ที่ส่วนท้ายของลูป อย่างไรก็ตามดูเหมือนวิธีแก้ปัญหาที่ไม่ดีโดยรวมในการชะลอการวนซ้ำโดยเจตนา นี่เป็นความคิดที่ดีหรือไม่?
turnHeading(double finalAngle, double kp, double ki, double kd, double f){
std::clock_t timer;
timer = std::clock();
double pastTime = 0;
double currentTime = ((std::clock() - timer) / (double)CLOCKS_PER_SEC);
const double initialHeading = getHeading();
finalAngle = angleWrapDeg(finalAngle);
const double initialAngleDiff = initialHeading - finalAngle;
double error = angleDiff(getHeading(), finalAngle);
double pastError = error;
double firstTimeAtSetpoint = 0;
double timeAtSetPoint = 0;
bool atSetpoint = false;
double integral = 0;
double derivative = 0;
double lastNonZeroD = 0;
while (timeAtSetPoint < .05)
{
updatePos(encoderL.read(), encoderR.read());
error = angleDiff(getHeading(), finalAngle);
currentTime = ((std::clock() - timer) / (double)CLOCKS_PER_SEC);
double dt = currentTime - pastTime;
double proportional = error / fabs(initialAngleDiff);
integral += dt * ((error + pastError) / 2.0);
double derivative = (error - pastError) / dt;
//FAILED METHOD OF USING LAST NON-0 VALUE OF DERIVATIVE
// if(epsilonEquals(derivative, 0))
// {
// derivative = lastNonZeroD;
// }
// else
// {
// lastNonZeroD = derivative;
// }
double power = kp * proportional + ki * integral + kd * derivative;
if (power > 0)
{
setMotorPowers(-power - f, power + f);
}
else
{
setMotorPowers(-power + f, power - f);
}
if (fabs(error) < 2)
{
if (!atSetpoint)
{
atSetpoint = true;
firstTimeAtSetpoint = currentTime;
}
else //at setpoint
{
timeAtSetPoint = currentTime - firstTimeAtSetpoint;
}
}
else //no longer at setpoint
{
atSetpoint = false;
timeAtSetPoint = 0;
}
pastTime = currentTime;
pastError = error;
}
setMotorPowers(0, 0);
}
turnHeading(90, .37, 0, .00004, .12);
คำตอบ
อย่าปลดคอนโทรลเลอร์ของคุณ
จุดประสงค์ของคอนโทรลเลอร์ไม่เพียง แต่เพื่อควบคุมระบบของคุณไปยังจุดที่ต้องการตามการตอบสนองแบบไดนามิกที่กำหนดไว้ล่วงหน้า แต่ยังเพื่อต่อต้านปัจจัยภายนอกที่อาจเป็นอุปสรรคซึ่งอาจเป็นอุปสรรคต่องานนี้ ลองนึกถึงสิ่งรบกวนที่จะขับเคลื่อนระบบให้ไกลจากจุดที่ตั้งไว้เมื่อถึงจุดนั้นแล้ว ดังนั้นคอนโทรลเลอร์จะต้องใช้งานได้ตลอดเวลา (เว้นแต่คุณจำเป็นต้องเปลี่ยนงานเองและด้วยเหตุนี้จึงต้องเปลี่ยนคอนโทรลเลอร์ด้วย)
ด้วยเหตุนี้คุณจะต้องเพิ่มส่วนที่สำคัญอย่างแน่นอนซึ่งมีหน้าที่รับผิดชอบในการบรรลุข้อผิดพลาดคงตัวที่เป็นโมฆะต่อหน้าปริมาณที่ไม่ได้จำลองและสิ่งรบกวนภายนอก
นี่เป็นแหล่งข้อมูลที่เกี่ยวข้อง: https://robotics.stackexchange.com/a/19198/6941.
เว้นอนุพันธ์ไว้
95% ของตัวควบคุม PID ในอุตสาหกรรมเป็นตัวควบคุม PI (ดู "ระบบป้อนกลับ" Astrom, Murray) เนื่องจากส่วน D สามารถมีบทบาทสำคัญเฉพาะกับกระบวนการที่ช้าเท่านั้น (เช่นผู้ที่เกี่ยวข้องกับการควบคุมอุณหภูมิและระดับถัง) นี่ไม่ใช่กรณีของคุณแน่นอน แหล่งข้อมูลที่เกี่ยวข้องเกี่ยวกับความยากลำบากของเงื่อนไขอนุพันธ์ ได้แก่ :
- https://robotics.stackexchange.com/a/21556/6941.
- https://robotics.stackexchange.com/a/21555/6941.
เมื่อฉันมีหุ่นยนต์แกว่งในลักษณะควบคุมโดยใช้ P เพียงอย่างเดียวฉันพยายามเพิ่ม D เพื่อป้องกันการยิงเกิน
ดูเหมือนว่าคุณกำลังปฏิบัติตามใบสั่งยาของ Ziegler-Nichols เพื่อปรับแต่งคอนโทรลเลอร์ของคุณ มีตารางที่คุณต้องยึดติดเพื่อให้คุณได้ประมาณการกำไร อย่างไรก็ตามสิ่งเหล่านี้เป็นแบบฮิวริสติกและมีแนวโน้มว่าจะไม่ได้ผลในกรณีของคุณ
เพียงแค่วางส่วน D และโฟกัสที่ตัวควบคุม PI นอกจากนี้ยังมีตัวแปร ZN อีกตัวหนึ่งที่ไม่ได้อาศัยการสั่นที่สร้างขึ้นโดยเจตนา:https://robotics.stackexchange.com/a/21616/6941.
ไม่เคยเพิ่มความล่าช้าให้กับระบบ
ความล่าช้าเป็นตัวร้ายที่ต้องรับมือในวงควบคุมและวิศวกรสัตว์ร้ายที่เลวร้ายที่สุดต้องต่อสู้ ( ดูนี้🎥 ) เนื่องจากพวกเขาลดระยะขอบเฟสลงอย่างมากซึ่งผลักดันให้ระบบโดยรวมไปสู่ความไม่เสถียร
หากคุณเห็นว่าการวนซ้ำของคุณเร็วเกินไปให้ใช้การสร้างอินพุตกับจุดที่ตั้งไว้ (เช่นวิถีการกระตุกขั้นต่ำ ) เพื่อให้ขั้นตอนที่คมชัดเริ่มขึ้น ระบบวงปิดจะตอบสนองอย่างสง่างามมากขึ้น ความเป็นไปได้อีกประการหนึ่งคือค่า P gain ของคุณสูงเกินไป: เพียงแค่ปรับตัวควบคุมจากนั้น
ในแง่นี้ถ้าคุณใส่อินทิกรัลเทอม I คุณจะต้องให้เหตุผลเกี่ยวกับเวลาตัวอย่าง $T_s$ เช่นกัน.
การกำหนดอัตราตัวอย่างคงที่สำหรับคอนโทรลเลอร์ของคุณจะดีกว่ามาก หลักการง่ายๆก็คือไม่ว่าเวลาในการตกตะกอนใดก็ตามที่คุณต้องการออกจากลูปเมื่อมันทำงานในระบบเชิงเส้นช่วงการสุ่มตัวอย่างของคุณควรอยู่ระหว่าง 10 เท่าถึง 100 เท่าน้อยกว่าเวลาในการตกตะกอน อีกวิธีหนึ่งคืออัตราการสุ่มตัวอย่างควรเร็วกว่าแบนด์วิดท์ลูปที่ต้องการ 10 ถึง 100 เท่า
เป็นโบนัสเพิ่มเติมเล็กน้อยหมายความว่าคุณสามารถคำนวณ dt นอกลูปได้
ตามความต้องการอัตราการสุ่มตัวอย่างควรกำหนดโดยฮาร์ดแวร์เช่นโดยตัวจับเวลาของฮาร์ดแวร์และฮาร์ดแวร์ควรสุ่มตัวอย่างตำแหน่งที่ดีกว่าโดยเรียกใช้จากตัวจับเวลา สิ่งนี้ช่วยลดข้อ จำกัด แบบเรียลไทม์ของซอฟต์แวร์ได้อย่างมาก
หากคุณใช้อัตราตัวอย่างที่เหมาะสมและส่วนใหญ่คุณไม่ได้ลงทะเบียนการเปลี่ยนแปลงในโปรแกรมเปลี่ยนไฟล์แสดงว่าตัวเข้ารหัสของคุณมีขั้นตอนไม่เพียงพอ
ฉันจะไม่เห็นด้วยกับ @Ugo_Pattachini หากลูปเกี่ยวข้องกับมอเตอร์และตัวควบคุมของคุณสะอาดเพียงพอการกระทำที่แตกต่างบางอย่างอาจเป็นประโยชน์ แต่มีโอกาสที่ดีที่จะต้องมีการ จำกัด แบนด์ (กล่าวคือคุณต้องมีตัวควบคุม lead-lag) และหากคุณกำลังทำการปรับ PID แบบนั่งกางเกงมีโอกาสดีที่คุณไม่มีเครื่องมือ ตั้งค่าวงดนตรีให้ถูกต้อง
อย่างไรก็ตามหากคุณไม่สามารถบังคับใช้เวลาที่เข้มงวดมากในการสุ่มตัวอย่างตัวเข้ารหัสอย่าพยายามใช้การควบคุมอนุพันธ์ เวลาในการสุ่มตัวอย่างที่ไม่สม่ำเสมอบวกกับความเร็วของมอเตอร์ของคุณจะทำให้เกิดเสียงดังมากขึ้นและตัวควบคุมอนุพันธ์มักจะขยายสัญญาณรบกวน หากคุณไม่สามารถจัดเตรียมสัญญาณที่สะอาดเพื่อควบคุมได้การควบคุมอนุพันธ์จะไม่เหมาะสม