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
댓글
댓글 쓰기