Hardware | L9110 2-Channel DC Motor Driver 사용해 보기

1. L9110

우연한 기회에 analog motor 를 제어하는 breakout 를 구하게 되었습니다.


수분과 열에 의하여 보드가 조금 손상되어 있네요.


사용된 chip 은 L9110S 라고 표기되어 있습니다. 모터 하나씩 제어할 수 있도록, 두 개가 실장되어 있습니다.




2. DC Motor

어렸을 적부터 가지고 놀던 모터는 전원선 부분에서 자주 단선이 되는 문제가 있었습니다. 이번에 테스트 이후, 다른 곳에서 또다시 사용할 수 있으므로, 조금 두꺼운 전선을 사용하기로 합니다. 아래 사진은, 비교를 위하여 Breadboard 에 사용하는 두꺼운 리드선과 대조해 봤습니다.


모터에 +/- 전선을 연결해 주고, 깔맞춤 수축튜브로 마무리 해 줍니다. 물론 전선과 모터 단자를 납땜도 해 두었습니다. 이렇게 해 놓으면, 쉽게 끊어지지 않을 것 입니다.


Breakout 보드와 DC Motor 를 연결 합니다. 굵은 전선은 심적 안심이 되네요.




3. Diagram

DC Motor + Breakout Board + Arduino 와 연결한 전체 구성 입니다.

------------------------------
    L9112S   |  Arduino Nano
------------------------------
    GND      |      GND
    A1A      |      D2
    A1B      |      D3
    B1A      |      D5
    B1B      |      D6
------------------------------
             |      MB102
------------------------------
    GND      |       GND
    VCC      |       5V
------------------------------
             |    DC Motor
------------------------------
 Motor A +/- |   Motor A +/-
 Motor B +/- |   Motor B +/-
------------------------------

그림으로 그린 구성도 입니다.




4. Source Code

모터 제어하는 arduino 소스코드는 아래 출처에서 참고하였습니다.

* Arduino Code for L9110 Dual DC motor controller module

DC Moter 두 개를, A/B 로 정의한 후, 각 모터의 좌우 방향시 필요한 digitalWrite 를 사용하여 정의하였습니다. 그런 다음, 한 개씩 좌우로 돌리고, 마지막으로 동시에 돌리는 소스 입니다. Comment 를 보면 내용을 알 수 있습니다.

/*
 * Display number on seven segment display with Arduino
 * Written by Ahmad Shamshiri for Robojax.com
Date modified: Jun 11, 2018 at 17:20 at Ajax, Ontario, Canada
watch video instruction for this code:https://youtu.be/-g6Q9lSHDzg

Code is provided for free AS IS without warranty. 
You can share this acode as long as you keep the above note intact.
 */

const int A1A = 2; //define pin 2 for A1A
const int A1B = 3; //define pin 3 for A1B
const int B1A = 5; //define pin 5 for B1A
const int B1B = 6; //define pin 6 for B1B

void setup() {
	pinMode(B1A, OUTPUT); // define pin as output
	pinMode(B1B, OUTPUT);
	
	pinMode(A1A, OUTPUT);
	pinMode(A1B, OUTPUT);    
	
	delay(3000);
}

void loop() {
	motorA('R'); // Turn motor A to RIGHT
	delay(2000);
	motorA('L'); // Turn motor A to LEFT
	delay(2000);
	motorA('O'); // Turn motor A OFF
	delay(2000);
	
	motorB('R'); // Turn motor B to RIGHT
	delay(2000);
	motorB('L'); // Turn motor B to LEFT
	delay(2000); 
	motorB('O'); // Turn motor B OFF
	delay(2000);
	
	motorA('R'); // Turn motor A to RIGHT
	motorB('R'); // Turn motor A to RIGHT
	delay(2000);
	motorA('L'); // Turn motor A to LEFT
	motorB('L'); // Turn motor B to LEFT
	delay(2000);
	motorA('O'); // Turn motor A OFF
	motorB('O'); // Turn motor B OFF
	delay(5000);
}

/*
 * @motorA
 * activation rotation of motor A
 * d is the direction
 * R = Right
 * L = Left
 */

void motorA(char d) {
	if(d == 'R') {
		digitalWrite(A1A, LOW);
		digitalWrite(A1B, HIGH);
	} else if (d == 'L') {
		digitalWrite(A1A, HIGH);
		digitalWrite(A1B, LOW);    
	} else {
		// Turn motor OFF
		digitalWrite(A1A, LOW);
		digitalWrite(A1B, LOW);
	}
} // motorA end


/*
 * @motorB
 * activation rotation of motor B
 * d is the direction
 * R = Right
 * L = Left
 */
void motorB(char d) {
	if(d == 'R') {
		digitalWrite(B1A, LOW);
		digitalWrite(B1B, HIGH); 
	} else if(d == 'L') {
		digitalWrite(B1A, HIGH);
		digitalWrite(B1B, LOW);
	} else {
		// Turn motor OFF      
		digitalWrite(B1A, LOW);
		digitalWrite(B1B, LOW);
	}
} // motorB end



5. Driving

위의 Source 를 이용해 실제 구동한 모습 입니다.


DC Motor 가 전류를 많이 먹어서, arduino 의 5V 에 연결하면, arduino 가 뜨거워 지거나, 전원부 다이오드가 타버릴 것입니다. 가능한 외부 전원 입력 - MB102 나 HW-131 을 사용해야 합니다.



6. Voltage Wave

Arduino Nano 의 digital pin 에서 출력되는 voltage 나, DC Motor 에 들어가는 전압에 대해 측정해 봤습니다.


digitalWrite = HIGH 일 때는, 순수하게 5V 를 뿜어 주는군요.


DC Motor 를 구동하는 5V 도 arduino 신호에 맞춰, 5V 를 띄워 줍니다. 차이는 많은 전류를 포함한 것이라 예측해 봅니다.




7. Two HIGH Input

소스를 보면, digitalWrite = HIGH, +/- 에 동시에 5V 를 보내주는 문장이 없습니다. 그래서 일부러 소스를 수정해서 돌려 봤습니다.

....

void loop() {
  motorA('R'); // Turn motor A to RIGHT
  delay(2000);
}

...

void motorA(char d) {
  if(d == 'R') {
    digitalWrite(A1A, LOW);
    digitalWrite(A1B, HIGH);
  } else if (d == 'L') {
    digitalWrite(A1A, HIGH);
    digitalWrite(A1B, LOW);
  } else if (d == 'H') {
    digitalWrite(A1A, HIGH);
    digitalWrite(A1B, HIGH);
  } else {
    // Turn motor OFF
    digitalWrite(A1A, LOW);
    digitalWrite(A1B, LOW);
  }
}

...

A1A / A1B 모두 HIGH / HIGH 로 하면 L9110 chip 이 LOW / LOW 로 사전 차단하는 듯 합니다. 모터의 양 단자에 HIGH / HIGH 로 하면 부하가 걸릴 것이 분명하기에, 차단하는 듯 합니다. 예외 상황까지 커버하는 L9110 되겠습니다.




8. PWM

Arduino 의 PWM 신호 발생을 이용하여, 속도 조절하는 방법은 아래 소스 입니다. 신호의 duty cycle 조정을 통하여, 최고 속도를 255 로 보고, 가감하는 소스 입니다.

* How to use the HG7881 (L9110) Dual Channel Motor Driver Module

소스를 살펴 보면, 회전을 멈출 때, 강제로 break 를 거는 방법과, 서서히 속도를 줄이는 방법도 나와 있습니다. 모터의 기계적인 구동을 생각하면, 서서히 멈추게 하는 것이 좋겠죠. 매우 참고가 되는 소스 입니다.

/*
  HG7881_Motor_Driver_Example - Arduino sketch
   
  This example shows how to drive a motor with using HG7881 (L9110) Dual
  Channel Motor Driver Module.  For simplicity, this example shows how to
  drive a single motor.  Both channels work the same way.
   
  This example is meant to illustrate how to operate the motor driver
  and is not intended to be elegant, efficient or useful.
   
  Connections:
   
    Arduino digital output D10 to motor driver input B-IA.
    Arduino digital output D11 to motor driver input B-IB.
    Motor driver VCC to operating voltage 5V.
    Motor driver GND to common ground.
    Motor driver MOTOR B screw terminals to a small motor.
     
  Related Banana Robotics items:
   
    BR010038 HG7881 (L9110) Dual Channel Motor Driver Module
    https://www.BananaRobotics.com/shop/HG7881-(L9110)-Dual-Channel-Motor-Driver-Module
 
  https://www.BananaRobotics.com
*/
 
// wired connections
#define HG7881_B_IA 5 // D5 --> Motor B Input A --> MOTOR B +
#define HG7881_B_IB 6 // D6 --> Motor B Input B --> MOTOR B -
 
// functional connections
#define MOTOR_B_PWM HG7881_B_IA // Motor B PWM Speed
#define MOTOR_B_DIR HG7881_B_IB // Motor B Direction
 
// the actual values for "fast" and "slow" depend on the motor
#define PWM_SLOW 50  // arbitrary slow speed PWM duty cycle
#define PWM_FAST 200 // arbitrary fast speed PWM duty cycle
#define DIR_DELAY 1000 // brief delay for abrupt motor changes
 
void setup()
{
  Serial.begin(115200);
  pinMode(MOTOR_B_DIR, OUTPUT);
  pinMode(MOTOR_B_PWM, OUTPUT);
  digitalWrite(MOTOR_B_DIR, LOW);
  digitalWrite(MOTOR_B_PWM, LOW);
}
 
void loop()
{
  boolean isValidInput;
  // draw a menu on the serial port
  Serial.println( "-----------------------------" );
  Serial.println( "MENU:" );
  Serial.println( "1) Fast forward" );
  Serial.println( "2) Forward" );
  Serial.println( "3) Soft stop (coast)" );
  Serial.println( "4) Reverse" );
  Serial.println( "5) Fast reverse" );
  Serial.println( "6) Hard stop (brake)" );
  Serial.println( "-----------------------------" );
  do
  {
    byte c;
    // get the next character from the serial port
    Serial.print("?");
    while(!Serial.available())
      ; // LOOP...
    c = Serial.read();
    // execute the menu option based on the character recieved
    switch( c )
    {
      case '1': // 1) Fast forward
        Serial.println("Fast forward...");
        // always stop motors briefly before abrupt changes
        digitalWrite(MOTOR_B_DIR, LOW);
        digitalWrite(MOTOR_B_PWM, LOW);
        delay(DIR_DELAY);
        // set the motor speed and direction
        digitalWrite(MOTOR_B_DIR, HIGH); // direction = forward
        analogWrite(MOTOR_B_PWM, 255-PWM_FAST); // PWM speed = fast
        isValidInput = true;
        break;      
         
      case '2': // 2) Forward      
        Serial.println("Forward...");
        // always stop motors briefly before abrupt changes
        digitalWrite(MOTOR_B_DIR, LOW);
        digitalWrite(MOTOR_B_PWM, LOW);
        delay(DIR_DELAY);
        // set the motor speed and direction
        digitalWrite(MOTOR_B_DIR,HIGH ); // direction = forward
        analogWrite(MOTOR_B_PWM, 255-PWM_SLOW); // PWM speed = slow
        isValidInput = true;
        break;      
         
      case '3': // 3) Soft stop (preferred)
        Serial.println("Soft stop (coast)...");
        digitalWrite(MOTOR_B_DIR, LOW);
        digitalWrite(MOTOR_B_PWM, LOW);
        isValidInput = true;
        break;      
 
      case '4': // 4) Reverse
        Serial.println("Reverse...");
        // always stop motors briefly before abrupt changes
        digitalWrite( MOTOR_B_DIR, LOW);
        digitalWrite( MOTOR_B_PWM, LOW);
        delay(DIR_DELAY);
        // set the motor speed and direction
        digitalWrite(MOTOR_B_DIR, LOW); // direction = reverse
        analogWrite(MOTOR_B_PWM, PWM_SLOW); // PWM speed = slow
        isValidInput = true;
        break;      
         
      case '5': // 5) Fast reverse
        Serial.println("Fast reverse...");
        // always stop motors briefly before abrupt changes
        digitalWrite(MOTOR_B_DIR, LOW);
        digitalWrite(MOTOR_B_PWM, LOW);
        delay(DIR_DELAY);
        // set the motor speed and direction
        digitalWrite(MOTOR_B_DIR, LOW); // direction = reverse      
        analogWrite(MOTOR_B_PWM, PWM_FAST); // PWM speed = fast
        isValidInput = true;
        break;
         
      case '6': // 6) Hard stop (use with caution)
        Serial.println("Hard stop (brake)...");
        digitalWrite(MOTOR_B_DIR, HIGH);
        digitalWrite(MOTOR_B_PWM, HIGH);
        isValidInput = true;
        break;      
         
      default:
        // wrong character! display the menu again!
        isValidInput = false;
        break;
    }
  } while(isValidInput == true);
 
  // repeat the main loop and redraw the menu...
}
/*EOF*/

실제 제어는 Serial Monitor 에서 번호 입력으로 구동합니다.


실제 구동 동영상 입니다.


Slow 로 했을 때, 파형을 찍어 보면, 아래와 같습니다. (255-200)/255 * 100% = 21.6% 정도이니, 아래 파형의 duty cycle 과 일치 합니다.


Fast 로 했을 경우, (255-50)/255 * 100% = 80.3% 로, 아래 오실로스코프 값과 일치 합니다.



FIN

댓글