Tüketim Mimarisini Robot C ile kullanmanın doğru yolu


11

Son zamanlarda Tüketim Mimarisi hakkında çok fazla okuma yaptım ve insanların savundukları birkaç farklı yol var.

Örneğin, bazı insanlar görevin kontrol altına alınması için genel bir "bayrak" değişkeni kullanırlar. Diğerleri endTimeSlice()ise hakemin gerçekten seçim yapmasını sağlar. Ve bence bu doğru.

Ben robot takip eden bir çizgi için üzerinde çalışıyorum RobotC kodu bu küçük bölümü var ama şu anda parça yöntemi her zaman bulma yöntemini alacak gibi doğru yapıyorum emin değilim. Doğru akış, bulmanın, hattı bulmak için bir spiral yol kullanarak robotu hatta yönlendirmesi gerektiğidir. Hat bulunduğunda parkur devralmalıdır.

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

Kısa tutmak için gerçek kod yerine bazı yorumları kullandım. İf if ifadelerim koşullar olarak yeterince iyi değil mi, çünkü robot hattan çıktığında devreye giriyor track(). Bunun sebebi parkurdaki diğer ifade midir? Eğer öyleyse, track()program başlangıcında yemden vazgeçmeden hattı kaybettiğinde dönüşler nasıl yapılır ?


1
Verdiğiniz sayılar StartTask, görevin önceliği midir? 9 en yüksek öncelik olacak mı? Bu durumda, findönceliğinden daha fazla olmamalıdır track? Aslında, durumu findve elsedurumu trackaynıdır. Yani, bir insan olarak, sensör değeri eşikten büyükse, ne yapardınız? Spira devam edin veya hattı ayarlamak için dönün?
Shahbaz

Tüketim mimarisinin ne olduğunu biliyorum ve robotlarınızın düşük seviyeli hesaplama görevleri için sorumluluk alan farklı donanım modüllerine sahip olduğundan eminim. Ve kodun sadece koşullu bir durumu dinlemek yerine sinyali emmesi gerekir. Peki sinyali başka bir donanıma geçirmemelisiniz? Şimdi benim sorunum iki Arduino'um var ve Arduino A'nın Arduino B'den bir sinyal almasını veya engellemesini istiyorum. Bunun nasıl yapıldığına dair bir fikri olan var mı? Arduino A'yı Arduino B'ye sinyal göndermek için bağlayabildiğimden, ancak sig'ı nasıl üstleneceğini veya engelleyeceğini bilmiyorum
Ambient Soda

Yanıtlar:


7

Tüketim Mimarisi ile davranışlarınızı dikkatle , görev Tönceliği atarsanız , robotun daha yüksek önceliğe sahip tüm görevler göz ardı edildiğinde yapması gereken şekilde olması gerektiği şekilde tasarlamalısınız .nTn

Örnek görevlerinizi sipariş edelim, ardından uygulamayı gerçekleştirmenin bir yolunu bulalım. Sizin görevler evade, findve track.

Genel olarak robotun bir hattı izlemesini istersiniz. Ancak, hattı algılayamadıysa, bulmaya çalışmalıdır. Her şeyden önce, engellerden kaçınmalıdır. Bu bize aşağıdaki sıralamayı verir:

  • En yüksek öncelik: evade
  • Sonra: find
  • Sonra: track

Bunun nedeni find, trackyukarıda da belirttiğim gibi, trackyalnızca gereksiz evadeve findgereksizdir. findAşağıya koyarsanız track, bu, hatta olmasanız bile, herhangi bir engel yoksa izlemeye başladığınız anlamına gelir.

Şimdi uygulamanıza bakalım:

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

task track(){

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

Daha findyüksek bir öncelik verdiğimizi unutmayın . Bu nedenle, robot bunu algılayamazsa lightSensor, hattı bulmaya çalışırken sarmal olarak gidecektir. Bir kez, trackdevreye girer. Gördüğünüz gibi else, trackasla olmaz.

Bu çalışırken, robot çok garip bir şekilde hareket ederdi. Robotunuzun mevcut yapısı göz önüne alındığında, aslında bu konuda yapabileceğiniz çok şey yok.


Sorunuzu zaten yanıtlamış olmama rağmen, işte çizgi izlemeniz için basit bir iyileştirme:

Bir ışık sensörü yerine iki kullanın; ls_leftve ls_right. (En az) iki sensör kullanarak, tamamen pist dışında mı yoksa pist dışında mı çıkmak üzere olduğunuzu anlayabilirsiniz. İkinci durumda, kolayca doğru yöne dönebilir ve tekrar yola çıkabilirsiniz.

Göreviniz findbenzer:

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

Yani, sadece hiçbir şey hissetmiyorsanız sarmal içine girersiniz

Senin trackgörevin artık daha verimli hale gelir:

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

Açıkçası, bir ışık sensörü matrisiyle, pistten ne kadar kötü gittiğinizi (yani hangi açıyla) daha iyi değerlendirebilir ve piste nasıl geri döneceğinize (yani hangi açısal hızla) daha iyi karar verebilirsiniz.


4

kısa cevap; Hayır, gerçekten işleri biraz farklı yapmanız gerekiyor.

uzun eksik cevap; Size robotC için uygun bir psuedo kodu vereyim, bu da sizi daha iyi bir yola sokuyor. İlk olarak, görevleri kullanmayın - bu robotC görevlerinin ne olduğu DEĞİLDİR. Belki işe yarayabilirler, belki de olmayabilirler (ve denemek için birkaç değişikliğe ihtiyacınız var).

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

burada birkaç şey var; öncelik önemsiz hale gelir. RobotC'ta öncelikleri olan görevler varmış gibi görünse de, tecrübelerime göre birikim uygulaması için iyi bir seçim değiller. Öncelikler her zaman onurlandırılmaz, görevler kesilemez (bazen), bu nedenle daha yüksek öncelikli bir olay meydana geldiğinde, beklediğiniz gibi tepki vermez, robotC sadece son zamanlarda yeniden girildi, böylece bir sensöre erişmek gibi şeyler 1'den fazla görev riskli olabilir (I2C zamanlama sorunları) ve bazı durumlarda değildir (otomatik olarak yoklanan sensörler).

İşleri çalıştırırken yukarıdaki döngüye kendi öncelik uygulamanızı ekleyebilirsiniz, ancak başlangıçlar için gerçekten gerekli değildir.

"// tıkanıklığı engelle" yorumunuz balistik bir davranışı açıklar. Bunlar çoklu görev kullanarak uygulamak biraz zor. Kullandığım basit döngü, yeni başlayanlar / öğrenme için çok daha kolay ve daha iyi hale getiriyor.

Sizi bırakacağım bir diğer şey de, bir çok şey için temiz ve uygunken, toplamın geleneksel olarak daha iyi olanı uygulamak için iyi bir yol olmadığıdır. Gerçekten de 'kaçınma' kısmı toplam için iyi bir aday olabilir, ama dürüst olmak gerekirse diğer göreviniz 'GoOnAboutYourBusiness' olarak adlandırılmalıdır. Bunu söylüyorum çünkü büyük olasılıkla aramadan izlemeye geçerek değiştirmek istemezsiniz. Geleneksel programlama döngülerine sahip olanlarla başa çıkın. Tek bir sensörle, - ışık algılanan son döngüden daha koyu veya daha açık mı? daha koyu hale gelirse (siyah çizgi varsayarak) aynı yönü çevirmeye devam edin, daha açıksa diğer yöne çevirin, eğer aynı kaldıysa, düz gidin. Daha yumuşak olabilmek için muhtemelen biraz PID eklemeniz ve sadece sola ve sağa döndürmek yerine bir direksiyon eğrisi kullanmanız gerekir.

Ve evet, çoklu sensörler yardımcı olur. http://www.mindsensors.com/ - evet, şu anda filmde benim (11/10/2012)

Güncelleme: gerçek kod

Bunu kısa bir süre içinde deneyeceğim, ancak yukarıda yazdıklarımı derleyip gösteriyor:

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

Bu sorunun basit bir döngü ile daha kolay çözüldüğünü kabul ediyorum. Kimsenin bunu neden küçümsediğini anlamıyorum.
Shahbaz

Basit bir döngü ile çözmenin daha kolay olduğu izlenimini bırakmak istemiyorum, daha ziyade görevlerden biri olarak basit bir döngüyü kullanmak için doğru tüketimin doğru kullanımı olduğu izlenimini bırakmak istiyorum. Kim düşürdüğünde mod puanları vardır ve hiçbir varsayım anlayışı yoktur. Bir LEGO NXT (robotC kullanarak ima edilir) üzerinde fazlalık yapan pek çok insan olmadığını görmezsiniz, bu nedenle kodun kolayca yapıştırılmasını beklemeyin.
Spiked3

Evet, OP'nin neden toplamı kadar basit bir şey için görevleri kullandığını merak ediyorum.
Rocketmagnet

Çünkü robotC ile çok çok çok çok yaygın bir başlangıç ​​hatası - her şey için görevleri denemek ve kullanmak. Keşke sadece gelişmiş bir bölgeye taşımak isterdim.
Spiked3
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.