การควบคุม PID: การเพิ่มการหน่วงเวลาก่อนการวนรอบถัดไปเป็นความคิดที่ดีหรือไม่?

Jan 11 2021

ฉันใช้การควบคุม 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);

คำตอบ

3 UgoPattacini Jan 12 2021 at 05:14

อย่าปลดคอนโทรลเลอร์ของคุณ

จุดประสงค์ของคอนโทรลเลอร์ไม่เพียง แต่เพื่อควบคุมระบบของคุณไปยังจุดที่ต้องการตามการตอบสนองแบบไดนามิกที่กำหนดไว้ล่วงหน้า แต่ยังเพื่อต่อต้านปัจจัยภายนอกที่อาจเป็นอุปสรรคซึ่งอาจเป็นอุปสรรคต่องานนี้ ลองนึกถึงสิ่งรบกวนที่จะขับเคลื่อนระบบให้ไกลจากจุดที่ตั้งไว้เมื่อถึงจุดนั้นแล้ว ดังนั้นคอนโทรลเลอร์จะต้องใช้งานได้ตลอดเวลา (เว้นแต่คุณจำเป็นต้องเปลี่ยนงานเองและด้วยเหตุนี้จึงต้องเปลี่ยนคอนโทรลเลอร์ด้วย)

ด้วยเหตุนี้คุณจะต้องเพิ่มส่วนที่สำคัญอย่างแน่นอนซึ่งมีหน้าที่รับผิดชอบในการบรรลุข้อผิดพลาดคงตัวที่เป็นโมฆะต่อหน้าปริมาณที่ไม่ได้จำลองและสิ่งรบกวนภายนอก

นี่เป็นแหล่งข้อมูลที่เกี่ยวข้อง: 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$ เช่นกัน.

1 TimWescott Jan 12 2021 at 08:36

การกำหนดอัตราตัวอย่างคงที่สำหรับคอนโทรลเลอร์ของคุณจะดีกว่ามาก หลักการง่ายๆก็คือไม่ว่าเวลาในการตกตะกอนใดก็ตามที่คุณต้องการออกจากลูปเมื่อมันทำงานในระบบเชิงเส้นช่วงการสุ่มตัวอย่างของคุณควรอยู่ระหว่าง 10 เท่าถึง 100 เท่าน้อยกว่าเวลาในการตกตะกอน อีกวิธีหนึ่งคืออัตราการสุ่มตัวอย่างควรเร็วกว่าแบนด์วิดท์ลูปที่ต้องการ 10 ถึง 100 เท่า

เป็นโบนัสเพิ่มเติมเล็กน้อยหมายความว่าคุณสามารถคำนวณ dt นอกลูปได้

ตามความต้องการอัตราการสุ่มตัวอย่างควรกำหนดโดยฮาร์ดแวร์เช่นโดยตัวจับเวลาของฮาร์ดแวร์และฮาร์ดแวร์ควรสุ่มตัวอย่างตำแหน่งที่ดีกว่าโดยเรียกใช้จากตัวจับเวลา สิ่งนี้ช่วยลดข้อ จำกัด แบบเรียลไทม์ของซอฟต์แวร์ได้อย่างมาก

หากคุณใช้อัตราตัวอย่างที่เหมาะสมและส่วนใหญ่คุณไม่ได้ลงทะเบียนการเปลี่ยนแปลงในโปรแกรมเปลี่ยนไฟล์แสดงว่าตัวเข้ารหัสของคุณมีขั้นตอนไม่เพียงพอ

ฉันจะไม่เห็นด้วยกับ @Ugo_Pattachini หากลูปเกี่ยวข้องกับมอเตอร์และตัวควบคุมของคุณสะอาดเพียงพอการกระทำที่แตกต่างบางอย่างอาจเป็นประโยชน์ แต่มีโอกาสที่ดีที่จะต้องมีการ จำกัด แบนด์ (กล่าวคือคุณต้องมีตัวควบคุม lead-lag) และหากคุณกำลังทำการปรับ PID แบบนั่งกางเกงมีโอกาสดีที่คุณไม่มีเครื่องมือ ตั้งค่าวงดนตรีให้ถูกต้อง

อย่างไรก็ตามหากคุณไม่สามารถบังคับใช้เวลาที่เข้มงวดมากในการสุ่มตัวอย่างตัวเข้ารหัสอย่าพยายามใช้การควบคุมอนุพันธ์ เวลาในการสุ่มตัวอย่างที่ไม่สม่ำเสมอบวกกับความเร็วของมอเตอร์ของคุณจะทำให้เกิดเสียงดังมากขึ้นและตัวควบคุมอนุพันธ์มักจะขยายสัญญาณรบกวน หากคุณไม่สามารถจัดเตรียมสัญญาณที่สะอาดเพื่อควบคุมได้การควบคุมอนุพันธ์จะไม่เหมาะสม