MPU6050, 직진/후진, 좌회전/우회전 버튼을 연결했던 ESP32는 브레드보드의 왼쪽편에 그대로 두고, 오른편에 핀이 겹치지 않도록 ESP32를 하나 더 달았다. (ESP32 하나로도 충분히 할 수 있을 것 같지만 두 개를 쓰면 센서 한두개 더 연결할 수 있을 것 같아서)
rotary encoder | esp32 |
---|---|
gnd | gnd |
+ | 3.3v |
sw | gpio36 |
dt | gpio39 |
clk | gpio34 |
ROTARY_ENCODER_XXX
: 로타리 엔코더 연결 핀을 define 한다.command
topic으로 보낼 것이다. LAST_ENCODED
는 값이 바뀌지 않는 한, 값을 한 번만 읽고 mqtt 송신 한 번만 보내도록 하기 위해 만든 bool 변수로 volatile
키워드를 추가해 과하게 똑똑한 컴파일러의 방해(!)를 차단했다.SPEED
는 실제 속도 레벨로 치환되는 값이다. (1~9이지만 왜인지 조금 돌려도 값이 1~2씩 튀어서 라즈베리파이쪽 코드에서 범위로 idx를 메겼다)rotary_check()
: 커스텀 객체가 아닌, 기본 Thread
객체를 만들어서 interval 마다 주기적으로 실행할 함수를 정의했다.#define ROTARY_ENCODER_SW 36
#define ROTARY_ENCODER_DATA 39
#define ROTARY_ENCODER_CLK 34
// ... EspMQTTClient 코드
// ... MQTT 송신용 tx()
// ...
// 한 번만 보내기 위한 로직 변수
volatile int LAST_ENCODED = 0, SPEED = 1;
// mqtt 보낼 payload
char rotary_command_base[10] = "speed=";
// 스레드가 설정된 interval에 맞춰 주기적으로 실행할 함수
void rotary_check(void) {
int clk = digitalRead(ROTARY_ENCODER_CLK);
int dt = digitalRead(ROTARY_ENCODER_DATA);
int encoded = (clk << 1) | dt;
int sum = (LAST_ENCODED << 2) | encoded;
if (sum == 0b1101 || sum == 0b1011) { // left
if (SPEED > 1) { // min SPEED = 1
// Serial.println("rotary change");
SPEED--;
rotary_command_base[6] = SPEED + '0';
tx(CMD_TOPIC, rotary_command_base);
}
}
if (sum == 0b1110 || sum == 0b1000) { // right
if (SPEED < 9) { // max SPEED = 9
// Serial.println("rotary change");
SPEED++;
rotary_command_base[6] = SPEED + '0';
tx(CMD_TOPIC, rotary_command_base);
}
}
LAST_ENCODED = encoded;
}
// create thread
Thread rotary_th = Thread();
// ... thread controller 관련 코드
void setup(void) {
// ... serial monitor begin
// ... mqtt client enable
// 로타리 엔코더 핀 설정
pinMode(ROTARY_ENCODER_SW, INPUT);
pinMode(ROTARY_ENCODER_DATA, INPUT);
pinMode(ROTARY_ENCODER_CLK, INPUT);
// callback thread func
// 로타리 엔코더 스레드 callback func
rotary_th.onRun(rotary_check);
rotary_th.setInterval(10);
// rotary thread add to thread controller
controller.add(&rotary_th);
}
// ... callback for the Timer
// ... onConnectionEstablished()
void loop() {
controller.run();
client.loop();
}
기존 cmd_thread.py 에 내용을 추가한다.
class CmdThread(threading.Thread):
# ... broker_address, speed_idx, speed 객체 변수
# ... is_lr_all_false()
def on_command(self, client, userdata, message):
# ... cmd parsing
# ... if go, back, left_m/M, right_m/M, mid, stop 코드
# speed=xx 로 값이 오기 때문에 in 키워드로 조건 걸기
elif "speed" in cmd:
idx = int(cmd.split("=")[1]) # 값 파싱
# 범위로 인덱싱
if idx <= 2:
self.speed_idx = 0
elif idx <= 4:
self.speed_idx = 1
elif idx <= 6:
self.speed_idx = 2
else:
self.speed_idx = 3
self.speed_changed()
# 속도 값이 변경되었을 때 실행할 함수
def speed_changed(self):
if IS_FRONT: # 지금 직진 중이면 PWM 재설정 후 자동 직진
self.go()
elif IS_BACK: # 지금 후진 중이면 PWM 재설정 후 자동 후진
self.back()
# ... init(), run()
# ... def 전, 좌회, 우회, 후, 중앙, 멈춤 메서드