第一部分 故事
故事背景:
正如唐僧师徒经历了一路的千难万险去求取真经,创客大侦探冲锋队寻找好奇心的路途也是困难重重。这一天,大家来到了人工智能岛上的神经元城堡,要打开传说中的七彩宝箱,取到宝箱里的一个存有通往下一关目的地导航资料的神经元模块。
传说这个七彩宝箱是一个很特殊的密码箱,使用颜色作为密码,只有输入了正确的颜色码才能打开宝箱。
角色分配:
A、粒子姐姐——指导老师;
B、阿杜一诺——家长;
C、曼德佳——小朋友。
规则说明与通关方式:
一、 粒子姐姐、阿杜一诺、曼德佳合作完成整个密码箱和解码平台的制作;
二、 粒子姐姐设置密码并宣读解码规则:
a. 将密码中的英文字母以莫尔斯码方式编码
b. 然后使用颜色码替代莫尔斯码 “·”=G(绿色),“-”=B(蓝色)
c. 每个字母结束后使用一个R(红色)作为结束符
d. 例如:密码“TR”对应的莫尔斯码为“- ·-·”,则对应的颜色码为BRGBGR;
三、 阿杜一诺和曼德佳合作在草稿纸上翻译出密码;
四、 曼德佳通过动作“输入”密码并打开宝箱,取出宝物(神经元模块)
a. 系统启动完毕后,密码箱前下方的方格底下会有循环闪烁的彩色流水灯
b. 在密码箱前解码时首先“站”(或用物体遮挡)在最靠近密码箱的第一个LED上方的方格内一次以启动密码箱,此时流水灯熄灭,显示红、绿、蓝三个灯,并且第一个灯位的灯色会随着所“站”方格下方的色灯颜色变化;
五、 根据编码的结果,依次“站”在相应颜色的的格子(红、绿或蓝色LED上方对应的格子)里,并注意第一个LED显示的颜色是否正确,全部完成后如果正确则会听到语音提示,即可打开宝箱取出宝物。否则需重新从头开始再次输入密码,直到成功打开宝箱为止。
游戏原理: 对莫尔斯密码(一种古老的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号)进行二次加密,最终用跳彩色方格的方式来进行解密。
第二部分:制作过程
设计思路:
本着“简单问题复杂化”和“有困难要上,没有困难创造困难也要上”的原则,通过使用尽可能多的上一次比赛得来的硬件进行系统设计,打开脑洞寻找思路,最后设计了这样一个方案:
由于本次任务的核心是密码和神经元模块,于是在学习了神经元模块资料和相关网上的资料后决定用神经元模块来做密码的解码单元,而不用Arduino做这个处理。
由超声波传感器测的解码者所站的位置,然后换算成模拟电压信号(由于手头没有模拟量输出的超声波模块,只能用普通的超声波模块输出到Arduino,然后再转换成模拟的PWM信号)输出给神经元模块,由神经元模块判断所输入的一系列电压脉冲的时程是否与实现学习的样板时程(即正确密码)相符,如果相符则输出开箱信号,经过信号分离模块后分给语音模块和七彩灯条。由于没有直接的七彩灯条驱动模块,只能再次利用Arduino模块进行七彩灯条的驱动控制。所以在这个项目中,Arduino相当于是两个接口模块,同时也作为是否进入解码模式的切换控制模块。
软件思路:密码内容由神经元模块通过学习后直接获得,与Arduino软件无关。同理成功开锁后的语音提示内容也由语音模块直接录制并播放,也与Arduino软件无关。Arduino软件则主要做如下控制:
首先,系统上电后自动进入“等待模式”,此时RGB灯条通过Arduino控制显示七彩流水灯效果,神经元模块没有输入信号。Arduino软件不停扫描超神波测距模块,直到发现在地面的第一个格子有物体为止。
其次,当检测到地面第一个格子有物体时,系统进入“解码模式”,此时RGB灯条切换成第一个灯显示输入状态、后面3、5、7灯分别显示红、绿、蓝色,以点亮需要输入密码的格子地板。Arduino根据超声波传感器测到的数据做两个判断:一个是通过距离换算成对应格子下LED的颜色,并将该实时颜色用第1个灯显示出来,以此提示用户当前输入的码色;同时Arduino将检测到的距离信号整形和插值放大后传给神经元模块用来判断密码的正确性。
再次,Arduino软件还不停地扫描来自于信号分离模块(即来自神经元模块)输出的信号,当检测到解码成功信号时控制彩灯进入闪烁状态,并将整个系统回复到原来的“等待模式”以准备下一次解码。
材料清单
- 单神经元模块 X1
- 信号分离模块 X1
- 固体录音模块 X1
- 扬声器模块 X1
- 7灯RGB灯条 X1
- Arduino UNO控制板 X1
- 超声波传感器 X1
- 超声波传感器支架 X1
- L293双H桥马达驱动模块 X1
- 电动保险箱玩具 X1
- 底板 X1
- 各种导线 X1
制作过程:
在正式搭建硬件之前先进行原理试验,包括神经元模块的功能学习试验、RGB灯条功能试验、密码箱开锁试验等。
1、模块原理试验:
2、电动保险箱试验:为了项目,借来娃的电动保险箱(储蓄罐),拆开来研究,发现里面是个电机,一个方向旋转是开锁,另外一个方向旋转是锁闭+进钞。于是决定用一个L293模块来驱动这个电机。
接下来开始搭建正式的硬件:找一块大小合适的底板、试摆、划线、钻孔、用六角铜柱和螺丝将各个模块固定在底板上:
接下去编写程序,边写边调:
然后找来小朋友,录音和训练神经元模块:
最后完成的模块是这样的:
完成的代码是这样的:
#include <DFRobot_NeoPixel.h>
#include <DFRobot_Servo.h>
double mind_n_Shaped_US;
double mind_n_Scaled_US;
double mind_n_Standby;
double mind_n_UltraSonic;
DFRobot_NeoPixel rgb_display_4;
Servo myservo9;
void PreProcess(double Input_Value);
void Lock_Control(double Ctl_Code);
void Motor_Drv(double Velocity);
void LED_Display(double Distance);
int ultrasonicSensorCodeAutoGeneratedReturnCM(int trigPin, int echoPin)
{
long duration;
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
if(digitalRead(echoPin) == 0){
digitalWrite(trigPin, LOW);
digitalWrite(trigPin, HIGH);
duration = pulseIn(echoPin, HIGH);
}else{
digitalWrite(trigPin, HIGH);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin,LOW);
}
duration = duration / 59;
if ((duration <=0) || (duration > 45000)) return false;
delay(50);
return duration;
}
void PreProcess(double Input_Value)
{
if ((Input_Value <= 3)) {
mind_n_Shaped_US = 0;
}
else {
if ((Input_Value <= 8)) {
mind_n_Shaped_US = 6;
}
else {
if ((Input_Value <= 11)) {
mind_n_Shaped_US = 9;
}
else {
if ((Input_Value <= 16)) {
mind_n_Shaped_US = 12;
}
else {
mind_n_Shaped_US = 20;
}
}
}
}
mind_n_Scaled_US = (map(mind_n_Shaped_US, 0, 20, 0, 255));
}
void Lock_Control(double Ctl_Code)
{
if ((Ctl_Code == 1)) {
Motor_Drv(127);
delay(800);
}
else {
if ((Ctl_Code == 2)) {
Motor_Drv(-255);
delay(2000);
}
}
Motor_Drv(0);
}
void Motor_Drv(double Velocity)
{
if ((Velocity == 0)) {
digitalWrite(10, LOW);
digitalWrite(11, LOW);
analogWrite(6, 0);
}
else {
if ((Velocity > 0)) {
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
}
else {
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
}
analogWrite(6, (constrain((abs(Velocity)), 0, 255)));
}
}
void LED_Display(double Distance)
{
if ((Distance <= 0)) {
rgb_display_4.setRangeColor(0, 0, 0xffffff);
}
else {
if ((Distance <= 6)) {
rgb_display_4.setRangeColor(0, 0, 0xff0000);
}
else {
if ((Distance <= 9)) {
rgb_display_4.setRangeColor(0, 0, 0x00ff00);
}
else {
if ((Distance <= 12)) {
rgb_display_4.setRangeColor(0, 0, 0x0000ff);
}
else {
rgb_display_4.setRangeColor(0, 0, 0x333333);
}
}
}
}
}
void setup() {
Serial.begin(19200);
rgb_display_4.begin(4, 7, 30);
myservo9.attach(9);
myservo9.angle(abs(90));
rgb_display_4.setRangeColor(0, 0, 0xffffff);
rgb_display_4.setRangeColor(1, 1, 0xcc33cc);
rgb_display_4.setRangeColor(2, 2, 0xff0000);
rgb_display_4.setRangeColor(3, 3, 0xffff00);
rgb_display_4.setRangeColor(4, 4, 0x00ff00);
rgb_display_4.setRangeColor(5, 5, 0x00ffff);
rgb_display_4.setRangeColor(6, 6, 0x0000ff);
Motor_Drv(0);
Lock_Control(1);
delay(500);
Lock_Control(2);
mind_n_Standby = 1;
digitalWrite(8, LOW);
}
void loop() {
mind_n_UltraSonic = (ultrasonicSensorCodeAutoGeneratedReturnCM(8, 12));
PreProcess(mind_n_UltraSonic);
analogWrite(3, mind_n_Scaled_US);
Serial.println((String((String((String(mind_n_UltraSonic) + String(", "))) + String((String(mind_n_Scaled_US) + String(", "))))) + String((String(digitalRead(2)) + String(".")))));
if ((mind_n_Standby == 1)) {
if ((mind_n_Scaled_US < 50)) {
mind_n_Standby = 0;
rgb_display_4.clear();
rgb_display_4.setRangeColor(2, 2, 0xff0000);
rgb_display_4.setRangeColor(4, 4, 0x00ff00);
rgb_display_4.setRangeColor(6, 6, 0x0000ff);
}
else {
rgb_display_4.rotate(1);
delay(500);
}
}
else {
LED_Display(mind_n_Shaped_US);
analogWrite(3, mind_n_Scaled_US);
if (digitalRead(2)) {
mind_n_Standby = 1;
Lock_Control(1);
delay(3000);
Lock_Control(2);
rgb_display_4.setRangeColor(0, 0, 0xffffff);
rgb_display_4.setRangeColor(1, 1, 0xcc33cc);
rgb_display_4.setRangeColor(2, 2, 0xff0000);
rgb_display_4.setRangeColor(3, 3, 0xffff00);
rgb_display_4.setRangeColor(4, 4, 0x00ff00);
rgb_display_4.setRangeColor(5, 5, 0x00ffff);
rgb_display_4.setRangeColor(6, 6, 0x0000ff);
}
}
}
最后的视频在这里:
rzyzzxw2019.08.11
厉害厉害