วิธีที่ถูกต้องในการใช้ Subsumption Architecture กับ Robot C


11

เมื่อเร็ว ๆ นี้ฉันได้อ่านเกี่ยวกับสถาปัตยกรรม Subsumptionเป็นจำนวนมากและมีหลายวิธีที่ผู้คนจะสนับสนุน

เช่นบางคนใช้ตัวแปร "flag" ทั่วโลกเพื่อให้งานควบคุม คนอื่นใช้endTimeSlice()และอนุญาตให้ผู้ตัดสินเลือกจริงๆ และฉันคิดว่านี่ถูกต้อง

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

task evade(){
    if(SensorValue(forwardSonarSensor) > threshold){
            //box the obstruction
    }
}

task find(){
    if(SensorValue(lightSensor) > threshold){
            //spiral the robot
    }
}

task track(){

    if(SensorValue(lightSensor) < threshold){
            //go straight
    }else{
                //execute turns to follow the line
    }
}

task main(){
    while(true){
        StartTask(evade,9);
        StartTask(track,8);
        StartTask(find,7);
        wait1Msec(250);
    }
}

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


1
ตัวเลขที่คุณให้ในStartTaskนั้นเป็นลำดับความสำคัญของงานหรือไม่ 9 จะเป็นลำดับความสำคัญสูงสุดหรือไม่ ในกรณีนั้นไม่ควรfindมีลำดับความสำคัญมากกว่าtrackนี้ ในความเป็นจริงสภาพfindและelseสภาพของtrackเหมือนกัน ในฐานะมนุษย์ถ้าค่าเซ็นเซอร์สูงกว่าขีด จำกัด คุณจะทำอย่างไร หมุนวนหรือหมุนเพื่อปรับแต่งเส้น?
Shahbaz

ฉันรู้ว่าสถาปัตยกรรมการจัดสรรคืออะไรและฉันมั่นใจว่าหุ่นยนต์ของคุณควรมีโมดูลฮาร์ดแวร์ที่แตกต่างกันซึ่งรับผิดชอบงานการคำนวณระดับต่ำ และรหัสนั้นควรดูดซับสัญญาณมากกว่าการฟังสถานะที่มีเงื่อนไข ดังนั้นคุณไม่ควรส่งสัญญาณไปยังฮาร์ดแวร์อีกชิ้น ตอนนี้ปัญหาของฉันคือฉันมี Arduinos สองตัวและฉันต้องการให้ Arduino A ย่อยหรือยับยั้งสัญญาณจาก Arduino B ไม่มีใครมีความคิดใด ๆ ว่าจะทำอย่างไร? ในขณะที่ฉันสามารถใช้สาย A ในการส่งสัญญาณไปยัง Arduino B แต่ฉันไม่แน่ใจว่าจะเพิ่มหรือยับยั้ง sig ได้อย่างไร
Ambient Soda

คำตอบ:


7

ด้วยสถาปัตยกรรม Subsumption คุณควรออกแบบพฤติกรรมของคุณในลักษณะที่ว่าถ้าคุณงานกำหนดTลำดับความสำคัญnแล้วTควรจะเป็นสิ่งที่หุ่นยนต์ควรทำอย่างไรถ้างานทั้งหมดที่มีความสำคัญสูงกว่าnจะถูกละเลย

ลองสั่งตัวอย่างงานของคุณแล้วหาวิธีนำไปใช้ งานของคุณมีevade, และfindtrack

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

  • ลำดับความสำคัญสูงสุด: evade
  • แล้ว: find
  • แล้ว: track

เหตุผลfindมีลำดับความสำคัญสูงกว่าtrackที่เป็นตามที่ฉันกล่าวข้างต้นคุณจะtrackถ้าevadeและfindไม่จำเป็นเท่านั้น หากคุณใส่findด้านล่างtrackนั่นหมายความว่าคุณเริ่มติดตามหากไม่มีสิ่งกีดขวางแม้ว่าคุณจะไม่ได้อยู่ในสาย

ตอนนี้เรามาดูการใช้งานของคุณ:

task find(){
    if(SensorValue(lightSensor) > threshold){
            //spiral the robot
    }
}

task track(){

    if(SensorValue(lightSensor) < threshold){
            //go straight
    }else{
                //execute turns to follow the line
    }
}

โปรดจำไว้ว่าเราให้findความสำคัญสูงกว่า ดังนั้นหากหุ่นยนต์ไม่สามารถรับรู้ได้หุ่นยนต์lightSensorจะหมุนวนเพื่อพยายามหาเส้น เมื่อมันtrackเริ่มเข้ามาคุณก็จะเห็นได้ว่าelseสภาพtrackไม่เคยเกิดขึ้น

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


แม้ว่าฉันจะตอบคำถามของคุณแล้ว แต่นี่เป็นการปรับปรุงการติดตามสายของคุณอย่างง่าย ๆ :

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

findงานของคุณคล้ายกัน:

task find(){
    if (SensorValue(ls_left) > threshold
        && Sensorvalue(ls_right) > threshold){
            //spiral the robot
    }
}

นั่นคือคุณจะเป็นเกลียวถ้าคุณไม่รู้สึกอะไรเลย

trackตอนนี้งานของคุณมีประสิทธิภาพมากขึ้น:

task track(){

    if (SensorValue(ls_left) < threshold
        && SensorValue(ls_right) < threshold){
            //go straight
    } else if (SensorValue(ls_left) < threshold
        && SensorValue(ls_right) > threshold){
            //turn left
    } else if (SensorValue(ls_left) > threshold
        && SensorValue(ls_right) < threshold){
            //turn right
    } else {
            // shouldn't happen, but go on spiral anyway
    }
}

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


4

คำตอบสั้น ๆ ไม่จริงคุณต้องทำสิ่งต่าง ๆ ค่อนข้างแตกต่างกันเล็กน้อย

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

// global variables
int distance;
int light;

main() {
   while (true) {
   distance = read_distance;
   light = read_light;
   if (task1_wantsToRun())
     task1_run();
   if (task2_wantsToRun())
     task2_run();   
   }
}

มีสองสิ่งที่นี่ ลำดับความสำคัญจะไม่เกี่ยวข้อง เป็นเรื่องดีที่ดูเหมือนว่าจะมีงานใน robotC พร้อมลำดับความสำคัญพวกเขาไม่ใช่ทางเลือกที่ดีสำหรับการใช้งาน subsumption ในประสบการณ์ของฉัน สำหรับเหตุผลเช่นลำดับความสำคัญไม่ได้รับเกียรติเสมอไปงานไม่สามารถถูกขัดจังหวะ (บางครั้ง) ดังนั้นเมื่อเกิดเหตุการณ์ที่มีลำดับความสำคัญสูงกว่ามันจะไม่ตอบสนองตามที่คุณคาดหวังไว้ RobotC เพิ่งจะเข้าใหม่เมื่อไม่นานมานี้ จากงานมากกว่า 1 งานอาจมีความเสี่ยง (ปัญหาเรื่องเวลาของ I2C) และในบางกรณีมันไม่ใช่ (เซ็นเซอร์แบบสำรวจโดยอัตโนมัติ)

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

ความคิดเห็นของคุณ "// กล่องสิ่งกีดขวาง" อธิบายพฤติกรรมขีปนาวุธ สิ่งเหล่านี้เป็นเรื่องยุ่งยากเล็กน้อยที่จะนำมาใช้โดยใช้การทำงานแบบมัลติทาสกิ้ง การวนรอบที่เรียบง่ายที่ฉันใช้ทำให้ง่ายขึ้นมากและดีกว่าสำหรับการเริ่ม / การเรียนรู้

อีกสิ่งหนึ่งที่ฉันจะทิ้งไว้ให้คุณคือการสมัครสมาชิกในขณะที่เรียบร้อยและเหมาะสมกับสิ่งต่าง ๆ มากมายไม่ใช่วิธีที่ดีที่จะใช้สิ่งที่ทำได้ดีกว่าแบบดั้งเดิม แน่นอนส่วน 'หลีกเลี่ยง' อาจเป็นผู้สมัครที่ดีสำหรับการสมัครเข้าทำงาน แต่งานอื่น ๆ ของคุณควรถูกเรียกว่า 'GoOnAboutYourBusiness' ฉันพูดแบบนี้เพราะคุณอาจไม่ต้องการเปลี่ยนจากการค้นหาเป็นการติดตามด้วยการบอกรับสมาชิก จัดการกับผู้ที่มีลูปการเขียนโปรแกรมแบบดั้งเดิม ด้วยเซ็นเซอร์เดียว - แสงมีความรู้สึกเข้มหรือเบากว่าลูปสุดท้ายหรือไม่? ถ้ามันเข้มขึ้น (สมมติว่าเส้นสีดำ) เปลี่ยนทิศทางไปเรื่อย ๆ ถ้ามันเบาลงให้เลี้ยวไปทางอื่นถ้ามันยังคงอยู่เหมือนเดิมให้ตรงไป คุณอาจต้องเพิ่ม PID และใช้โค้งพวงมาลัยแทนการเลี้ยวซ้ายและขวาเพื่อให้นุ่มนวลขึ้น

และใช่เซ็นเซอร์หลายตัวช่วย http://www.mindsensors.com/ - ใช่นั่นคือฉันในภาพยนตร์ปัจจุบัน (11/10/2012)

อัปเดต: รหัสจริง

ฉันจะลองใช้เวลาซักครู่ แต่มันจะรวบรวมและอธิบายสิ่งที่ฉันเขียนไว้ด้านบน:

#pragma config(Sensor, S1,     S_LIGHT,        sensorLightActive)
#pragma config(Sensor, S2,     S_DISTANCE,     sensorSONAR)
#pragma config(Motor,  motorB,          LEFT,          tmotorNXT, PIDControl, encoder)
#pragma config(Motor,  motorC,          RIGHT,         tmotorNXT, PIDControl, encoder)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

int distance_value, light_value;

bool evade_wantsToRun()
{
    return distance_value < 30;
}

void evade_task()
{
    // full stop
    motor[LEFT] = 0;        
    // evade the object ballistically (ie in full control)  
    // turn left, drive
    nSyncedTurnRatio = 0;
    motor[LEFT] = -20;
    Sleep(500);
    nSyncedTurnRatio = 100;
    Sleep(1000);
    // turn right, drive
    nSyncedTurnRatio = 0;
    motor[LEFT] = 20;
    Sleep(500);
    nSyncedTurnRatio = 100;
    Sleep(1000);
    // turn right, drive
    nSyncedTurnRatio = 0;
    motor[LEFT] = 20;
    Sleep(500);
    nSyncedTurnRatio = 100;
    Sleep(1000);
    // turn left, resume
    nSyncedTurnRatio = 0;
    motor[LEFT] = 20;
    Sleep(500);
    motor[LEFT] = 0;
}

///////////////////////////////

void TurnBySteer(int d)
{
    // normalize -100 100 to 0 200
    nSyncedTurnRatio = d + 100; 
}
///////////////////////////////

typedef enum programPhase { starting, searching, following, finished };
programPhase phase = starting;

// these 'tasks' are called from a loop, thus do not need to loop themselves

void initialize()
{
    nSyncedTurnRatio = 50;
    nSyncedMotors = synchBC;
    motor[LEFT] = 30;       // start a spiral drive
    phase = searching;
}

void search()
{
    if (light_value < 24)
    {
        nSyncedTurnRatio = 100;
        phase = following;
    }
}

int lastLight = -1;
int currentSteer = 0;
void follow()
{
    // if it is solid white we have lost the line and must stop
    // if lightSensors detects dark, we are on line
    // if it got lighter, we are going more off line
    // if it got darker we are headed in a good direction, slow down turn in anticipation
    // +++PID will be even smoother
    if (light_value > 64)
    {
        motor[LEFT] = 0;
        phase = finished;
        return;
    }
    if (light_value < 24)
        currentSteer = 0;
    else if (light_value > lastLight)
        currentSteer += sgn(currentSteer) * 1;
    else    // implied (light_value < lastLight)
        currentSteer -= sgn(currentSteer) * 1;      

    TurnBySteer(currentSteer);
}

bool regularProcessing_wantsToRun()
{
    return phase != finished;
}

void regularProcessing_task()
{
    switch (phase)
    {
    case starting:
        initialize();
        break;
    case searching:
        search();
        break;
    case following:
        follow();
    }
}

task main()
{
    // subsumption tasks in priority oder
    while (true)
    {
        // read sensors once per loop
        distance_value = SensorValue[S_DISTANCE];
        light_value = SensorValue[S_LIGHT];
        if (evade_wantsToRun())
            evade_task();
        if (regularProcessing_wantsToRun())
            regularProcessing_task();
        else
            StopAllTasks();
        EndTimeSlice();     // give others a chance, but make it as short as possible
    }
}

ฉันยอมรับว่าปัญหานี้แก้ไขได้ง่ายขึ้นด้วยการวนซ้ำแบบง่าย ฉันไม่เข้าใจว่าเพราะเหตุใดจึงมีคนลงคะแนน
Shahbaz

ฉันไม่ต้องการทิ้งการแสดงผลที่ง่ายต่อการแก้ไขด้วยการวนรอบแบบง่าย ๆ แต่เป็นการแสดงผลที่เป็นการใช้ subsumption ที่ถูกต้องเพื่อใช้การวนรอบแบบง่ายเป็นหนึ่งในงาน ใครก็ตามที่ถูกลดระดับมันมีคะแนน mod และไม่มีความเข้าใจในการ subsumption คุณจะไม่พบว่ามีคนจำนวนไม่มากที่ทำ subsumption บน LEGO NXT (โดยนัยโดยใช้ robotC) ดังนั้นอย่าคาดหวังว่าโค้ดจะพร้อมวางให้พร้อม
Spiked3

ใช่ฉันสงสัยว่าทำไม OP ถึงใช้งานเพื่ออะไรง่ายๆ
Rocketmagnet

เพราะมันเป็นความผิดพลาดเริ่มต้นที่พบได้บ่อยมากกับ robotC - เพื่อลองใช้งานสำหรับทุกสิ่ง ฉันหวังว่าพวกเขาจะย้ายไปยังพื้นที่ขั้นสูงเท่านั้น
Spiked3
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.