Cara yang benar untuk menggunakan Subsumption Architecture dengan Robot C

11

Saya telah melakukan banyak membaca akhir-akhir ini tentang Subsumption Architecture dan ada beberapa cara yang berbeda untuk mengadvokasi orang.

Misalnya beberapa orang menggunakan variabel "bendera" global untuk mengontrol tugas. Yang lain menggunakan endTimeSlice()dan memungkinkan arbiter untuk benar-benar memilih. Dan saya pikir ini benar.

Saya memiliki bagian kecil ini dari kode RobotC yang sedang saya kerjakan untuk robot yang mengikuti garis tetapi saya tidak yakin saya melakukannya dengan benar karena saat ini metode lintasan akan selalu mengambil alih metode pencarian. Aliran yang benar adalah bahwa find harus memandu robot ke garis menggunakan jalur spiral untuk menemukan garis. Setelah garis ditemukan trek harus mengambil alih.

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);
    }
}

Saya baru saja menggunakan beberapa komentar di sini daripada kode yang sebenarnya untuk membuatnya singkat. Apakah pernyataan if saya tidak cukup baik sebagai syarat karena ketika robot mati, track()mengambil alih. Apakah ini karena pernyataan lain dalam jalur? Jika demikian, bagaimana cara track()melakukan belokan ketika kehilangan garis tanpa mengambil alih dari hijauan pada awal program?

James MV
sumber
1
Angka-angka yang Anda berikan StartTask, apakah itu prioritas tugas? Apakah 9 akan menjadi prioritas tertinggi? Dalam hal itu, bukankah seharusnya findmemiliki prioritas lebih dari track? Padahal, kondisi finddan elsekondisinya tracksama. Jadi, sebagai manusia, jika nilai sensor lebih besar dari ambang, apa yang akan Anda lakukan? Terus spiral atau putar untuk menyesuaikan garis?
Shahbaz
Saya tahu apa itu arsitektur subsumption, dan saya yakin robot Anda harus memiliki modul perangkat keras yang berbeda yang bertanggung jawab atas tugas komputasi tingkat rendah. Dan bahwa kode sebenarnya harus menyerap sinyal daripada hanya mendengarkan keadaan kondisional. Jadi bukankah seharusnya Anda memberikan sinyal ke perangkat keras lain? Sekarang masalah saya adalah saya punya dua Arduino dan saya ingin Arduino A untuk merangkum atau menghambat sinyal dari Arduino B. Adakah yang tahu bagaimana hal ini dilakukan? Seperti yang saya dapat kawat Arduino A untuk mengirim sinyal ke Arduino B tapi saya tidak yakin bagaimana untuk berlangganan atau menghambat sig
Ambient Soda

Jawaban:

7

Dengan Subsumption Architecture, Anda harus merancang perilaku dengan hati-hati sedemikian rupa sehingga jika Anda menetapkan Tprioritas tugas n, maka Tseharusnya apa yang harus dilakukan robot jika semua tugas dengan prioritas lebih tinggi daripada ndiabaikan.

Mari kita memesan contoh tugas Anda, lalu mencari cara untuk mengimplementasikannya. Tugas Anda adalah evade, finddan track.

Secara umum Anda ingin robot melacak garis. Namun, jika tidak dapat mendeteksi garis, maka ia harus mencoba menemukannya. Di atas semua itu, ia harus menghindari rintangan. Ini memberi kami pemesanan berikut:

  • Prioritas utama: evade
  • Kemudian: find
  • Kemudian: track

Alasannya findmemiliki prioritas lebih tinggi daripada trackitu, seperti yang saya sebutkan di atas, Anda trackhanya akan jika evadedan findtidak perlu. Jika Anda letakkan di findbawah ini track, itu berarti Anda mulai melacak jika tidak ada halangan, bahkan jika Anda tidak terhubung.

Sekarang mari kita lihat implementasi Anda:

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

task track(){

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

Ingatlah bahwa kami memberikan findprioritas yang lebih tinggi. Oleh karena itu, jika robot tidak dapat merasakannya lightSensor, ia akan berputar mencoba menemukan garis. Setelah itu terjadi, tracktendangan masuk. Seperti yang Anda lihat, elsekondisi tracktidak pernah terjadi.

Sementara ini berhasil, robot akan bergerak sangat canggung. Sebenarnya tidak banyak yang bisa Anda lakukan tentang hal itu, mengingat bentuk robot Anda saat ini.


Meskipun saya sudah menjawab pertanyaan Anda, tetapi berikut ini adalah peningkatan sederhana untuk pelacakan garis Anda:

Alih-alih satu sensor cahaya, gunakan dua; ls_leftdan ls_right. Dengan menggunakan (setidaknya) dua sensor, Anda dapat memahami apakah Anda benar-benar keluar dari trek, atau akan keluar dari trek. Dalam kasus kedua, Anda dapat dengan mudah beralih ke arah yang tepat dan kembali ke jalurnya.

findTugas Anda serupa:

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

Yaitu, Anda melakukan spiral hanya jika Anda tidak merasakan apa-apa sama sekali

trackTugas Anda sekarang menjadi lebih efisien:

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
    }
}

Jelas, dengan matriks sensor cahaya, Anda dapat lebih baik menilai seberapa buruk Anda keluar dari jalur (yaitu dengan sudut apa) dan lebih baik memutuskan bagaimana untuk kembali ke jalur (yaitu dengan kecepatan sudut apa).

Shahbaz
sumber
4

Jawaban singkat; tidak, Anda benar-benar perlu melakukan sesuatu yang sedikit berbeda.

jawaban panjang yang tidak lengkap; Biarkan saya memberi Anda beberapa kode psuedo yang sesuai untuk robotC, yang menempatkan Anda di jalur yang lebih baik. Pertama, jangan gunakan tugas - ini BUKAN tugas robotC. Mereka dapat dibuat bekerja, mungkin, mungkin tidak (dan Anda perlu beberapa perubahan untuk mencoba).

// 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();   
   }
}

ada beberapa hal di sini; prioritas menjadi tidak relevan. Sebagus tampaknya memiliki tugas dalam robotC dengan prioritas, mereka bukan pilihan yang baik untuk implementasi subsumption dalam pengalaman saya. Untuk alasan seperti, prioritas tidak selalu dihormati, tugas tidak dapat terganggu (kadang-kadang) sehingga ketika acara prioritas yang lebih tinggi terjadi, itu tidak akan bereaksi seperti yang Anda harapkan, robotC hanya baru-baru ini menjadi peserta kembali, sehingga hal-hal seperti mengakses sensor dari lebih dari 1 tugas mungkin berisiko (masalah waktu I2C), dan dalam beberapa kasus tidak (sensor yang disurvei secara otomatis).

Anda dapat menambahkan implementasi prioritas Anda sendiri ke loop di atas saat Anda menyelesaikan pekerjaan, tetapi itu benar-benar tidak diperlukan untuk memulai.

Komentar Anda "// kotak penghalang" menggambarkan perilaku balistik. Itu agak sulit untuk diterapkan menggunakan multi-tasking. Loop sederhana yang saya gunakan membuatnya jauh lebih mudah, dan lebih baik untuk pemula / belajar.

Hal lain yang akan saya tinggalkan untuk Anda, adalah bahwa pelunasan sementara rapi dan sesuai untuk banyak hal, bukanlah cara yang baik untuk menerapkan apa yang lebih baik dilakukan secara tradisional. Memang bagian 'hindari' mungkin merupakan kandidat yang baik untuk disubsidi, tetapi sejujurnya tugas Anda yang lain harus disebut 'GoOnAboutYourBusiness'. Saya mengatakan ini karena Anda mungkin tidak ingin mengubah dari pencarian ke mengikuti dengan subsumption. Tangani mereka dengan loop pemrograman tradisional. Dengan sensor tunggal, - apakah cahaya yang dirasakan lebih gelap atau lebih terang dari pada putaran terakhir? jika semakin gelap (dengan asumsi garis hitam) terus berputar ke arah yang sama, jika semakin terang berbelok ke arah lain, jika tetap sama, lurus. Anda mungkin perlu menambahkan beberapa PID dan menggunakan kurva kemudi alih-alih hanya belok kiri dan kanan agar lebih halus.

Dan ya, banyak sensor membantu. http://www.mindsensors.com/ - yeah, itu saya dalam film saat ini (11/10/2012)

Perbarui: kode aktual

Saya akan mencoba ini sebentar lagi, tetapi ini mengkompilasi dan menggambarkan apa yang saya tulis di atas:

#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
    }
}
Spiked3
sumber
Saya setuju bahwa masalah ini lebih mudah diselesaikan dengan loop sederhana. Saya tidak mengerti mengapa ada orang yang menurunkan ini.
Shahbaz
Saya tidak ingin meninggalkan kesan bahwa itu lebih mudah untuk diselesaikan dengan loop sederhana, tetapi kesan bahwa itu adalah penggunaan subsumsi yang benar untuk menggunakan loop sederhana sebagai salah satu tugas. Siapa pun yang menurunkannya memiliki poin mod, dan tidak memiliki pemahaman tentang subsumption. Anda tidak akan menemukan bahwa tidak banyak orang yang melakukan subsumsi pada LEGO NXT (tersirat menggunakan robotC), jadi jangan berharap kode tersedia untuk disisipkan.
Spiked3
Ya, saya bertanya-tanya mengapa OP menggunakan tugas untuk sesuatu yang sederhana seperti subsumsi.
Rocketmagnet
Karena itu adalah kesalahan pemula yang sangat sangat sangat sangat sangat umum dengan robotC - untuk mencoba dan menggunakan tugas untuk semuanya. Saya berharap mereka akan memindahkannya ke area canggih saja.
Spiked3