回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

【Arduino 动手做】Anansi:一个很酷的蜘蛛状机器人 简单

头像 驴友花雕 2025.06.18 2 0

这个项目最初是来自 Thingiverse 的 Xpider。然后我说 Alex Glow 的 Archimedes。这让我大吃一惊。我非常想要一个。所以,我开始研究自己的机器人伴侣。我觉得我不是一个猫头鹰类型的人,我希望我的佣兽是特别的。然后我想起了蜘蛛 Anansi 的非洲故事,他是骗子和故事之神。我决定用故事的想法来设计这个机器人,因此 Asi 诞生了(实际上是 Asi_v4,v1-3 是原型)。

集会
最初的设计是 Xpider,但我把它提升了一个档次,通过门外的很多东西编辑了很多东西,你知道的修补。这些是您必须打印的大部分零件。

组装是不言自明的,但无论如何这里有一些照片。

对于电子设备,您通常可以将它们放在头部的顶部或底部(您的调用),但必须按原样连接伺服器。请确保装备在上面。

Asi 由两个微控制器控制,一个 Trinket 和一个 Arduino Nano。Trinket 控制眼睛的运动,多亏了伺服器,它以随机的间隔来回转动。Arduino Nano 控制眼睛。当他环顾四周时,这也是随机的,通常人们认为他在看他们。

请注意,我将它们放在两个小面包板上,这些面包板用 4 节 AA 电池菊花链连接。(您也可以使用锂离子电池 3.7 200mAh。使用锂电池时,由于某种原因它有时无法正常工作,因此我会使用两节单独的锂电池并将它们连接到同一个开关上,以便一切立即开始。

这个头只是我在假期里得到的一个圣诞球。我后退一步,轻轻地喷上了黑色喷漆。然后取一些热胶,粘在 Asi 的脖子上,BOOM 就有了头!

最后,我怎么穿它。我只是拿了一些电枢线,把它串在 Asi 底部的整体上,然后将它们缠绕在我背包的肩包上。

01.jpg
02.jpg
03.jpg
03-.jpg
04.jpg
04-.jpg
05.jpg
06.jpg
06-.jpg
06-0.jpg
06-9.jpg
07.jpg

07_max7219_fig_02_96dpi_xiNLBFraIz.jpg
leds_circuit-diagram_KSpTypq1XD.jpg

项目代码

代码
#include <LedControl.h>

//We always have to include the LedControl library
#include "LedControl.h"

/*
 Create LetControl object, define pin connections
 We have 2 MAX72XX for eyes.
 */
#define PIN_EYES_DIN 12
#define PIN_EYES_CS 11
#define PIN_EYES_CLK 10
LedControl lc = LedControl(PIN_EYES_DIN, PIN_EYES_CLK, PIN_EYES_CS, 2);

// rotation
bool rotateMatrix0 = false;  // rotate 0 matrix by 180 deg
bool rotateMatrix1 = false;  // rotate 1 matrix by 180 deg

// define eye ball without pupil  
byte eyeBall[8]={
  B00111100,
  B01111110,
  B11111111,
  B11111111,
  B11111111,
  B11111111,
  B01111110,
  B00111100
};

byte eyePupil = B11100111;

// stores current state of LEDs
byte eyeCurrent[8];
int currentX;
int currentY;
int cntLoop = 0;
int cntEffect = 0;

// min and max positions
#define MIN -2
#define MAX  2

// delays
#define DELAY_BLINK 40

// perform an effect every # of loop iterations, 0 to disable
#define EFFECT_ITERATION 4

/*
  Arduino setup
*/
void setup() 
{
  // MAX72XX is in power-saving mode on startup, we have to do a wakeup call
  lc.shutdown(0,false);
  lc.shutdown(1,false);

  // set the brightness to low
  lc.setIntensity(0,1);
  lc.setIntensity(1,1);

  // clear both modules
  lc.clearDisplay(0);
  lc.clearDisplay(1);
 
  // LED test
  // vertical line
  byte 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;
    delay(50);
  }
  // full module
  b = B11111111;
  for (int r=0; r<=7; r++)
  {
    setRow(0, r, b);
    setRow(1, r, b);
  }
  delay(500);
  
   // clear both modules
  lc.clearDisplay(0);
  lc.clearDisplay(1);
  delay(500);

  // random seed
  randomSeed(analogRead(0));
 
  // center eyes, crazy blink
  displayEyes(0, 0);
  delay(2000);
  blinkEyes(true, false);
  blinkEyes(false, true);
  delay(1000);

}

/*
  Arduino loop
*/
void loop() 
{ 
  // move to random position, wait random time
  moveEyes(random(MIN, MAX + 1), random(MIN, MAX + 1), 50);
  delay(random(5, 7) * 500);
  
  // blink time?
  if (random(0, 5) == 0)
  {
    delay(500);
    blinkEyes();
    delay(500);
  }
  
  // effect time?
  if (EFFECT_ITERATION > 0)
  {
    cntLoop++;
    if (cntLoop == EFFECT_ITERATION)
    {
      cntLoop = 0;
      if (cntEffect > 6) cntEffect = 0;
      switch(cntEffect)
      {
        case 0: // cross eyes
          crossEyes();
          delay(1000);
          break;
    
        case 1: // round spin
          roundSpin(2);
          delay(1000);
          break;
        
        case 2: // crazy spin
          crazySpin(2);
          delay(1000);
          break;
        
        case 3: // meth eyes
          methEyes();
          delay(1000);
          break;
                
        case 4: // lazy eye
          lazyEye();
          delay(1000);
          break;
          
        case 5: // crazy blink
          blinkEyes(true, false);
          blinkEyes(false, true);
          delay(1000);
          break;

        case 6: // glow
          glowEyes(3);
          delay(1000);
          break;

        default: 
          break;
      }
      cntEffect++;
    }
  }
}

/*
  This method blinks both eyes
*/
void blinkEyes()
{
  blinkEyes(true, true);
}

/*
  This method blinks eyes as per provided params
*/
void blinkEyes(boolean blinkLeft, boolean blinkRight)
{
  // blink?
  if (!blinkLeft && !blinkRight)
    return;
  
  // close eyelids
  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(DELAY_BLINK);
  }
  
  // open eyelids
  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(DELAY_BLINK);
  }
}

/*
  This methods moves eyes to center position, 
  then moves horizontally with wrapping around edges.
*/
void crazySpin(int times)
{
  if (times == 0)
    return;
  
  moveEyes(0, 0, 50);
  delay(500);
  
  byte row = eyePupil;
  for (int t=0; t<times; t++)
  {
    // spin from center to L
    for (int i=0; i<5; i++)
    {
      row = row >> 1;
      row = row | B10000000;
      setRow(0, 3, row);  setRow(1, 3, row);  
      setRow(0, 4, row);  setRow(1, 4, row);
      delay(50); 
      if (t == 0) 
        delay((5-i)*10); // increase delay on 1st scroll (speed up effect)
    }
    // spin from R to center
    for (int i=0; i<5; i++)
    {
      row = row >> 1;
      if (i>=2) 
        row = row | B10000000;
      setRow(0, 3, row);  setRow(1, 3, row);  
      setRow(0, 4, row);  setRow(1, 4, row);
      delay(50);
      if (t == (times-1)) 
        delay((i+1)*10); // increase delay on last scroll (slow down effect)
    }
  }
}

/*
  This method crosses eyes
*/
void crossEyes()
{
  moveEyes(0, 0, 50);
  delay(500);

  byte pupilR = eyePupil;  
  byte pupilL = eyePupil;
  
  // move pupils together
  for (int i=0; i<2; i++)
  {
    pupilR = pupilR >> 1;
    pupilR = pupilR | B10000000;
    pupilL = pupilL << 1;
    pupilL = pupilL | B1;
    
    setRow(0, 3, pupilR); setRow(1, 3, pupilL);
    setRow(0, 4, pupilR); setRow(1, 4, pupilL);
    
    delay(100);
  }
  
  delay(2000);
  
  // move pupils back to center
  for (int i=0; i<2; i++)
  {
    pupilR = pupilR << 1;
    pupilR = pupilR | B1;
    pupilL = pupilL >> 1;
    pupilL = pupilL | B10000000;
    
    setRow(0, 3, pupilR); setRow(1, 3, pupilL);
    setRow(0, 4, pupilR); setRow(1, 4, pupilL);
    
    delay(100);
  }
}

/*
  This method displays eyeball with pupil offset by X, Y values from center position.
  Valid X and Y range is [MIN,MAX]
  Both LED modules will show identical eyes
*/
void displayEyes(int offsetX, int offsetY) 
{
  // ensure offsets are  in valid ranges
  offsetX = getValidValue(offsetX);
  offsetY = getValidValue(offsetY);
  
  // calculate indexes for pupil rows (perform offset Y)
  int row1 = 3 - offsetY;
  int row2 = 4 - offsetY;

  // define pupil row
  byte pupilRow = eyePupil;

  // perform offset X
  // bit shift and fill in new bit with 1 
  if (offsetX > 0) {
    for (int i=1; i<=offsetX; i++)
    {
      pupilRow = pupilRow >> 1;
      pupilRow = pupilRow | B10000000;
    }
  }
  else if (offsetX < 0) {
    for (int i=-1; i>=offsetX; i--)
    {
      pupilRow = pupilRow << 1;
      pupilRow = pupilRow | B1;
    }
  }

  // pupil row cannot have 1s where eyeBall has 0s
  byte pupilRow1 = pupilRow & eyeBall[row1];
  byte pupilRow2 = pupilRow & eyeBall[row2];
  
  // display on LCD matrix, update to eyeCurrent
  for(int r=0; r<8; r++)
  {
    if (r == row1)
    {
      setRow(0, r, pupilRow1);
      setRow(1, r, pupilRow1);
      eyeCurrent[r] = pupilRow1;
    }
    else if (r == row2)
    {
      setRow(0, r, pupilRow2);
      setRow(1, r, pupilRow2);
      eyeCurrent[r] = pupilRow2;
    }
    else
    {
      setRow(0, r, eyeBall[r]);
      setRow(1, r, eyeBall[r]);
      eyeCurrent[r] = eyeBall[r];
    }
  }
  
  // update current X and Y
  currentX = offsetX;
  currentY = offsetY;
}

/*
  This method corrects provided coordinate value
*/
int getValidValue(int value)
{
  if (value > MAX)
    return MAX;
  else if (value < MIN)
    return MIN;
  else
    return value;
}

/*
  This method pulsates eye (changes LED brightness)
*/
void glowEyes(int times)
{
  for (int t=0; t<times; t++)
  {
    for (int i=2; i<=8; i++)
    {
      lc.setIntensity(0,i);
      lc.setIntensity(1,i);
      delay(50);
    }

    delay(250);

    for (int i=7; i>=1; i--)
    {
      lc.setIntensity(0,i);
      lc.setIntensity(1,i);
      delay(25);
    }

    delay(150);
  }
}

/*
  This method moves eyes to center, out and then back to center
*/
void methEyes()
{
  moveEyes(0, 0, 50);
  delay(500);

  byte pupilR = eyePupil;  
  byte pupilL = eyePupil;

  // move pupils out
  for (int i=0; i<2; i++)
  {
    pupilR = pupilR << 1;
    pupilR = pupilR | B1;
    pupilL = pupilL >> 1;
    pupilL = pupilL | B10000000;
    
    setRow(0, 3, pupilR); setRow(1, 3, pupilL);
    setRow(0, 4, pupilR); setRow(1, 4, pupilL);
    
    delay(100);
  }

  delay(2000);
  
  // move pupils back to center
  for (int i=0; i<2; i++)
  {
    pupilR = pupilR >> 1;
    pupilR = pupilR | B10000000;
    pupilL = pupilL << 1;
    pupilL = pupilL | B1;
    
    setRow(0, 3, pupilR); setRow(1, 3, pupilL);
    setRow(0, 4, pupilR); setRow(1, 4, pupilL);
    
    delay(100);
  }
}

/*
  This method moves both eyes from current position to new position
*/
void moveEyes(int newX, int newY, int stepDelay)
{
  // set current position as start position
  int startX = currentX;
  int startY = currentY;
  
  // fix invalid new X Y values
  newX = getValidValue(newX);
  newY = getValidValue(newY);
  
  // eval steps
  int stepsX = abs(currentX - newX);
  int stepsY = abs(currentY - newY);

  // need to change at least one position
  if ((stepsX == 0) && (stepsY == 0))
    return;
   
  // eval direction of movement, # of steps, change per X Y step, perform move
  int dirX = (newX >= currentX) ? 1 : -1;
  int dirY = (newY >= currentY) ? 1 : -1;
  int steps = (stepsX > stepsY) ? stepsX : stepsY;
  int intX, intY;
  float changeX = (float)stepsX / (float)steps;
  float changeY = (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);
    delay(stepDelay);
  }
}

/*
  This method lowers and raises right pupil only
*/
void lazyEye()
{
  moveEyes(0, 1, 50);
  delay(500);
  
  // lower left pupil slowly
  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);
    delay(150);
  }
  
  delay(1000);
  
  // raise left pupil quickly
  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]);
    delay(25);
  }  
}

/*
  This method spins pupils clockwise
*/
void roundSpin(int times)
{
  if (times == 0)
    return;
  
  moveEyes(2, 0, 50);
  delay(500);
  
  for (int i=0; i<times; i++)
  {
    displayEyes(2, -1); delay(40); if (i==0) delay(40);
    displayEyes(1, -2); delay(40); if (i==0) delay(30);
    displayEyes(0, -2); delay(40); if (i==0) delay(20);
    displayEyes(-1, -2); delay(40);if (i==0) delay(10);
    displayEyes(-2, -1); delay(40);
    displayEyes(-2, 0); delay(40);
    displayEyes(-2, 1); delay(40);if (i==(times-1)) delay(10);
    displayEyes(-1, 2); delay(40);if (i==(times-1)) delay(20);
    displayEyes(0, 2); delay(40); if (i==(times-1)) delay(30);
    displayEyes(1, 2); delay(40); if (i==(times-1)) delay(40);
    displayEyes(2, 1); delay(40); if (i==(times-1)) delay(50);
    displayEyes(2, 0); delay(40);
  }
}


/*
  This method sets values to matrix row
  Performs 180 rotation if needed
*/
void setRow(int addr, int row, byte rowValue)
{
  if (((addr == 0) && (rotateMatrix0)) || (addr == 1 && rotateMatrix1))
  {
    row = abs(row - 7);
    rowValue = bitswap(rowValue);
  }

  lc.setRow(addr, row, rowValue);
}


/*
  Reverse bits in byte
  http://www.nrtm.org/index.php/2013/07/25/reverse-bits-in-a-byte/
*/
byte bitswap (byte x)
{
  byte result;
 
    asm("mov __tmp_reg__, %[in] \n\t"
      "lsl __tmp_reg__  \n\t"   /* shift out high bit to carry */
      "ror %[out] \n\t"  /* rotate carry __tmp_reg__to low bit (eventually) */
      "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" (result) : [in] "r" (x));
      return(result);
}

【Arduino 动手做】Anansi:一个很酷的蜘蛛状机器人
项目链接:https://www.hackster.io/Odd_Jayy/asi-anansi-robot-companion-dbf92c
项目作者:Jorvon Moss
项目视频 :https://www.youtube.com/watch?v=80WwwqvtrAk
项目代码:https://www.hackster.io/code_files/240674/download
https://www.hackster.io/code_files/240671/download
3D 文件:https://hacksterio.s3.amazonaws.com/uploads/attachments/794407/asiv5_foot_g0d1Hp92X6.stl
https://hacksterio.s3.amazonaws.com/uploads/attachments/794367/anansi_servo_turn_gear_v6_QTpoDkaCAq.stl

00.jpg
00162---=.gif


评论

user-avatar
icon 他的勋章
    展开更多