산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Asi(Anansi) 로봇 도우미

구성품 및 소모품

Arduino Nano R3
× 1
SG90 마이크로 서보 모터
× 1
MAX7219 적색 LED 도트 매트릭스 디스플레이 모듈
× 1
4xAA 배터리 홀더
리튬 이온 배터리 3.7 200mah도 작동
× 1
나사
× 1
투명 플라스틱 아크릴 목욕 폭탄 몰드 쉘
× 1
Adafruit Trinket - 미니 마이크로컨트롤러 - 5V 로직
× 1

필요한 도구 및 기계

3D 프린터(일반)
뜨거운 글루건(일반)

이 프로젝트 정보

이야기

이 프로젝트는 원래 Thingiverse의 Xpider였습니다. 그런 다음 Alex Glow의 아르키메데스를 말합니다. 그것은 내 마음을 날려 버렸어. 너무 싫었어요. 그래서 나는 스스로 로봇 동반자를 만드는 일을 해야 했다. 나는 내가 올빼미 유형이 아니라고 생각했고 나의 친숙한 사람이 특별하기를 원했습니다. 그러다가 거미, 사기꾼, 이야기의 신 아난시의 아프리카 이야기가 떠올랐다. 스토리라는 생각으로 봇을 디자인하기로 했고 그래서 Asi가 탄생했습니다(실제로는 Asi_v4, v1-3은 프로토타입).

어셈블리

원래 디자인은 Xpider였습니다. 그러나 나는 그것을 한 단계 더 끌어 올렸고 많은 것을 외부에서 편집했고 당신도 알다시피 땜질했습니다. 이것들은 인쇄해야 하는 대부분의 부품입니다.

조립은 꽤 자명하지만 어쨌든 여기에 몇 가지 사진이 있습니다.

전자 제품의 경우 일반적으로 머리의 위쪽이나 아래쪽에 둘 수 있지만(귀하의 호출) 서보는 그렇게 부착해야 합니다. 기어가 켜져 있는지 확인하십시오.

Asi는 Trinket과 Arduino Nano의 두 가지 마이크로 컨트롤러로 제어됩니다. Trinket은 임의의 간격으로 앞뒤로 회전하는 서보 덕분에 눈의 움직임을 제어합니다. Arduino Nano는 눈을 제어합니다. 그가 주위를 둘러보는 것도 무작위적이며 보통 사람들은 그가 그들을 보고 있다고 생각합니다.

참고로 저는 4x AA 배터리로 데이지 체인으로 연결된 두 개의 작은 브레드보드에 있습니다. (리튬 이온 배터리 3.7 200mAh를 사용할 수도 있습니다. 리튬 이온 배터리의 경우 어떤 이유로 작동하지 않는 경우가 있으므로 별도의 리튬 배터리 2개를 사용하여 동일한 온오프 스위치에 부착합니다. 모든 것이 한 번에 시작됩니다.)

머리는 내가 휴가 동안 얻은 크리스마스 구체입니다. 나는 한 발 물러서서 검은 색 스프레이 페인트로 가볍게 뿌렸다. 그런 다음 뜨거운 접착제를 가져다가 Asi의 목 부분에 붙이면 머리가 붐!

마지막으로 착용 방법입니다. 전기자 철사를 가져와서 Asi 바닥 부분 전체에 꿰어 배낭의 어깨에 메었습니다.

<섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

코드

<울>
  • 아시 아이
  • 장신구와 아시 넥
  • 아시 아이 Arduino
    Asi eye용 코드
    #include //항상 LedControl 라이브러리를 포함해야 합니다.#include "LedControl.h"/* LetControl 객체를 생성하고 핀 연결을 정의합니다. 눈에는 2개의 MAX72XX가 있습니다. */#define PIN_EYES_DIN 12#define PIN_EYES_CS 11#define PIN_EYES_CLK 10LedControl lc =LedControl(PIN_EYES_DIN, PIN_EYES_CLK, PIN_EYES_CS, 2);// rotationbool rotateMatrix0 =false; // 0 행렬을 180도 회전합니다. degbool rotateMatrix1 =false; // 180도만큼 회전하는 현재 상태 저장// 퓨필 바이트 없이 안구 정의 eyeBall[8]={ B01111110, B11111111, B11111111, B11111111, B11111111, B11111111, B0110101; LEDsbyte eyeCurrent[8];int currentX;int currentY;int cntLoop =0;int cntEffect =0;// 최소 및 최대 위치#define MIN -2#define MAX 2// delays#define DELAY_BLINK 40// 마다 효과 수행 루프 반복 횟수, 0에서 비활성화#define EFFECT_ITERATION 4/* Arduino setup*/void setup() { // MAX72XX는 시작 시 절전 모드에 있으므로 웨이크업 호출을 수행해야 합니다. lc.shutdown(0,false); lc.shutdown(1,거짓); // 밝기를 낮게 설정 lc.setIntensity(0,1); lc.setIntensity(1,1); // 두 모듈 모두 지우기 lc.clearDisplay(0); lc.clearDisplay(1); // LED 테스트 // 세로줄 바이트 b =B10000000; for (int c=0; c<=7; c++) { for (int r=0; r<=7; r++) { setRow(0, r, b); setRow(1, r, b); } b =b>> 1; 지연(50); } // 전체 모듈 b =B11111111; (int r=0; r<=7; r++) { setRow(0, r, b); setRow(1, r, b); } 지연(500); // 두 모듈 모두 지우기 lc.clearDisplay(0); lc.clearDisplay(1); 지연(500); // 랜덤 시드 randomSeed(analogRead(0)); // 중심 눈, 미친듯이 깜박임 displayEyes(0, 0); 지연(2000); 깜박임 눈(참, 거짓); 깜박임(거짓, 참); delay(1000);}/* Arduino loop*/void loop() { // 임의의 위치로 이동하고 임의의 시간을 기다립니다. moveEyes(random(MIN, MAX + 1), random(MIN, MAX + 1), 50); 지연(무작위(5, 7) * 500); // 깜박임 시간? if (random(0, 5) ==0) { delay(500); 눈 깜박임(); 지연(500); } // 효과 시간? if (EFFECT_ITERATION> 0) { cntLoop++; if (cntLoop ==EFFECT_ITERATION) { cntLoop =0; if (cntEffect> 6) cntEffect =0; switch(cntEffect) { case 0:// 교차 눈 crossEyes(); 지연(1000); 부서지다; 사례 1:// 라운드 스핀 roundSpin(2); 지연(1000); 부서지다; 사례 2:// 미친 회전 crazySpin(2); 지연(1000); 부서지다; 사례 3:// meth 눈 methEyes(); 지연(1000); 부서지다; 사례 4:// 게으른 눈 lazyEye(); 지연(1000); 부서지다; 사례 5:// 미친 깜박임 깜박임 눈(true, false); 깜박임(거짓, 참); 지연(1000); 부서지다; 사례 6:// 글로우 glowEyes(3); 지연(1000); 부서지다; 기본값:중단; } cntEffect++; } }}/* 이 메서드는 두 눈을 모두 깜박입니다.*/void 깜박임Eyes(){ 깜박임(true, true);}/* 이 메서드는 제공된 매개변수에 따라 눈을 깜박입니다.*/void 깜박임Eyes(boolean blinkLeft, boolean blinkRight){ // 깜박임 ? if (!blinkLeft &&!blinkRight) return; // 눈꺼풀을 감습니다. for (int i=0; i<=3; i++) { if (blinkLeft) { setRow(0, i, 0); setRow(0, 7-i, 0); } if (blinkRight) { setRow(1, i, 0); setRow(1, 7-i, 0); } 지연(DELAY_BLINK); } // 눈꺼풀을 엽니다 for (int i=3; i>=0; i--) { if (blinkLeft) { setRow(0, i, eyeCurrent[i]); setRow(0, 7-i, eyeCurrent[7-i]); } if (blinkRight) { setRow(1, i, eyeCurrent[i]); setRow(1, 7-i, eyeCurrent[7-i]); } 지연(DELAY_BLINK); }}/* 이 메서드는 눈을 중앙 위치로 이동한 다음 가장자리를 감싸면서 수평으로 이동합니다.*/void crazySpin(int times){ if (times ==0) return; moveEyes(0, 0, 50); 지연(500); 바이트 행 =eyePupil; for (int t=0; t> 1; 행 =행 | B10000000; setRow(0, 3, 행); setRow(1, 3, 행); setRow(0, 4, 행); setRow(1, 4, 행); 지연(50); if (t ==0) 지연((5-i)*10); // 첫 번째 스크롤 시 지연 증가(속도 향상 효과) } // R에서 중심으로 회전 for (int i=0; i<5; i++) { row =row>> 1; if (i>=2) 행 =행 | B10000000; setRow(0, 3, 행); setRow(1, 3, 행); setRow(0, 4, 행); setRow(1, 4, 행); 지연(50); if (t ==(times-1)) 지연((i+1)*10); // 마지막 스크롤 시 지연 증가(느림 효과) } }}/* 이 메서드는 눈을 가립니다.*/void crossEyes(){ moveEyes(0, 0, 50); 지연(500); 바이트 눈동자R =eyePupil; 바이트 동공L =눈동공; // 동공을 함께 이동 for (int i=0; i<2; i++) { 동공 =동공>> 1; 동공R =동공R | B10000000; 동공 =동공 <<1; 동공 =동공 | B1; setRow(0, 3, 동공R); setRow(1, 3, 동공L); setRow(0, 4, 동공R); setRow(1, 4, 동공L); 지연(100); } 지연(2000); // 동공을 중앙으로 다시 이동 for (int i=0; i<2; i++) { 동공 =동공 <<1; 동공R =동공R | B1; 동공 =동공L>> 1; 동공 =동공 | B10000000; setRow(0, 3, 동공R); setRow(1, 3, 동공L); setRow(0, 4, 동공R); setRow(1, 4, 동공L); 지연(100); }}/* 이 메서드는 중심 위치에서 X, Y 값만큼 동공 오프셋이 있는 안구를 표시합니다. 유효한 X 및 Y 범위는 [MIN,MAX]입니다. 두 LED 모듈 모두 동일한 눈을 표시합니다.*/void displayEyes(int offsetX, int offsetY) { // 오프셋이 유효한 범위에 있는지 확인합니다. offsetX =getValidValue(offsetX); 오프셋Y =getValidValue(오프셋Y); // 동공 행에 대한 인덱스 계산(오프셋 Y 수행) int row1 =3 - offsetY; int row2 =4 - 오프셋 Y; // 동공 행 바이트를 정의합니다.pupilRow =eyePupil; // 오프셋 X를 수행합니다. // 비트 이동을 수행하고 새 비트를 1로 채웁니다. if (offsetX> 0) { for (int i=1; i<=offsetX; i++) { pupilRow =pupilRow>> 1; 동공 =동공 | B10000000; } } else if (offsetX <0) { for (int i=-1; i>=offsetX; i--) { 동공 =동공 <<1; 동공 =동공 | B1; } } // 눈동자 행은 1을 가질 수 없습니다. 여기서 eyeBall의 바이트는 0입니다. PupilRow1 =눈동자 Row &eyeBall[row1]; 바이트 눈동자Row2 =눈동자 및 눈볼[row2]; // LCD 매트릭스에 표시, eyeCurrent로 업데이트 for(int r=0; r<8; r++) { if (r ==row1) { setRow(0, r, 눈동자Row1); setRow(1, r, 동공1); 눈 현재[r] =눈동자 행1; } else if (r ==row2) { setRow(0, r, 눈동자Row2); setRow(1, r, 동공2); 눈 현재[r] =눈동자 행2; } else { setRow(0, r, eyeBall[r]); setRow(1, r, eyeBall[r]); eyeCurrent[r] =eyeBall[r]; } } // 현재 X 및 Y 업데이트 currentX =offsetX; currentY =offsetY;}/* 이 메서드는 제공된 좌표 값을 수정합니다.*/int getValidValue(int value){ if (value> MAX) return MAX; 그렇지 않으면 (값 =1; i--) { lc.setIntensity(0,i); lc.setIntensity(1,i); 지연(25); } 지연(150); }}/* 이 메서드는 눈을 가운데로 이동했다가 바깥쪽으로 이동했다가 다시 가운데로 이동합니다.*/void methEyes(){ moveEyes(0, 0, 50); 지연(500); 바이트 눈동자R =eyePupil; 바이트 동공L =눈동공; // 동공을 밖으로 이동 for (int i=0; i<2; i++) { 동공 =동공 <<1; 동공R =동공R | B1; 동공 =동공L>> 1; 동공 =동공 | B10000000; setRow(0, 3, 동공R); setRow(1, 3, 동공L); setRow(0, 4, 동공R); setRow(1, 4, 동공L); 지연(100); } 지연(2000); // 동공을 다시 중앙으로 이동 for (int i=0; i<2; i++) { 동공 =동공>> 1; 동공R =동공R | B10000000; 동공 =동공 <<1; 동공 =동공 | B1; setRow(0, 3, 동공R); setRow(1, 3, 동공L); setRow(0, 4, 동공R); setRow(1, 4, 동공L); 지연(100); }}/* 이 메서드는 두 눈을 현재 위치에서 새 위치로 이동합니다.*/void moveEyes(int newX, int newY, int stepDelay){ // 현재 위치를 시작 위치로 설정 int startX =currentX; 정수 시작Y =현재Y; // 유효하지 않은 새 XY 값 수정 newX =getValidValue(newX); newY =getValidValue(newY); // 단계 평가 int stepsX =abs(currentX - newX); int stepsY =abs(현재Y - 새Y); // 적어도 하나의 위치를 ​​변경해야 함 if ((stepsX ==0) &&(stepsY ==0)) return; // 이동 ​​방향 평가, 단계 수, XY 단계마다 변경, 이동 수행 int dirX =(newX>=currentX) ? 1:-1; int dirY =(newY>=현재Y) ? 1:-1; int 단계 =(단계 X> 단계 Y) ? 단계X :단계Y; int intX, intY; float changeX =(float)stepsX / (float)steps; float 변경Y =(float)stepsY / (float)steps; for (int i=1; i<=steps; i++) { intX =startX + round(changeX * i * dirX); intY =startY + round(changeY * i * dirY); displayEyes(intX, intY); 지연(단계지연); }}/* 이 메서드는 오른쪽 눈동자만 낮추고 올립니다.*/void lazyEye(){ moveEyes(0, 1, 50); 지연(500); // 왼쪽 아래 동공을 천천히 for (int i=0; i<3; i++) { setRow(1, i+2, eyeBall[i+2]); setRow(1, i+3, eyeBall[i+3] &eyePupil); setRow(1, i+4, eyeBall[i+4] &eyePupil); 지연(150); } 지연(1000); // 왼쪽 눈동자를 빠르게 올리기 for (int i=0; i<3; i++) { setRow(1, 4-i, eyeBall[4-i] &eyePupil); setRow(1, 5-i, eyeBall[5-i] &eyePupil); setRow(1, 6-i, eyeBall[6-i]); 지연(25); } }/* 이 메서드는 눈동자를 시계 방향으로 회전합니다.*/void roundSpin(int times){ if (times ==0) return; moveEyes(2, 0, 50); 지연(500); for (int i=0; i<번; i++) { displayEyes(2, -1); 지연(40); if (i==0) 지연(40); displayEyes(1, -2); 지연(40); if (i==0) 지연(30); displayEyes(0, -2); 지연(40); if (i==0) 지연(20); displayEyes(-1, -2); 지연(40);만약 (i==0) 지연(10); displayEyes(-2, -1); 지연(40); displayEyes(-2, 0); 지연(40); displayEyes(-2, 1); 지연(40);if (i==(배-1)) 지연(10); displayEyes(-1, 2); 지연(40);if (i==(배-1)) 지연(20); displayEyes(0, 2); 지연(40); if (i==(times-1)) 지연(30); displayEyes(1, 2); 지연(40); if (i==(times-1)) 지연(40); displayEyes(2, 1); 지연(40); if (i==(times-1)) 지연(50); displayEyes(2, 0); 지연(40); }}/* 이 메소드는 행렬 행에 값을 설정합니다. 필요한 경우 180 회전을 수행합니다.*/void setRow(int addr, int row, byte rowValue){ if (((addr ==0) &&(rotateMatrix0)) || (addr ==1 &&회전 매트릭스1)) { 행 =abs(행 - 7); rowValue =비트스왑(rowValue); } lc.setRow(addr, row, rowValue);}/* 바이트 단위의 역 비트 http://www.nrtm.org/index.php/2013/07/25/reverse-bits-in-a-byte/* /byte bitswap (byte x){ 바이트 결과; asm("mov __tmp_reg__, %[in] \n\t" "lsl __tmp_reg__ \n\t" /* 높은 비트를 캐리로 시프트 */ "ror %[out] \n\t" /* 캐리 __tmp_reg__를 로우로 회전 비트 (결국) */ "lsl __tmp_reg__ \n\t" /* 2 */ "ror %[out] \n\t" "lsl __tmp_reg__ \n\t" /* 3 */ "ror %[out] \ n\t" "lsl __tmp_reg__ \n\t" /* 4 */ "ror %[out] \n\t" "lsl __tmp_reg__ \n\t" /* 5 */ "ror %[out] \n\ t" "lsl __tmp_reg__ \n\t" /* 6 */ "ror %[out] \n\t" "lsl __tmp_reg__ \n\t" /* 7 */ "ror %[out] \n\t" "lsl __tmp_reg__ \n\t" /* 8 */ "ror %[out] \n\t" :[out] "=r" (결과) :[in] "r" (x)); 반환(결과);}
    장신구가 있는 Asi Neck Arduino
    이것이 내가 Asi 목이 앞뒤로 움직이는지 확인하는 데 사용하는 것입니다.
     // Servo 매개변수입니다. 핀은 장신구에서 1 또는 4여야 합니다. 서보 위치는 // 원시 타이머/카운터 틱(1 틱 =0.128 밀리초)으로 지정됩니다. // 서보 펄스 타이밍은 일반적으로 1-2ms이지만 서보 간에 약간 다를 수 있으므로 이러한 제한을 조정해야 할 수도 있습니다. 현실과 일치합니다.#define SERVO_PIN 4 // 핀 1 또는 4는 Trinket에서 지원됩니다#define SERVO_MIN 4 // ~1ms 펄스#define SERVO_MAX 26 // ~2ms 펄스 Adafruit_TiCoServo 서보; void setup(void) {#if (F_CPU ==16000000L) // 16MHz Trinket은 정확한 타이밍을 위해 프리스케일을 설정해야 합니다. // 이것은 서보.attach() 전에 수행되어야 합니다! clock_prescale_set(clock_div_1);#endifservo.attach(SERVO_PIN); 핀모드(LED_PIN, 출력); digitalWrite(LED_PIN, HIGH);} uint32_t lastLookTime =0; // 마지막 헤드 턴 시간 void loop(void) { unsigned long t =millis(); // 현재 시간 // 마지막 머리 회전 이후 1/2초 이상 경과한 경우... if((t - lastLookTime)> 500) { if(random(10) ==0) { // 1- in-10 기회... // ...머리를 새로운 방향으로 무작위로 이동:서보.write(random(SERVO_MIN, SERVO_MAX)); 마지막보기 시간 =t; // 앞으로의 참조를 위해 헤드 턴 시간을 저장합니다. } } // 헤드 턴 검사와 관련이 없습니다. if(random(10) ==0) { // 10분의 1의 확률이 있습니다... // .. ."눈 깜박임":digitalWrite(LED_PIN, LOW); // LED 꺼짐 delay(random(50, 250)); // 임의의 짧은 순간 동안 digitalWrite(LED_PIN, HIGH); // 다시 ON } delay(100); // loop()를 초당 10회 정도 반복}

    맞춤형 부품 및 인클로저

    실제 다리 끝 부분서보용 터너 기어를 추가하는 것을 잊었습니다. 보통 인쇄하여 가운데에 서보 부착물을 끼운 다음 서보 본체에 나사로 고정합니다. Asi 헤드를 회전시키는 데 사용되는 기어 서보 나사와 함께 사용하는 것이 좋습니다. 서보 피스를 사용하여 asi GearAsi 넥 플레이트용 서보의 Asithe 홀더 중간 파이스에 놓는 것이 좋습니다. 여기가 아크릴 구가 접착되는 곳입니다. 목

    회로도

    Asi Neck에 사용한 회로 이것은 내가 Asi를 시작하는 데 사용한 것입니다. 작은 회로 기판에서 둘 다에 전원을 공급하기 위해 데이지 체인으로 연결할 수 있습니다.

    제조공정

    1. Arduino+Raspberry Pi 로봇 플랫폼을 만드는 방법
    2. 라즈베리 파이 CD 상자 로봇
    3. PiCy – 작은 Raspberry Pi 구동 로봇!
    4. 구르는 알람 로봇
    5. Minecraft 크리퍼 로봇 제작
    6. 아르키메데스:AI 로봇 올빼미
    7. CV 로봇 열기
    8. ROS 로봇
    9. 간단한 파이 로봇
    10. 음료 로봇이란?