驴友花雕 发表于 2025-6-18 12:09:40

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

这个项目最初是来自 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 底部的整体上,然后将它们缠绕在我背包的肩包上。


























驴友花雕 发表于 2025-6-18 12:24:58

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




驴友花雕 发表于 2025-6-18 12:26:18

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

项目代码

#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={
B00111100,
B01111110,
B11111111,
B11111111,
B11111111,
B11111111,
B01111110,
B00111100
};

byte eyePupil = B11100111;

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

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

// 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);
      setRow(0, 7-i, eyeCurrent);
    }
    if (blinkRight)
    {
      setRow(1, i, eyeCurrent);
      setRow(1, 7-i, eyeCurrent);
    }
    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
Both LED modules will show identical eyes
*/
void displayEyes(int offsetX, int offsetY)
{
// ensure offsets arein 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;
byte pupilRow2 = pupilRow & eyeBall;

// 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 = pupilRow1;
    }
    else if (r == row2)
    {
      setRow(0, r, pupilRow2);
      setRow(1, r, pupilRow2);
      eyeCurrent = pupilRow2;
    }
    else
    {
      setRow(0, r, eyeBall);
      setRow(1, r, eyeBall);
      eyeCurrent = eyeBall;
    }
}

// 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);
    setRow(1, i+3, eyeBall & eyePupil);
    setRow(1, i+4, eyeBall & eyePupil);
    delay(150);
}

delay(1000);

// raise left pupil quickly
for (int i=0; i<3; i++)
{
    setRow(1, 4-i, eyeBall & eyePupil);
    setRow(1, 5-i, eyeBall & eyePupil);
    setRow(1, 6-i, eyeBall);
    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__, % \n\t"
      "lsl __tmp_reg__\n\t"   /* shift out high bit to carry */
      "ror % \n\t"/* rotate carry __tmp_reg__to low bit (eventually) */
      "lsl __tmp_reg__\n\t"   /* 2 */
      "ror % \n\t"
      "lsl __tmp_reg__\n\t"   /* 3 */
      "ror % \n\t"
      "lsl __tmp_reg__\n\t"   /* 4 */
      "ror % \n\t"

      "lsl __tmp_reg__\n\t"   /* 5 */
      "ror % \n\t"
      "lsl __tmp_reg__\n\t"   /* 6 */
      "ror % \n\t"
      "lsl __tmp_reg__\n\t"   /* 7 */
      "ror % \n\t"
      "lsl __tmp_reg__\n\t"   /* 8 */
      "ror % \n\t"
      : "=r" (result) : "r" (x));
      return(result);
}

驴友花雕 发表于 2025-6-18 12:27:55

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

【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





页: [1]
查看完整版本: 【Arduino 动手做】Anansi:一个很酷的蜘蛛状机器人