Loading [MathJax]/extensions/tex2jax.js

基于Arduino的太阳能电池板数字生态箱(第2部分)

这篇文章来源于DevicePlus.com英语网站的翻译稿。

承接第1部分的内容,我们将在第2部分中继续使用Arduino制作有趣的电子产品。在上文中,我们从组装电路进行到加速度计测试,这次,我们将完成硬件的制作。这个独特的电子套件创意来自艺术家平原真,他的作品主要以“关系”为主题。大阪艺术大学副教授平原先生使用电脑和电子设备制作了许多媒体艺术作品。近年来,他主要研究如何使用木材和石头等天然材料制作3D作品。那么,现在让我们一起来探索“基于Arduino的太阳能电池板数字饲养箱”的第2部分(也是最后一部分)。

硬件

步骤分解
我们首先从组装外部组件和安装电子元器件开始。过程如下:

  1. 用激光切割材料
  2. 组装主体
  3. LED接线及安装
  4. 安装太阳能电池板

步骤1:用激光切割材料

材料是用激光加工机切割出来的。外部是3mm厚的椴木胶合板。从左边起依次为:LED表面,太阳能电池板表面,两个侧面和LED底座。LED底座上的刻线用于在粘贴LED时使其对齐。

可能很难看清楚,其实在下图的右上角有一个1mm厚的半透明亚克力板。它用于帮助扩散来自全彩串行LED灯带的光。

cutting materials with a laser

请下载并使用以下链接中提取的数据。按照红线切割,按照黑线刻画标记。在实际工作时,请务必根据您使用的激光机来调整设置。

>> CutData.ai

步骤2:组装主体

在两侧边缘涂上木工粘合剂,然后将这四块板和LED以及太阳能电池板粘贴在一起。粘合后立即夹紧并固定到位。如果您担心粘合的强度不够,可以将一小块木头贴在粘合位置的拐角处进行加固。

assembly

步骤3:LED接线及安装

将灯带分割成5个单独的全彩LED灯带。电极中间可以用钳子剪开。将跳线保留在临时接线时的位置。

LED wiring and installation

将单独的全彩串行LED灯带沿对准标记粘贴到底座上。这个时候,请注意在临时接线时所连接的跳线应在左上角位置,且电极方向与划线箭头方向一致。

各个全彩串行LED灯带的电极之间通过硬跳线进行连接。电极之间的内侧距离约为11mm,中间距离约为17mm,外侧距离约为23mm。左上方连接跳线的LED编号为0,其余LED编号按照连接顺序递增,因此右下方LED编号为24。

separated electrodes of the full-color serial LED tapes

现在,我们戳一下面包板上的跳线,然后检查其是否断开。将LED示例程序([Adafruit NeoPixel]> [Simple])中NUPIXELS的值从16改为25即可完成。如果LED都呈绿色亮起,就表示没有问题。

#define NUMPIXELS 16

#define NUMPIXELS 25

步骤4:安装LED底座和面包板

依次叠加椴木胶合板(LED表面)、亚克力板、LED底座,然后用四个螺丝将它们固定到位。连接着全彩串行LED灯带的跳线应从板之间布线到内部。垫片使用非导电垫圈(M2)。由于间隙越厚越利于光的扩散,因此请根据自己的需要将间隙距离调整到约0.5mm至1mm之间。

 installing the LED base and breadboard

installing the LED base and breadboard

将面包板连接到LED底座的中心。面包板的背部也有双面胶带,所以将离型纸撕下并将面包板贴上。请注意,如果您在安装后尝试移除面包板,那么里面的引脚将会脱落。将连接了全彩串行LED灯带的跳线插入面包板的电源、GND和6个引脚。

Attach the breadboard to the center of the LED base

步骤5:用3D打印机制造太阳能电池板托架

用于固定太阳能电池板的托架通过3D打印技术制造。从下面的链接下载STL文件,并使用3D打印机打印托架。请打印出两个相同形状的托架,层压设置分别为粗糙和精细。

>> SolarPanelFixture.stl

solar panels are output with a 3D printer

首先,用螺丝将一个托架固定在太阳能电池板顶部的内侧。3D打印机打印出来的托架上有一个未切割的2mm孔。用M2平头螺钉钻孔并将其固定。

solar panels assembly

接下来,在将太阳能电池板插入上侧托架的同时,用螺钉固定下侧托架。

solar panels assembly

步骤6:硬件制作完成!

将太阳能电池板DC插头插入面包板上的DC插座,此时所有的硬件应已经准备齐全。

solar panel hardware

solar panel hardware

然后,为了在Arduino Pro Mini 328上写入草图,移除下侧的托架,并拆下太阳能电池板。

草图

完成步骤
接下来,我将详细介绍写入草图的所有步骤:

  1. 管理库
  2. 以二维数组方式管理LED
  3. 种草
  4. 养动物并管理多种生物
  5. 动物在加速度计发生感应时增殖

管理库
我们将使用Adafruit提供的Neo Pixel和加速度计LIS3DH库。此外,我们将定期使用一个名为[MsTimer2]的指定函数。从Arduino IDE菜单中选择[Sketch]> [Include Library]> [Manage Library]来打开库管理器。在搜索字段中输入[MsTimer2],然后从显示出来的选项中进行选择并安装。

Arduino IDE menu

管理矩阵中的LED
LED灯带从0到24连续编号,但为了更容易表达动植物的位置,可以换为用横纵坐标来表示。LED编号存储在二维数组中。

int ledMatrix[WIDTH][HEIGHT];//2D array to record LED layout and number
ledMatrix[0][0] = 0;// 0 is、x=0, y=0
ledMatrix[1][0] = 9;// 9 is、x=1, y=0
ledMatrix[2][0] = 10;// 10 is、 x=2, y=0
ledMatrix[3][0] = 19;// 19 is、 x=3, y=0
ledMatrix[4][0] = 20;// 10 is、 x=4, y=0

查看源代码 GitHub托管项目ledMatrix.ino

 

种草
创建一个5 x 5的二维数组,该数组用于保存草的生长情况以及每帧中在随机位置种草。

 

int grassMatrix[WIDTH][HEIGHT];//2D array that keeps grass growing
int rndX = random(WIDTH);
int rndY = random(HEIGHT);
grassMatrix[rndX][rndY] += random(GRASS_GROWTH_POTENTIAL + 1); //Grows grass at random locations

查看源代码 GitHub托管项目grassMatrix.ino

养动物

定义一个结构来处理和保存动物的参数。动物信息通过这一系列动物结构进行管理。动物结构有一个生/死标志,如果它没有死,那么会进行移动和觅食。接下来,将一只动物移向最茂密的草丛。当进入草地部分时,动物开始进食,并将草的生长水平设置为0,然后将这一部分的摄入添加到动物的体能中。同时,每一帧都会消耗一定的体能,如果体能降到0,动物就会死亡。

...
struct Animal
{
float x;
float y;
int life;
bool isDead;
RGB color;
};
...
Animal animals[ANIMAL_MAX_NUM];//動物の情報を保持する配列
...
for ( int i = 0; i < ANIMAL_MAX_NUM; i++)
{
if ( !animals[i].isDead )
{
moveMaxGrass(i);//一番大きな草に向かって移動
//現在地の草を食べて体力回復
animals[i].life += grassMatrix[int(animals[i].x)][int(animals[i].y)];
grassMatrix[int(animals[i].x)][int(animals[i].y)] = 0;
//体力減少
animals[i].life -= ANIMAL_DECREASE;
//体力が0になったら死亡
if ( animals[i].life <= 0 )
{
animals[i].life = 0;
animals[i].isDead = true;
}
...

增殖动物

有两种方法可以增殖动物。一种是当主体倒下以及检测到一定程度的振动时。这种情况下,一个随机颜色的新动物将会出现在屏幕中间。

...
// 加速度センサーが反応していれば、動物を増やす
if ( bornFlag )
{
bornFlag = false;
bornAnimal(-1);
}
...
view raw bornFlag.ino hosted with ❤ by GitHub

另一种是当动物吃草并且体能达到极限时。动物的体能将会减半,并增加相同颜色的动物数量。

...
//体力が上限になったら増える
if ( animals[i].life > MAX_BRIGHTNESS )
{
animals[i].life = MAX_BRIGHTNESS / 2;
bornAnimal(i);
}
...
view raw animals.ino hosted with ❤ by GitHub

整体草图

#define WIDTH 5//LEDの横の数
#define HEIGHT 5//LEDの縦の数
#define LED_PIN 6//LEDテープの信号線
#define INTERVAL 750//画面切り替えのインターバル
#define MAX_BRIGHTNESS 32//動植物の最大の明るさ
#define ANIMAL_MAX_NUM 10//動物の最大数
#define ANIMAL_DECREASE 1//動物の体力減少
#define GRASS_GROWTH_NUM 3//同時に草が成長する箇所
#define GRASS_GROWTH_POTENTIAL 2//草が成長するスピード
#define KNOCK_THRESHOLD 5000//ノックと判断する閾値
#include <MsTimer2.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
struct RGB
{
int r;
int g;
int b;
};
struct Animal
{
float x;
float y;
int life;
bool isDead;
RGB color;
};
// LED
Adafruit_NeoPixel pixels;//LEDをコントロールするオブジェクト
int ledMatrix[WIDTH][HEIGHT];//LEDの配置と番号を記録する2次元配列
int grassMatrix[WIDTH][HEIGHT];//草の育成を保持する2次元配列
Animal animals[ANIMAL_MAX_NUM];//動物の情報を保持する配列
//加速度センサー
Adafruit_LIS3DH lis = Adafruit_LIS3DH();//加速度センサーをコントロールするオブジェクト
long px, py, pz;//1フレーム前の加速度
boolean bornFlag;//次のフレームで生物が誕生するかのフラグ
void setup()
{
Serial.begin( 9600 );
randomSeed( analogRead(0) );
// TIMER -------------------------
MsTimer2::set(INTERVAL, update);//関数updateを一定間隔ごとに呼び出すタイマー
MsTimer2::start();
// NEOPIXEL --------------------
pixels = Adafruit_NeoPixel(WIDTH * HEIGHT, LED_PIN, NEO_GRB + NEO_KHZ800);//NeoPixelオブジェクトを生成
pixels.begin();
// ACC SENSOR ------------------------
if (! lis.begin(0x18)) {
while (1);
}
lis.setRange(LIS3DH_RANGE_2_G);//加速度センサーの感度を設定。2, 4, 8, 16G
// LED MATRIX -------------------------
//0~24番のLEDをX, Yの座標に置き換える
ledMatrix[0][0] = 0;//0番のLEDは、x=0, y=0
ledMatrix[1][0] = 9;//9番のLEDは、x=1, y=0
ledMatrix[2][0] = 10;
ledMatrix[3][0] = 19;
ledMatrix[4][0] = 20;
ledMatrix[0][1] = 1;
ledMatrix[1][1] = 8;
ledMatrix[2][1] = 11;
ledMatrix[3][1] = 18;
ledMatrix[4][1] = 21;
ledMatrix[0][2] = 2;
ledMatrix[1][2] = 7;
ledMatrix[2][2] = 12;
ledMatrix[3][2] = 17;
ledMatrix[4][2] = 22;
ledMatrix[0][3] = 3;
ledMatrix[1][3] = 6;
ledMatrix[2][3] = 13;
ledMatrix[3][3] = 16;
ledMatrix[4][3] = 23;
ledMatrix[0][4] = 4;
ledMatrix[1][4] = 5;
ledMatrix[2][4] = 14;
ledMatrix[3][4] = 15;
ledMatrix[4][4] = 24;
reset();
}
void loop()
{
checkKnock();//ノックされたかどうか判断する
delay(1);
}
void update()
{
// GRASS ----------------------------------------
grawGrass();//草が育つ
// ANIMAL ----------------------------------------
for ( int i = 0; i < ANIMAL_MAX_NUM; i++)
{
if ( !animals[i].isDead )
{
moveMaxGrass(i);//一番大きな草に向かって移動
//現在地の草を食べて体力回復
animals[i].life += grassMatrix[int(animals[i].x)][int(animals[i].y)];
grassMatrix[int(animals[i].x)][int(animals[i].y)] = 0;
//体力減少
animals[i].life -= ANIMAL_DECREASE;
//体力が0になったら死亡
if ( animals[i].life <= 0 )
{
animals[i].life = 0;
animals[i].isDead = true;
}
//体力が上限になったら増える
if ( animals[i].life > MAX_BRIGHTNESS )
{
animals[i].life = MAX_BRIGHTNESS / 2;
bornAnimal(i);
}
}
}
// KNOCK ----------------------------------------
// 加速度センサーが反応していれば、動物を増やす
if ( bornFlag )
{
bornFlag = false;
bornAnimal(-1);
}
// OUTPUT ----------------------------------------
setLed();//LEDに値をセットし、光らせる
}
void reset()
{
// ANIMAL -------------------------------------
for ( int i = 0; i < ANIMAL_MAX_NUM; i++)
{
animals[i].x = random(WIDTH);
animals[i].y = random(HEIGHT);
animals[i].life = 10;
animals[i].color.r = random(0, 10);
animals[i].color.g = random(0, 10);
animals[i].color.b = random(0, 10);
animals[i].isDead = true;
}
// GRASS -------------------------------------
for ( int y = 0; y < HEIGHT; y++)
{
for ( int x = 0; x < WIDTH; x++)
{
grassMatrix[x][y] = 0;
}
}
// LED -------------------------------------
pixels.clear();
pixels.show();
}
void grawGrass()
{
for ( int i = 0; i < GRASS_GROWTH_NUM; i++)
{
int rndX = random(WIDTH);
int rndY = random(HEIGHT);
grassMatrix[rndX][rndY] += random(GRASS_GROWTH_POTENTIAL + 1); //ランダムな場所の草が成長する
if ( grassMatrix[rndX][rndY] > MAX_BRIGHTNESS ) grassMatrix[rndX][rndY] = MAX_BRIGHTNESS;
}
}
void moveMaxGrass( int _id )
{
// 最も成長している草の位置を調べる
int maxGrass = 0;
int maxGrassX = 0;
int maxGrassY = 0;
for ( int y = 0; y < HEIGHT; y++)
{
for ( int x = 0; x < WIDTH; x++)
{
if ( grassMatrix[x][y] > maxGrass )
{
maxGrass = grassMatrix[x][y];
maxGrassX = x;
maxGrassY = y;
}
}
}
// 目標と比較して近づく
int nX = animals[_id].x;
int nY = animals[_id].y;
if ( (maxGrassX - animals[_id].x) > 0 )
{
nX += 1;
} else if ( (maxGrassX - animals[_id].x) < 0 )
{
nX -= 1;
}
if ( (maxGrassY - animals[_id].y) > 0 )
{
nY += 1;
} else if ( (maxGrassY - animals[_id].y) < 0 )
{
nY -= 1;
}
//移動先に生きている動物がいたら、移動しない
for ( int i = 0; i < ANIMAL_MAX_NUM; i++ )
{
if ( animals[i].x == nX && animals[i].y == nY )//XY両方とも一致している
{
if ( !animals[i].isDead )//生存している
{
if ( i != _id) //自分自身ではない
{
return;//関数を終わる
}
}
}
}
animals[_id].x = nX;
animals[_id].y = nY;
}
void bornAnimal(int _parent)
{
int x;
int y;
int r;
int g;
int b;
//枠の空きを探す
for ( int i = 0; i < ANIMAL_MAX_NUM; i++)
{
if ( animals[i].isDead )
{
if ( _parent < 0 )//振動で生まれた場合
{
x = WIDTH / 2;
y = HEIGHT / 2;
r = random(0, 15);
g = random(0, 15);
b = random(0, 15);
} else {//親がいる場合
x = animals[ _parent ].x;
y = animals[ _parent ].y;
r = animals[ _parent ].color.r;
g = animals[ _parent ].color.g;
b = animals[ _parent ].color.b;
}
animals[i].x = x;
animals[i].y = y;
animals[i].life = 10;
animals[i].color.r = r;
animals[i].color.g = g;
animals[i].color.b = b;
animals[i].isDead = false;
break;//ループを抜ける
}
}
}
void checkKnock() {
lis.read();//センサーの値を読み取り
long delta = abs(px - lis.x) + abs(py - lis.y) + abs(pz - lis.z);//各軸の変化量の合計
if ( delta > KNOCK_THRESHOLD )//変化量が大きければ
{
bornFlag = true;
}
px = lis.x;
py = lis.y;
pz = lis.z;
}
void setLed()
{
RGB rgbMatrix[WIDTH][HEIGHT];
// GRASS --------------------------------------
for ( int y = 0; y < HEIGHT; y++)
{
for ( int x = 0; x < WIDTH; x++)
{
//rgbMatrixの初期化
rgbMatrix[x][y].r = 0;
rgbMatrix[x][y].g = 0;
rgbMatrix[x][y].b = 0;
rgbMatrix[x][y].g += grassMatrix[x][y];//草の色を追加
}
}
// ANIMAL --------------------------------------
for ( int i = 0; i < ANIMAL_MAX_NUM; i++)
{
if ( !animals[i].isDead )
{
//動物の色を追加
rgbMatrix[int(animals[i].x)][int(animals[i].y)].r += animals[i].color.r;
rgbMatrix[int(animals[i].x)][int(animals[i].y)].g += animals[i].color.g;
rgbMatrix[int(animals[i].x)][int(animals[i].y)].b += animals[i].color.b;
}
}
// SET DATA ------------------------------------
for ( int y = 0; y < HEIGHT; y++)
{
for ( int x = 0; x < WIDTH; x++)
{
//rgbMatrixの色をLEDににセットする
pixels.setPixelColor( ledMatrix[x][y], pixels.Color(rgbMatrix[x][y].r, rgbMatrix[x][y].g, rgbMatrix[x][y].b ) );
}
}
pixels.show();
}
view raw define.ino hosted with ❤ by GitHub

digital rearing box powered by solar panels using Arduino

总结

做得好!您已经完成了!如果您将太阳能电池板朝向太阳,我相信光点会开始移动。当它开始移动寻找食物时,看起来确实像一个生物。那么,您对通过重写种草方式和动物的运动方式来创建自己的原始生态系统有何感想呢?

这就是对这个系列的总结了。通过这两部分内容,我们学习了如何使用Arduino制作由太阳能电池板供电的数字饲养箱。我希望每个人都可以利用这些知识来制造一些真正独特的东西。

DevicePlus 编辑团队
DevicePlus 编辑团队

设备升级版适用于所有热爱电子和机电一体化的人。

基于Arduino的太阳能电池板数字生态箱(第1部分)

Arduino基础: 控制电机

相关文章

  1. how-to-make-eobot_02_19

    “魅力四射”的机器人制作【下篇】

  2. “魅力四射”的机器人制作【上篇】

  3. 用Arduino和TOF距离传感器制作甜甜圈播放器【后篇】

  4. 用Arduino和TOF距离传感器制作甜甜圈播放器【前篇】

  5. 1-1

    Arduino电子制作总结!基于微控制器的电子制作基础之基础篇

  6. 用Arduino制作的太阳能电池板供电数字养殖箱【前篇】

    用Arduino制作的太阳能电池板供电数字养殖箱【前篇】

  7. 使用D/A转换器灵活控制电压并使用Arduino输出模拟信号的方法

  8. 在最后一刻停下来!用Arduino和距离传感器制作小鸡赛车!(第3篇•最终篇)

Arduino入门指南

基础知识

EMC


TECH INFO

  • Sugiken老师的电机驱动器课堂
  • 技术分享
  • Arduino入门指南
  • Raspberry Pi初学者指南
  • 技术动态
下载推荐