AI 탐구노트

아두이노 : 조이스틱으로 서보모터 조종하기 - 2편 본문

DIY 테스트

아두이노 : 조이스틱으로 서보모터 조종하기 - 2편

42morrow 2024. 9. 30. 18:30

 

 

이전 글에서는 아두이노에 조이스틱을 연결해서 움직임 값을 시리얼 모니터로 확인해 봤습니다.

서보모터 2개의 연결은 아래 이전 글을 참고하시면 됩니다.

 

[DIY 테스트] - 아두이노 : 조이스틱으로 서보모터 조종하기 - 1편

 

 

이번에는 조이스틱을 조종해 서보모터를 동작시키는 것을 해볼 생각입니다.

 

이를 위해 다음과 같은 작업을 진행합니다. 

  1. Python으로 pyfirmata 패키지를 이용해 아두이노를 컨트롤합니다.
  2. 조이스틱 움직임을 읽어와서 이를 이용해 다시 서보모터를 조종하도록 합니다.

 

Python 코드 생성

코딩은 ChatGPT한테 시켰는데 아주 잘 만들어 줍니다. ^^; 

주문사항은 아두이노, 서보모터, 조이스틱이 각각 어떻게 매핑되어 있고 조이스틱을 누르면 중지/재시작을 수행해라 정도였습니다.

후자의 경우는 연속형이라 계속해서 돌아가는 상황이 발생할까봐였는데 돌려보니 기우였던 것 같습니다. 

 

import pyfirmata
import time

# 아두이노 포트 설정 - 제 경우, ttyUSB0 대신 ttyArduino로 symbolic Link를 사용 중입니다.
board = pyfirmata.Arduino('/dev/ttyArduino')

# 핀 설정
SERVO_X_PIN = 9
SERVO_Y_PIN = 10
JOYSTICK_SW_PIN = 7
JOYSTICK_X_PIN = 'a:0:i'
JOYSTICK_Y_PIN = 'a:1:i'

# 서보모터와 조이스틱 초기화
servo_x = board.get_pin(f'd:{SERVO_X_PIN}:s')
servo_y = board.get_pin(f'd:{SERVO_Y_PIN}:s')
joystick_sw = board.get_pin(f'd:{JOYSTICK_SW_PIN}:i')
joystick_x = board.get_pin(JOYSTICK_X_PIN)
joystick_y = board.get_pin(JOYSTICK_Y_PIN)

# 서보모터 최대/최소 각도 설정
SERVO_MIN = 0
SERVO_MAX = 180

# 조이스틱 중심 값과 임계값 설정
JOYSTICK_CENTER = 0.5  # 조이스틱의 중간 값을 0.5로 설정
JOYSTICK_THRESHOLD = 0.1

# 메인 루프
def loop():
    running = True  # 서보모터 작동 상태
    last_switch_state = 1  # 마지막 스위치 상태

    it = pyfirmata.util.Iterator(board)
    it.start()

    joystick_sw.enable_reporting()
    joystick_x.enable_reporting()
    joystick_y.enable_reporting()

    while True:
        # 조이스틱 스위치 상태 확인
        switch_state = joystick_sw.read()

        # 버튼이 눌릴 때마다 서보모터 작동/멈춤 전환
        if switch_state == 0 and last_switch_state == 1:
            running = not running  # 작동 상태 반전
            time.sleep(0.5)  # 버튼이 눌릴 때 반응 딜레이
        
        last_switch_state = switch_state

        # 서보모터 작동 중일 때만 조이스틱 값에 따라 서보 제어
        if running:
            x_value = joystick_x.read()
            y_value = joystick_y.read()

            if x_value is not None and y_value is not None:
                x_angle = (x_value * (SERVO_MAX - SERVO_MIN)) + SERVO_MIN
                y_angle = (y_value * (SERVO_MAX - SERVO_MIN)) + SERVO_MIN

                servo_x.write(x_angle)
                servo_y.write(y_angle)

        # 100ms 딜레이 후 루프 반복
        time.sleep(0.1)

# 프로그램 종료 시 서보모터 초기화
def cleanup():
    servo_x.write(90)
    servo_y.write(90)
    board.exit()

if __name__ == "__main__":
    try:
        loop()
    except KeyboardInterrupt:
        cleanup()

 

 

 

결과 확인

위의 코드를 이용해 구동시킨 후에 찍은 작동 영상을 올려봅니다. 잘 동작하는 것 같죠?

 

영상 : 서보모터 2개, 조이스틱 모듈을 아두이노에 연결해서 Python으로 구동시킨 예시

 

 

 

남은 숙제

위와 같이 잘 움직입니다만, 가끔씩 delay가 생기거나, Y축으로 특정각도 이상되면 그 뒤부터는 작동하지 않는 경우가 있었습니다.

이는 Y축 값을 특정 각도로 제한하는 로직이 추되면 해결될 문제로 판단됩니다.

시작할 때 딜레이가 생기는 부분은, 초기화를 완료하고 약간의 대기 시간을 주면 해결될 수 있다고 올라온 글을 본 적이 있습니다.

몇 가지는 고도화가 필요할 때 추가적으로 검토하면 될 것 같네요.