[아두이노] Differential Wheeled RC카 만들기 #2-3 "모터 구동/정지 함수 제작"

    이전까지의 포스팅에서 모터의 회전 방향, 그리고 데드존까지 테스트 해봤습니다.

    바로 차동 구동 알고리즘으로 들어갈까 하여 구상을 해보니 하나 걸리는게 있어서 작업을 해놓고 넘어가려고 합니다.


    굳이?

    지금 구상한 것들을 간단하게(귀찮으니까) 그려봤습니다.

     

    평균 함수는 솔직히 마무리 단계에서 사용을 하게 될지 잘 모르겠습니다.

    일단 평균 함수를 사용하면 연산이 느려지는데, 모터의 가동 범위가 줄었을 뿐더러 "과연 필터링을 하지 않은 값이 그렇게 영향을 미칠까?" 라는 생각도 들기 때문입니다.

     

    믹서의 알고리즘 양단에 있는 스케일링 함수는 어쩌면 최대한 중복을 피해서 사용하게 될 것 같습니다.

    느려지기도 하고 굳이 여러번 할 필요가 없으니까요.

     

    그런데 어찌됐던 반드시 빠지지 않을 부분이 있습니다.

    바로 알고리즘 출력부 쪽의 모터에 명령을 주는 부분입니다.

    양쪽 모터에 적절한 값을 주어 전진, 후진, 정지(일단 옵션)를 시켜야 합니다.

    만들기 어려운 함수는 아니니, 사용하게 될지 말지는 나중에 생각하고 일단 만들어 봤습니다.


    코드

    #define motorLeft_EN 3    // Left Motor: ENA(PWM) pin
    #define motorLeft_OUT1 2  // Left Motor: IN1 pin
    #define motorLeft_OUT2 4  // Left Motor: IN2 pin
    #define motorRight_EN 5   // Right Motor: ENB(PWM) pin
    #define motorRight_OUT1 7 // Right Motor: IN3 pin
    #define motorRight_OUT2 6 // Right Motor: IN4 pin
    
    void motorRun(bool Side, bool Direction, int Speed, int Duration) {
      /*
        bool Side : select which motor to run.
                    {false: Left; true: Right}
        bool Direction : select the direction of motor.
                         {false: backward; true: foward}
        int Speed : speed value to run motor.
                    {0 <= Speed <256}
        int Duration : time to run. [msec]
      */
      int pwmPin = 0;
      if (Side == false)
      {
        digitalWrite(motorLeft_OUT1, Direction);
        digitalWrite(motorLeft_OUT2, !Direction);
        pwmPin = motorLeft_EN;
        Serial.print("LEFT ");
      }
      else
      {
        digitalWrite(motorRight_OUT1, Direction);
        digitalWrite(motorRight_OUT2, !Direction);
        pwmPin = motorRight_EN;
        Serial.print("RIGHT ");
      }
      Serial.print("motor RUN, ");
      Serial.print("for "); Serial.print(Duration); Serial.print(" msec,\t");
      analogWrite(pwmPin, Speed);
      Serial.print("speed at "); Serial.println(Speed);
      delay(Duration);
    }
    
    void motorStop(bool Side, int Duration) {
      if (Side == false) {
        digitalWrite(motorLeft_OUT1, HIGH);
        digitalWrite(motorLeft_OUT2, HIGH);
        Serial.print("Left ");
      }
      else {
        digitalWrite(motorRight_OUT1, HIGH);
        digitalWrite(motorRight_OUT2, HIGH);
        Serial.print("Right ");
      }
      Serial.println("motor STOP");
      delay(Duration);
    }
    
    void setup() {
      Serial.begin(19200);
      pinMode(motorLeft_EN, OUTPUT);
      pinMode(motorLeft_OUT1, OUTPUT);
      pinMode(motorLeft_OUT2, OUTPUT);
      pinMode(motorRight_EN, OUTPUT);
      pinMode(motorRight_OUT1, OUTPUT);
      pinMode(motorRight_OUT2, OUTPUT);
    }
    
    void loop() {
      // Left motor, direction: backward, with 100 speed, for 3 sec.
      motorRun(false, false, 100, 3000);
      motorStop(false, 1000);
    
      // Left motor, direction: foward, with 100 speed, for 3 sec.
      motorRun(false, true, 100, 3000);
      motorStop(false, 1000);
    
      // Right motor, direction: backward, with 100 speed, for 3 sec.
      motorRun(true, false, 100, 3000);
      motorStop(true, 1000);
    
      // Right motor, direction: foward, with 100 speed, for 3 sec.
      motorRun(true, true, 100, 3000);
      motorStop(true, 1000);
    }

    motorRun() 함수와 motorStop() 함수를 제작했습니다.

     

    모터 구동 함수

    void motorRun(bool Side, bool Direction, int Speed, int Duration) {
      /*
        bool Side : select which motor to run.
                    {false: Left; true: Right}
        bool Direction : select the direction of motor.
                         {false: backward; true: foward}
        int Speed : speed value to run motor.
                    {0 <= Speed <256}
        int Duration : time to run. [msec]
      */
      int pwmPin = 0;
      if (Side == false)
      {
        digitalWrite(motorLeft_OUT1, Direction);
        digitalWrite(motorLeft_OUT2, !Direction);
        pwmPin = motorLeft_EN;
        Serial.print("LEFT ");
      }
      else
      {
        digitalWrite(motorRight_OUT1, Direction);
        digitalWrite(motorRight_OUT2, !Direction);
        pwmPin = motorRight_EN;
        Serial.print("RIGHT ");
      }
      Serial.print("motor RUN, ");
      Serial.print("for "); Serial.print(Duration); Serial.print(" msec,\t");
      analogWrite(pwmPin, Speed);
      Serial.print("speed at "); Serial.println(Speed);
      delay(Duration);
    }

    먼저 motorRun() 함수는 4가지 파라미터를 선언했습니다.

    호출할 때 4가지 인자를 사용해야 한다는 얘기죠.

    함수 시작 부분에 코멘트로 설명을 적어놓았지만, 사랑하는 우리말 한글로 한번 더 풀어보겠습니다.

    • Side (bool) : 좌측과 우측 모터 중 어느 모터를 구동할지 선택합니다. 왼쪽 모터는 false를, 오른쪽 모터는 true를 입력합니다.
    • Direction (bool) : 모터를 회전시킬 방향을 선택합니다. 역방향은 false를, 정방향은 true를 입력합니다.
    • Speed (int) : 모터를 구동시킬 속도를 입력합니다. 값의 범위는 0~255 입니다.
    • Duration (int) : 모터를 구동시킬 시간을 입력합니다. 단위는 msec 입니다.

     

    모터 정지 함수

    void motorStop(bool Side, int Duration) {
      if (Side == false) {
        digitalWrite(motorLeft_OUT1, HIGH);
        digitalWrite(motorLeft_OUT2, HIGH);
        Serial.print("Left ");
      }
      else {
        digitalWrite(motorRight_OUT1, HIGH);
        digitalWrite(motorRight_OUT2, HIGH);
        Serial.print("Right ");
      }
      Serial.println("motor STOP");
      delay(Duration);
    }

    모터를 정지시키는 motorStop() 함수입니다.

    해당 함수는 2가지 파라미터가 존재합니다.

    • Side (bool) : 좌측과 우측 모터 중 어느 모터를 정지할지 선택합니다. 왼쪽 모터는 false를, 오른쪽 모터는 true를 입력합니다.
    • Duration : 모터를 정지할 시간을 입력합니다. 단위는 msec 입니다.

    무언가 조금 찝찝하다...

    모터 구동 함수에서 실질적으로 모터에 PWM 명령을 주는 analogWrite() 함수를 보면, 결국 모터에게는 0~255 사이의 값을 주어야 한다는 것을 알 수 있습니다.

    하지만 제가 구상한 차동 구동 알고리즘은 Throttle(thrust)과 Rudder(steering)의 조합에 따른 출력값을 계산하기 때문에 믹서는 0~100%의 값을 받도록 해야 합니다.

    그 말은 수신기의 raw 값을 0~100%의 백분율로 변환해 믹서로 입력, 계산 후 다시 0~255의 PWM을 출력해야 한다는 소리죠.

    스케일링이 2번 일어나게 되는데 과연 이게 정말 필요한지, 낭비는 아닌지 싶네요.

    댓글

    Designed by JB FACTORY