목표
차량용 보안모듈을 만들기 위해 하드웨어를 만드는 것이 목표이다.
사이드 미러를 위한 2중 축을 모터로 구현할 것이며 4개의 버튼을 통해 움직임을 할 것이다.
구현
하드웨어 구성
1. 라즈베리파이는 I2C를 통해 PWM컨트롤러PCA9685와 통신
2. 버튼 4개는 GPIO를 통해 라즈베리파이 INPUT으로 신호를 입력
3. 두개의 모터는 PWM컨트롤러PCA9685 채널 0, 1로 조정됨
핀 맵
1. PCA9685 :
SCL과 라즈베리파이 5번(SCL) 연결
SDA과 라즈베리파이 3번(SDA) 연결
VCC는 3.3V V+는 5V에 연결
전원은 공급 모듈을 사용했음 (되게 편하다. 추천!! 전원만 주면 3.3, 5V를 브레드 보드에 공급가능)
2. GPIO INPUT
BCM기준으로 코드도 짜야된다.
3.3V 입력을 준다.
버튼을 통해 아래와 같은 기능을 구성할 것이다.
GPIO 18 : 모터1 각도 2도 +
GPIO 23 : 모터1 각도 2도 -
GPIO 24 : 모터2 각도 2도 +
GPIO 25 : 모터2 각도 2도 -
이중 축 구성
이중축은 SG90 서보모터용 팬 틸트 브라켓을 사서 썼다. 근데 크기에 안맞는게 있어서 좀 잘라서 붙이느라 고생했다. 위에서 보았듯 사이드 미러는 두개의 축이 필요하므로 위의 거를 사용했다.
코드
PCA9685를 제어하기 위해 adafruit_pca9685 라이브러리를 사용했다.
그런데 인터넷에 나와있는 방법은 adafruit_pca9685 오픈소스를 다운받고, python3 ... install의 방법으로 라이브러리를 설치하는 방법을 사용했는데 AttributeError: install_layout 문제로 안되었다.
고생해서 발견한 방법은 https://github.com/adafruit/Adafruit_CircuitPython_PCA9685를 참조하여...
mkdir project-name && cd project-name
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-pca9685
위 방법을 따라해서 가상환경에서 사용하는 방법이었다.
그리고 아래 코드를 작성후 실행하여면 된다.
import time
import RPi.GPIO as GPIO
import board
import busio
from adafruit_pca9685 import PCA9685
# 서보 모터 설정
i2c = busio.I2C(board.SCL, board.SDA)
pwm = PCA9685(i2c)
pwm.frequency = 50 # SG90 모터는 50Hz에서 동작
# GPIO 설정 (BCM 모드)
GPIO.setmode(GPIO.BCM)
# 버튼 핀 설정
button_pin_18 = 18 # 모터 1 각도 2도 증가
button_pin_23 = 23 # 모터 1 각도 2도 감소
button_pin_24 = 24 # 모터 2 각도 2도 증가
button_pin_25 = 25 # 모터 2 각도 2도 감소
GPIO.setup(button_pin_18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button_pin_23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button_pin_24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button_pin_25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
# 서보 모터 각도 초기값
current_angle_1 = 90 # 모터 1 (채널 0)의 초기 각도
current_angle_2 = 90 # 모터 2 (채널 1)의 초기 각도
# 서보 모터 제어 함수
def set_servo_angle(channel, angle):
pulse_min = 0x0666 # 2.5% 듀티 사이클
pulse_max = 0x199A # 12.5% 듀티 사이클
pulse_range = pulse_max - pulse_min
# 각도를 PWM 듀티 사이클로 변환
pulse_width = int(pulse_min + (pulse_range * (angle / 180.0)))
pwm.channels[channel].duty_cycle = pulse_width # 서보 모터 제어 (채널 설정)
try:
print("Press the buttons to move the servos by 2 degrees.")
while True:
# GPIO 18: 모터 1 각도 2도 증가
if GPIO.input(button_pin_18) == GPIO.HIGH:
if current_angle_1 < 180:
current_angle_1 += 2
set_servo_angle(0, current_angle_1) # 채널 0번 (모터 1) 제어
print(f"Motor 1 (Channel 0) angle: {current_angle_1} degrees")
time.sleep(0.2)
# GPIO 23: 모터 1 각도 2도 감소
if GPIO.input(button_pin_23) == GPIO.HIGH:
if current_angle_1 > 0:
current_angle_1 -= 2
set_servo_angle(0, current_angle_1) # 채널 0번 (모터 1) 제어
print(f"Motor 1 (Channel 0) angle: {current_angle_1} degrees")
time.sleep(0.2)
# GPIO 24: 모터 2 각도 2도 증가
if GPIO.input(button_pin_24) == GPIO.HIGH:
if current_angle_2 < 180:
current_angle_2 += 2
set_servo_angle(1, current_angle_2) # 채널 1번 (모터 2) 제어
print(f"Motor 2 (Channel 1) angle: {current_angle_2} degrees")
time.sleep(0.2)
# GPIO 25: 모터 2 각도 2도 감소
if GPIO.input(button_pin_25) == GPIO.HIGH:
if current_angle_2 > 0:
current_angle_2 -= 2
set_servo_angle(1, current_angle_2) # 채널 1번 (모터 2) 제어
print(f"Motor 2 (Channel 1) angle: {current_angle_2} degrees")
time.sleep(0.2)
time.sleep(0.1) # 버튼 상태 체크 딜레이
except KeyboardInterrupt:
print("Program stopped by user")
GPIO.cleanup()
pwm.channels[0].duty_cycle = 0 # 모터 1 정지 (채널 0)
pwm.channels[1].duty_cycle = 0 # 모터 2 정지 (채널 1)
결과
사이드 미러라 각도는 조금씩만 바뀌게 조정하였다. 각도가 작아 버튼을 눌렀을때 변화가 작아서 잘 보이진 않는다.