로봇 C와 함께 Subsumption Architecture를 사용하는 올바른 방법


11

Subsumption Architecture 에 대해 최근에 많은 책을 읽었 으며 사람들이 옹호하는 것처럼 보이는 몇 가지 다른 방법이 있습니다.

예를 들어 일부 사람들은 전역 "플래그"변수를 사용하여 작업을 제어합니다. 다른 사람들 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()인계 하기 때문에 내 if 문이 조건으로 충분하지 않습니다 . 이것은 트랙 내의 else 문 때문입니까? 그렇다면 track()프로그램을 시작할 때 마초를 인계하지 않고 회선을 풀 때 회전 하는 방법은 무엇입니까?


1
에 입력 한 숫자 StartTask는 작업의 우선 순위입니까? 9가 최우선 순위가됩니까? 이 경우 ? find보다 우선 순위가 높아서는 안됩니다 track. 실제로 조건 findelse조건은 track동일합니다. 따라서 사람으로서 센서 값이 임계 값보다 크면 어떻게해야합니까? 나선형으로 가거나 선을 조정하기 위해 돌리시겠습니까?
Shahbaz

하위 가정 아키텍처가 무엇인지 알고 있으며, 로봇에 저수준 계산 작업을 담당하는 다른 하드웨어 모듈이 있어야합니다. 그리고 코드는 단순히 조건부 상태를 수신하기보다는 신호를 흡수해야합니다. 신호를 다른 하드웨어로 전달해서는 안됩니까? 이제 내 문제는 두 개의 Arduino가 있고 Arduino A가 Arduino B의 신호를 대체하거나 억제하기를 원합니다. 누구든지 이것이 어떻게 수행되는지 알고 있습니까? Arduino A를 연결하여 Arduino B에 신호를 보낼 수는 있지만 시그를 포섭하거나 억제하는 방법을 잘 모르겠습니다
Ambient Soda

답변:


7

포섭 아키텍처로, 당신은 신중하게 할당 작업의 경우 것과 같은 방식으로 당신의 행동을 설계해야합니다 T우선 n, 다음 T우선 순위가 높은 모든 작업이보다 경우 로봇이해야 할 일해야 n무시됩니다.

예제 작업을 주문한 다음 구현 방법을 알아 봅시다. 당신의 작업은 evade, find하고 track.

일반적으로 로봇이 선을 추적하기를 원할 것입니다. 그러나 라인을 감지 할 수 없으면 찾아야합니다. 무엇보다도 장애물을 피해야합니다. 이것은 우리에게 다음과 같은 순서를줍니다 :

  • 최우선 순위 : 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

짧은 대답; 아니, 당신은 정말로 약간 다르게 행동 할 필요가 있습니다.

긴 불완전한 답변; 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는 최근에 다시 진입 한 것이므로 센서 액세스와 같은 것들 둘 이상의 작업에서 위험이 발생할 수 있으며 (I2C 타이밍 문제) 경우에 따라 (자동 폴링 센서) 그렇지 않습니다.

작업을 수행함에 따라 위의 루프에 자신의 우선 순위 구현을 추가 할 수 있지만 실제로는 시작에 필요하지 않습니다.

귀하의 의견 "// 상자 방해물"은 탄도 행동을 설명합니다. 멀티 태스킹을 사용하여 구현하기에는 약간 까다 롭습니다. 내가 사용한 간단한 루프는 초보자 / 학습에 훨씬 쉽고 편리합니다.

내가 당신에게 남겨줄 또 다른 것은, 많은 것들에 깔끔하고 적절하면서도 포섭이 전통적으로 더 잘 수행되는 것을 구현하는 좋은 방법이 아니라는 것입니다. 실제로 '피하다'부분은 추정에 대한 좋은 후보가 될 수 있지만 솔직히 다른 작업은 'GoOnAboutYourBusiness'라고합니다. 나는 당신이 아마도 하위 추정으로 검색에서 다음으로 변경하고 싶지 않기 때문에 이것을 말합니다. 전통적인 프로그래밍 루프로 처리하십시오. 단일 센서를 사용하면 빛이 마지막 루프보다 어둡거나 밝습니까? 어두워 진 경우 (검은 색 선으로 가정) 같은 방향으로 계속 돌리고, 반대로 반대 방향으로 돌리면 동일하게 유지되면 똑바로 가십시오. 더 부드럽게하려면 왼쪽과 오른쪽으로 돌리는 대신 PID를 추가하고 조향 곡선을 사용해야합니다.

그리고 여러 센서가 도움이됩니다. http://www.mindsensors.com/- 예, 현재 영화에서 나입니다 (2012 년 11 월 10 일)

업데이트 : 실제 코드

나는 이것을 잠시 후에 시도 할 것이지만, 위에서 쓴 것을 컴파일하고 보여줍니다.

#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

간단한 루프로 해결하기가 더 쉽다는 인상을 남기고 싶지 않고 단순한 루프를 작업 중 하나로 사용하기 위해 하위 가정을 올바르게 사용한다는 인상을 남기고 싶습니다. 다운 그레이드 한 사용자는 모드 포인트가 있으며 하위 가정에 대한 이해가 없습니다. LEGO NXT에서 하위 추정을하는 사람들이 많지 않다는 것을 알 수 없으므로 (robotC를 사용하여) 코드를 쉽게 붙여 넣을 수 있다고 기대하지 마십시오.
Spiked3

예, OP가 하위 가정만큼 간단한 작업을 수행하는 이유가 궁금합니다.
Rocketmagnet

robotC는 매우 일반적인 초보자 실수이므로 모든 작업을 시도하고 사용합니다. 나는 그들이 그것을 고급 전용 영역으로 옮기기를 바랍니다.
Spiked3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.