//==============================================================
// MotorBank BLC-H3000 시리즈(D: 2채널 / F: 4채널) 인휠 컨트롤러 아두이노 공용 예제 V1.2
// 근거: 제품 상세 IO 포트 신호 설명·주의사항(확정 자료)
// 보드: Arduino Uno
//
// [V1.2 변경 사항]
// - 방향 전환 시 제동 보조 정지 후 전환 (주행 중 급반전 방지)
// - 브레이크 해제/전환 시 RC 필터 방전 대기 50ms 추가
// - 상태 추적(현재 속도·방향·브레이크)으로 같은 방향 증감속은 딥 없이 즉시 반영
//
// [구조 이해 - 중요]
// BLC-H3000D(2채널): 모터 2개를 동일 명령으로 동시 제어 (보드 1장)
// BLC-H3000F(4채널): 2채널 보드 2장 구성, 모터 4개를 동일 명령으로 동시 제어
// → 어느 쪽도 좌우 바퀴 개별 속도 차동 조향은 불가. 개별 제어가 필요하면 단독형 컨트롤러 여러 대 사용
// 본 예제는 보드 1장의 MCU 3선을 제어하며, 4채널(2보드)은 같은 신호를 두 보드에 병렬 연결합니다.
//
// [MCU IO 3선 (제품 자료 확정)]
// 황색(속도) : 0~5V 아날로그 전압, 높을수록 빠름
// 브레이크 IO : LOW = 제동(속도 IO 전압이 높을수록 제동 강도 증가) / 정상 구동 시 반드시 HIGH
// 블랙(방향) : LOW(0V) = 회전 방향 전환
// 로직 레벨 : 0~3.4V = Low / 3.5~5V = High → 3.3V 보드는 레벨 변환 모듈 권장
// GND : MCU와 드라이버 GND 반드시 공통 (자료 명시)
//
// [아두이노 결선]
// D9(PWM) -> RC 필터(1kΩ 직렬 + 10uF 병렬 to GND, τ≈10ms) -> 황색(속도)
// * 자료가 "0~5V 아날로그 전압" 입력을 명시하므로 PWM은 평활해 아날로그 전압으로 인가
// D7 -> 적색(브레이크) D6 -> 흑색(방향) GND 공통
//
// [모터 결선] 3상선은 임의 순서 연결 후 회전 방향이 반대면 3상 중 2선 교체.
// 홀선은 미연결 가능(지능형). 연결 시 홀 5V/GND 극성 확인 필수.
//
// [운용 주의 (자료 확정)]
// - 속도를 과도하게 낮추면 스톨 보호로 정지할 수 있음 → 전원 재인가로 복구
// - SMPS 사용 시 브레이크 회생전류로 전원 보호 차단 가능 → 배터리 전원 권장
// (방향 전환 시 제동을 사용하므로 특히 배터리 전원 권장, 커넥터는 XT60)
// - 입력 전압 22~42V (22V 이하 보호 동작 가능), 48V 사용 불가
// - MCU 제어 이상 시 내장 노브로 정상 동작 확인 후 배선·프로그램 점검
//
// [한계 고지]
// 본 컨트롤러 구성은 속도/정지 피드백이 없습니다. 방향 전환 정지 시간
// (REVERSE_BRAKE_MS)은 실제 부하·관성에 맞게 반드시 조정하십시오.
//
// [시리얼 모니터 사용법] (9600bps, "새 줄" 설정)
// f60 : 정방향 속도 60% r40 : 역방향 40% s : 속도 0(관성 정지)
// b80 : 브레이크 강도 80%로 제동(0~100, 속도 IO 전압=제동 강도) g : 브레이크 해제
//==============================================================
const int SPEED_PIN = 9; // PWM -> RC 필터 -> 황색
const int BRAKE_PIN = 7; // 적색
const int DIR_PIN = 6; // 흑색
const int RC_SETTLE_MS = 50; // RC 필터 충·방전 대기
const int REVERSE_BRAKE_PCT = 70; // 방향 전환용 제동 강도
const int REVERSE_BRAKE_MS = 700; // 방향 전환용 제동 시간 (부하에 맞게 조정!)
int curSpeed = 0;
bool curFwd = true;
bool braking = false;
void setSpeed(int pct) {
pct = constrain(pct, 0, 100);
curSpeed = pct;
analogWrite(SPEED_PIN, map(pct, 0, 100, 0, 255));
}
// 제동 보조 정지 (방향 전환 전용, 블로킹)
void brakeStopBlocking() {
setSpeed(0);
delay(RC_SETTLE_MS); // 주행 전압 방전
digitalWrite(BRAKE_PIN, LOW);
setSpeed(REVERSE_BRAKE_PCT); // 속도 IO 전압 = 제동 강도
delay(REVERSE_BRAKE_MS); // 피드백이 없으므로 시간 기반 정지
setSpeed(0);
delay(RC_SETTLE_MS);
braking = true;
}
void runMotor(bool fwd, int pct) {
pct = constrain(pct, 0, 100);
// 주행 중 방향 전환 → 제동 정지 후 전환
if (fwd != curFwd && curSpeed > 0 && !braking) brakeStopBlocking();
if (braking) { // 제동 중이었다면 안전하게 해제
setSpeed(0);
delay(RC_SETTLE_MS); // 제동 전압 방전 (해제 순간 움찔 방지)
digitalWrite(BRAKE_PIN, HIGH);
braking = false;
}
digitalWrite(DIR_PIN, fwd ? HIGH : LOW);
curFwd = fwd;
setSpeed(pct); // 같은 방향 증감속은 딥 없이 즉시 반영
}
void coastStop() { // 속도 0, 브레이크는 걸지 않음(관성 정지)
setSpeed(0);
}
void applyBrake(int pct) {
pct = constrain(pct, 0, 100);
if (pct == 0) pct = 50; // 'b' 단독 입력 시 기본 50%
setSpeed(0);
delay(RC_SETTLE_MS); // 주행 전압 방전
digitalWrite(BRAKE_PIN, LOW);
braking = true;
setSpeed(pct); // 브레이크 강도
}
void releaseBrake() {
setSpeed(0);
delay(RC_SETTLE_MS); // 제동 전압 방전
digitalWrite(BRAKE_PIN, HIGH);
braking = false;
}
void setup() {
pinMode(BRAKE_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
setSpeed(0);
digitalWrite(BRAKE_PIN, HIGH); // 주행 가능 상태로 시작하되 속도 0
braking = false;
digitalWrite(DIR_PIN, HIGH); // 정방향
Serial.begin(9600);
Serial.setTimeout(100);
Serial.println(F("BLC-H3000 ready. f60 r40 s b80 g"));
}
void loop() {
if (!Serial.available()) return;
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.length() == 0) return;
char c = cmd.charAt(0);
int v = cmd.substring(1).toInt();
switch (c) {
case 'f': runMotor(true, v);
Serial.print(F("FWD ")); Serial.print(constrain(v, 0, 100)); Serial.println('%'); break;
case 'r': runMotor(false, v);
Serial.print(F("REV ")); Serial.print(constrain(v, 0, 100)); Serial.println('%'); break;
case 's': coastStop();
Serial.println(F("STOP (coasting)")); break;
case 'b': applyBrake(v);
Serial.print(F("BRAKE ")); Serial.print(v > 0 ? constrain(v, 0, 100) : 50); Serial.println('%'); break;
case 'g': releaseBrake();
Serial.println(F("BRAKE OFF (speed 0)")); break;
default: Serial.println(F("? f60 r40 s b80 g"));
}
}
작성: MotorBank 기술팀 · 아두이노 우노 기준 · 최종 업데이트: 2026-09-15 (V1.2)
상품이 장바구니에 담겼습니다.
바로 확인하시겠습니까?
상품이 찜 리스트에 담겼습니다.
바로 확인하시겠습니까?