[作品提交] 【Follow me第二季第1期】完结篇

aramy   2024-8-25 10:21 楼主

本次Follow Me 活动带来的Adafruit Circuit Playground Express这块板子非常有意思,绚烂的灯光加上传感器,很适合做成装饰品,出去玩肯定是最吸引眼球的哪一个。

项目视频演示


本项目完成了本期活动的全部内容,所有任务的展示如下:

hw

任务成果展示


入门任务:开发环境搭建,板载LED点亮


对应论坛帖:【Follow me第二季第1期】开发环境的搭建和点亮LED灯 https://bbs.eeworld.com.cn/thread-1289781-1-1.html

 

1、环境搭建

这次打算用arduino来进行功能开发,所以使用了vscode+platformio来进行开发。使用vscode创建"adafruit_circuitplayground"工程。在github上下载这个板子的库文件。将下载的文件夹放到工程lib文件夹下。编译会有报错,提示:#error TinyUSB is not selected, please select it in "Tools->Menu->USB Stack" ,需要在platformio.iini文件中添加“lib_ignore = Adafruit TinyUSB Library”。再次编译,即可成功。

 

[env:adafruit_circuitplayground_m0]
platform = atmelsam
board = adafruit_circuitplayground_m0
framework = arduino

lib_ignore = Adafruit TinyUSB Library

2、点灯

参考电路图,板子上D13管脚有接一颗红色LED灯。再参考官方提供的例程,先来点亮这颗红色LED灯。并且打开了串口,通过USB口与上位机进行通讯。

#include <Adafruit_CircuitPlayground.h>

void setup() {
  CircuitPlayground.begin();
  Serial.begin(115200);
}

void loop() {
  CircuitPlayground.redLED(HIGH);
  delay(500);
  CircuitPlayground.redLED(LOW);
  delay(500);
  Serial.println("Follow me Season 2!");
}


基础任务部分,对应论坛帖:【Follow me第二季第1期】基础任务一、二、三 https://bbs.eeworld.com.cn/thread-1290634-1-1.html

基础任务一:控制板载炫彩LED,跑马灯点亮和颜色变换

 

板子外边缘有一圈全彩LED灯,一共10颗。跑马灯就是依次逐个点亮LED灯,利用肉眼的视觉残留,感觉到灯光的运动。这里使用了最大的亮度,颜色使用一个随机数,让10颗LED灯依次亮起,每次亮20ms。

#include <Adafruit_CircuitPlayground.h>

void setup()
{
  CircuitPlayground.begin();
  Serial.begin(115200);
  CircuitPlayground.strip.setBrightness(255);
}

void loop()
{
  uint32_t color=random(0, 0xffffff);
  for (int i = 0; i < 10; ++i)
  {
    CircuitPlayground.strip.setPixelColor(i, color);
    CircuitPlayground.strip.show();
    delay(20);
    CircuitPlayground.strip.clear();
  }
}

基础任务二:监测环境温度和光线,通过板载LED展示舒适程度

板子上集成了超多的传感器,其中就有温度计和光线传感器。因为没有显示屏,就需要使用LED展示温度和光线的信息。光线强弱直接和LED灯的亮度挂钩,光线越强,LED灯越亮。实测中光线传感器非常靠近0~2号LED灯的位置,这样LED灯的光线会影响到光线传感器读取环境光强数据。所以0~3号LED灯,没有去驱动,使其处于关闭状态。

环境光线强度由LED灯的亮度表现,温度就由LED灯的颜色来表现了。设定最低温度和最高温度,最低温度20摄氏度,最高40摄氏度。将这个温度区间映射到全彩色域。越靠近20度,颜色就越偏向冷色调(蓝色),越靠近40度,颜色就约偏向于暖色调(紫红),符合心理上对温度感知的映像。

#include <Adafruit_CircuitPlayground.h>
float MinTemp = 20.0, MaxTemp = 40.0, a, b, c, d;
float tempC;
uint16_t lightval;
void Getabcd()
{
  a = MinTemp + (MaxTemp - MinTemp) * 0.2121;
  b = MinTemp + (MaxTemp - MinTemp) * 0.3182;
  c = MinTemp + (MaxTemp - MinTemp) * 0.4242;
  d = MinTemp + (MaxTemp - MinTemp) * 0.8182;
}

//浮点数转颜色  伪彩色
void GetColor(float val,uint8_t rgbval[])
{
  byte red = 0, green = 0, blue = 0;
  red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
  if ((val > MinTemp) & (val < a))
  {
    green = constrain(255.0 / (a - MinTemp) * val - (255.0 * MinTemp) / (a - MinTemp), 0, 255);
  }
  else if ((val >= a) & (val <= c))
  {
    green = 255;
  }
  else if (val > c)
  {
    green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
  }
  else if ((val > d) | (val < a))
  {
    green = 0;
  }

  if (val <= b)
  {
    blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
  }
  else if ((val > b) & (val <= d))
  {
    blue = 0;
  }
  else if (val > d)
  {
    blue = constrain(240.0 / (MaxTemp - d) * val - (d * 240.0) / (MaxTemp - d), 0, 240);
  }
  rgbval[0]=red;
  rgbval[1]=green;
  rgbval[2]=blue;

  // return red << 16 | green << 8 | blue;
}

void setup()
{
  CircuitPlayground.begin();
  Serial.begin(115200);
  CircuitPlayground.strip.setBrightness(255);
  Getabcd();
}

void loop()
{
  uint8_t rgbval[3];
  tempC = CircuitPlayground.temperature();
  lightval= CircuitPlayground.lightSensor();
  Serial.print(tempC);
  Serial.print("    ");
  Serial.println(lightval);
  GetColor(tempC,rgbval);
  CircuitPlayground.strip.setBrightness(lightval>255?255:lightval);
  for(uint8_t i=3;i<10;i++)
    CircuitPlayground.strip.setPixelColor(i, rgbval[0], rgbval[1], rgbval[2]);
  CircuitPlayground.strip.show();
  delay(200);
  CircuitPlayground.strip.clear();
}


基础任务三:接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警

 

板子上有红外发射和接收装置。看文档介绍是可以利用这两个传感器测量距离的。有做测试,但是没能成功。使用AD测量红外接收端,没有获得与距离正相关的数据。还发现长时间点亮红外LED灯,板子都快烤糊了,都出味了。遂放弃使用红外测距,改为超声波模块测距。效果也是非常不错。

距离继续使用上一个实验中的伪彩色转换方法,将距离映射到颜色。将10厘米到300厘米距离 完整映射到全彩色色域。设定阈值,当距离小于20厘米时,驱动蜂鸣器报警。

#include <Adafruit_CircuitPlayground.h>
float MinTemp = 1.0, MaxTemp = 30.0, a, b, c, d;

#define Trig A0 //引脚Tring
#define Echo A1 //引脚Echo
float dm;       //距离变量 分米
float temp;     //

void Getabcd()
{
  a = MinTemp + (MaxTemp - MinTemp) * 0.2121;
  b = MinTemp + (MaxTemp - MinTemp) * 0.3182;
  c = MinTemp + (MaxTemp - MinTemp) * 0.4242;
  d = MinTemp + (MaxTemp - MinTemp) * 0.8182;
}

//浮点数转颜色  伪彩色
void GetColor(float val, uint8_t rgbval[])
{
  byte red = 0, green = 0, blue = 0;
  red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
  if ((val > MinTemp) & (val < a))
  {
    green = constrain(255.0 / (a - MinTemp) * val - (255.0 * MinTemp) / (a - MinTemp), 0, 255);
  }
  else if ((val >= a) & (val <= c))
  {
    green = 255;
  }
  else if (val > c)
  {
    green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
  }
  else if ((val > d) | (val < a))
  {
    green = 0;
  }

  if (val <= b)
  {
    blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
  }
  else if ((val > b) & (val <= d))
  {
    blue = 0;
  }
  else if (val > d)
  {
    blue = constrain(240.0 / (MaxTemp - d) * val - (d * 240.0) / (MaxTemp - d), 0, 240);
  }
  rgbval[0] = red;
  rgbval[1] = green;
  rgbval[2] = blue;

  // return red << 16 | green << 8 | blue;
}

void setup()
{
  CircuitPlayground.begin();
  Serial.begin(115200);
  CircuitPlayground.strip.setBrightness(255);
  Getabcd();
  pinMode(Trig, OUTPUT);
  pinMode(Echo, INPUT);
}

void loop()
{
  uint8_t rgbval[3];
  //给Trig发送一个低高低的短时间脉冲,触发测距
  digitalWrite(Trig, LOW);  //给Trig发送一个低电平
  delayMicroseconds(2);     //等待 2微妙
  digitalWrite(Trig, HIGH); //给Trig发送一个高电平
  delayMicroseconds(10);    //等待 10微妙
  digitalWrite(Trig, LOW);  //给Trig发送一个低电平

  temp = float(pulseIn(Echo, HIGH)); //存储回波等待时间,  //pulseIn函数会等待引脚变为HIGH,开始计算时间,再等待变为LOW并停止计时  //返回脉冲的长度  //声速是:340m/1s 换算成 34000cm / 1000000μs => 34 / 1000  //因为发送到接收,实际是相同距离走了2回,所以要除以2  //距离(厘米)  =  (回波时间 * (34 / 1000)) / 2  //简化后的计算公式为 (回波时间 * 17)/ 1000
  dm = (temp * 17) / 10000;          //把回波时间换算成dm

  if (dm > 0)
  {
    Serial.print("距离=");
    Serial.println(dm);
    GetColor((30.0 - dm), rgbval);
    for (uint8_t i = 0; i < 10; i++)
      CircuitPlayground.strip.setPixelColor(i, rgbval[0], rgbval[1], rgbval[2]);
    CircuitPlayground.strip.show();
    if (dm < 2)
    {                                        //距离小于20cm时,拉响警报
      CircuitPlayground.playTone(1000, 500); // 播放警报音500ms
    }
  }
  delay(500);
  CircuitPlayground.strip.clear();
}

 


 

进阶任务(必做):制作不倒翁——展示不倒翁运动过程中的不同灯光效果


板子上集成了运动传感器(LIS3DH 3轴XYZ加速度计),带有轻击和自由落体检测功能。这里意味着,这个板子能监测加速度变化,但是没有办法监测角速度变化,没有办法检测旋转动作的发生。库函数的例程提供了读取加速度的代码,参考着例程,很容易就读取到3个方向的加速度。

将板子水平放置,y方向就是重力方向,在静止状态下会有9.8的重力加速度。X方向为水平方向,通过X,Y两个轴方向的加速度,就可以求出板子当前的倾角,将倾角映射到颜色空间和LED灯的个数,就可以得到不同角度下绚烂的LED灯光了。

#include <Adafruit_CircuitPlayground.h>
#include <math.h>
#define PI 3.1415926

float MinTemp = 0.0, MaxTemp = 30.0, a, b, c, d;
float tempC;
uint16_t lightval;
void Getabcd()
{
  a = MinTemp + (MaxTemp - MinTemp) * 0.2121;
  b = MinTemp + (MaxTemp - MinTemp) * 0.3182;
  c = MinTemp + (MaxTemp - MinTemp) * 0.4242;
  d = MinTemp + (MaxTemp - MinTemp) * 0.8182;
}

// 浮点数转颜色  伪彩色
void GetColor(float val, uint8_t rgbval[])
{
  byte red = 0, green = 0, blue = 0;
  red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
  if ((val > MinTemp) & (val < a))
  {
    green = constrain(255.0 / (a - MinTemp) * val - (255.0 * MinTemp) / (a - MinTemp), 0, 255);
  }
  else if ((val >= a) & (val <= c))
  {
    green = 255;
  }
  else if (val > c)
  {
    green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
  }
  else if ((val > d) | (val < a))
  {
    green = 0;
  }

  if (val <= b)
  {
    blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
  }
  else if ((val > b) & (val <= d))
  {
    blue = 0;
  }
  else if (val > d)
  {
    blue = constrain(240.0 / (MaxTemp - d) * val - (d * 240.0) / (MaxTemp - d), 0, 240);
  }
  rgbval[0] = red;
  rgbval[1] = green;
  rgbval[2] = blue;
}

void setup()
{
  Serial.begin(115200);
  CircuitPlayground.begin();
  CircuitPlayground.strip.setBrightness(255);
  Getabcd();
}

void loop()
{
  uint8_t rgbval[3];
  float x, y, angle;
  x = CircuitPlayground.motionX();
  y = CircuitPlayground.motionY();
  angle = atan2(y, x) * 180 / PI;

  Serial.println(angle);
  GetColor(abs(angle)/2, rgbval);
  for (uint8_t i = 0; i < abs(angle)/4; i++)
    CircuitPlayground.strip.setPixelColor(i, rgbval[0], rgbval[1], rgbval[2]);
  CircuitPlayground.strip.show();
  delay(200);
  CircuitPlayground.strip.clear();
  // delay(200);
}

 

VID_20240825_085514

 

 创意任务二:章鱼哥——章鱼哥的触角根据环境声音的大小,章鱼哥的触角可舒展或者收缩


下单时购买了舵机,收到后发现,这个舵机与日常见到的舵机有所不同。平常见到的舵机多为180度舵机,这个是360度舵机。之前接触的舵机,驱动信号为50Hz方波,其中高电平变换从0.5ms到2.5ms对应着0~180度角度。这个舵机驱动信号也是50Hz方波,但是1.5ms对应着停止。0.5ms~1.5ms对应着顺时针旋转,1.5ms~2.5ms对应着逆时针旋转。其中距离1.5ms距离越近,旋转速度越慢,越远旋转速度越快。但是,无法控制指定角度的旋转,而且顺时针和逆时针旋转速度并不对等。这就导致很难很好地控制舵机悬臂的位置。

这里收集麦克风声音,简单地映射到舵机旋转上,去驱动舵机的旋转。

#include <Adafruit_CircuitPlayground.h>
#include <Servo.h> 
float value;
Servo myservo;

void setup() {
  Serial.begin(115200);
  CircuitPlayground.begin();
   myservo.attach(A1, 500, 2500); // 修正脉冲宽度
   myservo.writeMicroseconds(1500); // 停机
}

void loop() {
  // Take 10 milliseconds of sound data to calculate
  value = CircuitPlayground.mic.soundPressureLevel(10);
  
  Serial.print("Sound Sensor SPL: ");
  Serial.println(value-60);
  myservo.writeMicroseconds(1500+(value-65)*20); // 停机
  delay(20);
}

e45d2b511601cfdf787b0685bc066b1.jpg

 

项目源码:


20240826103241147.zip (487.14 KB)
(下载次数: 1, 2024-8-26 10:32 上传)


心得体会:

非常喜欢follow me这个活动,除了有好玩的开发板,还有很多厉害的大佬在论坛中指导。玩的同时还提升了技术。但是follow me活动不要设限制啊,这一季居然只让参加两期活动,每一期都不舍得错过啊!

本帖最后由 aramy 于 2024-9-26 20:50 编辑

回复评论 (1)

谢谢啦
点赞  2024-8-26 15:39
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复