우분투 터미널 창을 열고 다음 코드를 입력해서 PCA9685 라이브러리 설치한다.
sudo pip install adafruit-circuitpython-pca9685 --break-system-packages
sudo pip install adafruit-circuitpython-servokit --break-system-packages
import time # Import time module to introduce delays in the program
import busio # Import busio module to set up I2C communication
from adafruit_motor import servo # Import servo module to control the servo motor
from adafruit_pca9685 import PCA9685 # Import PCA9685 module to interface with the PCA9685 PWM controller
from board import SCL, SDA # Import specific pins SCL and SDA for I2C communication
# Initialize I2C communication on the Raspberry Pi using the SCL and SDA pins.
# I2C 통신 활성화, 핀 설정 코드
i2c = busio.I2C(SCL, SDA)
# Create an instance of the PCA9685 class using the I2C communication.
# This instance will be used to control PWM signals, which are typically used for controlling servos.
# PCA9685 보드 I2C 주소 설정 코드 (변경방법은 아래 설명 참고)
pca = PCA9685(i2c)
# Set the PWM frequency to 50Hz, which is the standard frequency for controlling servo motors.
pca.frequency = 50
# Create a ContinuousServo object on channel 0 of the PCA9685.
# A continuous servo can rotate indefinitely in either direction based on the throttle value.
# PCA9685 보드에서 몇번째 핀에 연결된 서보모터를 제어할 것인지.
# 0 ~ 15 번까지 있다.
servo0 = servo.ContinuousServo(pca.channels[0])
# Set the throttle to full speed forward (1.0).
# Throttle value can range from -1.0 (full speed reverse) to 1.0 (full speed forward).
servo0.throttle = 1.0
# Keep the servo running at full speed for 3 seconds.
time.sleep(3)
# Stop the servo by setting the throttle to 0.0 (no movement).
servo0.throttle = 0.0
# Briefly sleep for 0.1 seconds to ensure the stop command is fully processed.
time.sleep(0.1)
# Deinitialize the PCA9685 to free up resources and reset the hardware.
# PCA9685 동작 종료 코드
pca.deinit()
PCA9685의 I2C 주소를 변경하고자 한다면 다음과 같이 변경한다.
pca = PCA9685(i2c)
# 이 원본 코드를 아래와 같이 수정한다.
pca = PCA9685(i2c, address=0x41)
#address = 에 이어서 보드에 설정한 값을 입력하면 된다.
다수의 서보모터를 사용할 경우 다음과 같이 코드를 변경한다.
servo0 = servo.ContinuousServo(pca.channels[0])
# 0번핀 (첫번째 핀)에 연결된 서보모터 0.
servo1 = servo.ContinuousServo(pca.channels[1])
# 1번핀 (두번째 핀)에 연결된 서보모터 1.
servo0 = servo.ContinuousServo(pca.channels[2])
# 2번핀 (세번째 핀)에 연결된 서보모터 2.
# ....
servo15 = servo.ContinuousServo(pca.channels[15])
# 15번핀 (열다섯번째 핀)에 연결된 서보모터 15.
# PCA9685에서 사용가능한 서보모터는 총 16개로 0번부터 15번까지 있다.
PCA 9685 메뉴얼
사용할 서보모터 규격.
20250302
서보모터를 각도로 제어하기 위해서 angle 함수를 사용하였다.
import time
import busio
from adafruit_motor import servo
from adafruit_pca9685 import PCA9685
from board import SCL, SDA
i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)
pca.frequency = 50
servo0 = servo.Servo(pca.channels[15])
servo0.set_pulse_width_range(330,2450)
servo0.actuation_range = 180
servo0.angle = 0
time.sleep(3)
servo0.angle = 90
time.sleep(3)
servo0.angle = 180
time.sleep(3)
pca.deinit()
서보모터를 anlge 함수로 제어하기 위해서는 서보모터의 최소 펄스와 최대 펄스를 설정해주어야 한다.
실험결과 내가 구입한 서보모터는 최소펄스 330일때 0도. 최대펄스 2450일때 180도로 움직인다.
actuation_range로 최대 각도를 변경해주었다. (기본값은 135도)
-----------
import time
import busio
from adafruit_motor import servo
from adafruit_pca9685 import PCA9685
from board import SCL, SDA
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)
pca.frequency = 50
ads = ADS.ADS1115(address=0x48, i2c=i2c)
channel = AnalogIn(ads, ADS.P0)
angleList = []
servo0 = servo.Servo(pca.channels[15])
servo0.set_pulse_width_range(330,2450)
servo0.actuation_range = 180
for deg in range(180) :
print(deg)
servo0.angle = deg
# 저장하고 싶은 타입을 사용
# angleList.append(channel.voltage)
# angleList.append(channel.value)
time.sleep(0.5)
print(angleList)
pca.deinit()
0 ~180도까지의 서보모터 저항값 리스트 생성 코드
-----------------------
가변저항의 전압값을 측정하여 리스트를 작성하였으나 실제로 동작시켰을때 정확하게 일치하는 경우는 적었다.
이에 측정된 전압값이 리스트의 값중에 가장 근접한 값의 인덱스를 반환하는 함수가 필요했다.
(아두이노에서는 map 함수를 사용하면 되서 편리해보였다.)
def findNearNum(exList, values):
answer = [0 for _ in range(2)] # answer 리스트 0으로 초기화
minValue = min(exList, key=lambda x:abs(x-values))
minIndex = exList.index(minValue)
answer[0] = minIndex
answer[1] = minValue
return answer
exList = [4, 10, 8, 32, 95]
values = 20.4213
returnList = findNearNum(exList, values)
print(returnList)
출처 : https://blog.naver.com/zzang9ha/222010163074
------
20도씩 회전시키면서 전압값으로 계산된 각도값과 비교하는 프로그램
import time
import busio
from adafruit_motor import servo
from adafruit_pca9685 import PCA9685
from board import SCL, SDA
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)
pca.frequency = 50
ads = ADS.ADS1115(address=0x48, i2c=i2c)
channel = AnalogIn(ads, ADS.P0)
servo0 = servo.Servo(pca.channels[15])
servo0.set_pulse_width_range(330,2450)
servo0.actuation_range = 180
angleList = [21416, 21416, 21417, 21493, 21446, 21370, 21269, 21205, 21104, 21038, 20974, 20852, 20793, 20736, 20628, 20569, 20521, 20409, 20354, 20285, 20173, 20105, 19980, 19938, 19879, 19745, 19747, 19643, 19541, 19479, 19396, 19310, 19227, 19168, 19069, 18998, 18890, 18852, 18796, 18666, 18623, 18552, 18437, 18378, 18351, 18205, 18176, 18086, 17983, 17931, 17814, 17752, 17697, 17570, 17513, 17451, 17349, 17292, 17238, 17129, 17066, 17002, 16880, 16811, 16719, 16668, 16593, 16495, 16441, 16350, 16261, 16189, 16120, 16004, 15943, 15870, 15771, 15778, 15623, 15576, 15481, 15382, 15329, 15261, 15153, 15089, 15019, 14937, 14863, 14800, 14697, 14627, 14512, 14446, 14391, 14257, 14259, 14152, 14061, 13991, 13930, 13839, 13757, 13716, 13594, 13522, 13429, 13376, 13292, 13199, 13113, 13072, 12961, 12902, 12796, 12702, 12645, 12576, 12469, 12423, 12342, 12266, 12170, 12087, 12026, 11945, 11830, 11793, 11720, 11621, 11554, 11494, 11380, 11322, 11254, 11154, 11082, 10964, 10973, 10844, 10757, 10686, 10636, 10528, 10463, 10398, 10291, 10221, 10178, 10054, 10005, 9893, 9834, 9763, 9663, 9591, 9516, 9438, 9359, 9296, 9194, 9120, 9073, 8973, 8901, 8811, 8745, 8660, 8580, 8508, 8454, 8348, 8297, 8206, 8118, 8056, 7970, 7880, 7800, 7709]
def findNearNum(exList, values):
answer = [0 for _ in range(2)] # answer 리스트 0으로 초기화
minValue = min(exList, key=lambda x:abs(x-values))
minIndex = exList.index(minValue)
answer = minIndex
return answer
servo0.angle = 0
time.sleep(5)
for i in range(0,200,20) :
servo0.angle = i
time.sleep(1)
print(channel.value)
print(findNearNum(angleList,channel.value))
20250305
서보모터를 손으로 동작시키기 위해서는 모터의 홀딩이 풀려야 되는데 모르겠다... 어떻게 해야 힘을 뺄수 있을까..