로버를 제작하고 블링크로 연결한 후, 픽시캠을 추가하여 개선하기로 했습니다. 배터리 홀더를 앞쪽으로 이동하여 팬/틸트 카메라를 장착했습니다.
픽시캠 (PixyCam)
픽시캠은 로봇 비전을 쉽게 만듭니다. 픽시는 DIY 로봇용 고속 비전 센서로, 버튼만 누르면 물체를 학습시킬 수 있습니다. 수백 개의 물체를 동시에 추적할 수 있으며 추적 중인 데이터만 제공합니다.
주황색 호박을 추적 대상으로 정했습니다.
시작하기가 얼마나 쉬운지 놀랍습니다. 아두이노에 픽시캠 연결 지침과 팬/틸트 메커니즘 조립 지침이 있습니다. 그림이 많아 매우 따라하기 쉽습니다. 설정 및 빌드 지침, 아두이노 통합 방법을 따라하고 예제를 테스트했습니다.
픽시캠 아두이노 API
아두이노에서 픽시 사용은 매우 간단합니다. SPI와 픽시 헤더를 포함하기만 하면 됩니다:
#include <SPI.h>
#include <Pixy.h>
그리고 setup()과 loop() 함수 밖에 전역 인스턴스를 생성합니다:
Pixy pixy;
아두이노 라이브러리에서 가장 중요한 메서드는 getBlocks()로, 픽시가 감지한 물체 수를 반환합니다. pixy.blocks[] 배열에서 각 감지된 물체에 대한 정보(감지된 물체당 배열 멤버 하나)를 확인할 수 있습니다. 각 배열 멤버(i)에는 다음 필드가 포함됩니다:
pixy.blocks[i].signature - 감지된 물체의 시그니처 번호 (일반 시그니처의 경우 1-7)
pixy.blocks[i].x - 감지된 물체 중심의 x 좌표 (0~319)
pixy.blocks[i].y - 감지된 물체 중심의 y 좌표 (0~199)
pixy.blocks[i].width - 감지된 물체 너비 (1~320)
pixy.blocks[i].height - 감지된 물체 높이 (1~200)
pixy.blocks[i].angle - 색상 코드인 경우 감지된 물체의 각도
pixy.blocks[i].print() - 감지된 물체 정보를 시리얼 포트로 출력하는 멤버 함수
아두이노로 픽시와 통신하는 것이 이처럼 간단합니다! 아두이노 라이브러리와 API에 대한 자세한 내용은 여기를 참조하세요. 로버에 사용된 코드는 다음과 같습니다. 원래 BLE 코드를 수정하고 물체 추적 기능을 추가했습니다. 설정 중:
void setup() {
.....
pixy.init();
....
}
메인 루프는 대략 다음과 같습니다:
void loop() {
......
// 픽시 데이터 읽기 및 블록 가져오기
static int i = 0;
int j;
uint16_t blocks;
char buf[32];
int32_t panError, tiltError;
blocks = pixy.getBlocks();
// 블록이 있는 경우
if (blocks) {
panError = X_CENTER - pixy.blocks[0].x;
tiltError = pixy.blocks[0].y - Y_CENTER;
panLoop.updatePan(panError);
tiltLoop.update(tiltError);
pixy.setServos(panLoop.m_pos, tiltLoop.m_pos);
i++;
// 프레임이 아두이노 속도를 늦추지 않도록 10프레임마다 처리
if (i % 10 == 0) {
int trackedBlock = 0;
sprintf(buf, "Detected %d:\n", blocks);
Serial.print(buf);
long maxSize = 0;
for (j = 0; j < blocks; j++) {
sprintf(buf, " block %d: ", j);
Serial.print(buf);
pixy.blocks[j].print();
long newSize = pixy.blocks[j].height * pixy.blocks[j].width;
if (newSize > maxSize) {
trackedBlock = j;
maxSize = newSize;
}
}
int32_t followError = RCS_CENTER_POS - panLoop.m_pos;
// 크기는 물체 면적. 최근 8개의 이동 평균 유지
size += pixy.blocks[trackedBlock].width * pixy.blocks[trackedBlock].height;
size -= size >> 3;
int forwardSpeed = constrain(400 - (size / 256), -100, 400);
int32_t differential = (followError + (followError * forwardSpeed)) >> 8;
int leftSpeed = constrain(forwardSpeed + differential, -400, 400);
int rightSpeed = constrain(forwardSpeed - differential, -400, 400);
motor1->setSpeed(leftSpeed);
motor3->setSpeed(leftSpeed);
motor2->setSpeed(rightSpeed);
motor4->setSpeed(rightSpeed);
double width = pixy.blocks[trackedBlock].width;
if (width <= 5) {
} else if (width < 20 && !running) {
Serial.println("running");
motor1->run(FORWARD);
motor3->run(FORWARD);
motor2->run(FORWARD);
motor4->run(FORWARD);
running = true;
} else if (width > 80 && !running) {
Serial.println("running");
motor1->run(BACKWARD);
motor3->run(BACKWARD);
motor2->run(BACKWARD);
motor4->run(BACKWARD);
running = true;
} else if (width >= 20 && width <= 80 && running) {
motor1->setSpeed(128);
motor2->setSpeed(128);
motor3->setSpeed(128);
motor4->setSpeed(128);
motor2->run(RELEASE);
motor4->run(RELEASE);
motor1->run(RELEASE);
motor3->run(RELEASE);
running = false;
}
}
}
}
픽시캠이 로버를 제어하지 않고 블링크만 실행하려면 렌즈 캡을 씌우세요. 그러면 픽시캠이 간섭하지 않습니다. 이 프로젝트가 아두이노 프로그래밍이나 다음 프로젝트에서 픽시캠 사용에 관심이 생기게 했다면 "프로젝트 존중" 버튼을 누르고 팔로우해 주세요.