(三)制作过程
在完成基本的原理分析和材料准备之后,我们开始整个红绿灯装置的制作和组装。在此过程中,在老师的指导下,我们分工合作从传感器的选择和连接,电线电路的焊接,软件代码的编写与调试,道路模型的制作,到整个系统的联调,一点一点地完成了智能红绿灯装置的制作。具体制作过程如图8所示。

图8 小组成员在科学老师指导下完成装置
首先是传感器的选择和连接。为了实现预想的原理,我们需要三大类的传感器,第一类用于检测行人或供行人触碰及感应,第二类用于检测道路中车辆的数量,第三类用于输出信号,即输出喇叭声音、显示剩余时间、点亮或熄灭红绿黄灯等。
在ArduinoUNO开发板的基础上,我们选择按键传感器检测触碰信号,如图9所示。这种传感器有3个引脚,其中电源端Vcc接UNO的5V输出端,Gnd就是接地,连接UNO上对应有“Gnd”字样的端口,信号输出端为OUT或S(即Signal),接在UNO上某个数字引脚上。我们需要在人行横道的两端各安一个按键传感器,因此Arduino开发板上需要两个对应的引脚来进行连接。在代码中我们用到的两数字引脚编号是#3和#4。在UNO开发板上,为了增加非接触式感应功能,我们加装光电传感器(图9的挥手传感器)。接口定义如下:
constintbuttonPinX=3; //thenumberofthepushbuttonpin3;
constintbuttonPinY=4; //thenumberofthepushbuttonpin4.

图9 可供行人触发的按键和感应器示意图
关于道路中车辆数量的检测,我们查阅的文献中提到较多的可实现的方法,比如用摄像头进行AI图像识别,可以精准识别车牌号码和数量;但是这种方式需要昂贵的设备,且需要时刻在线获得云端数据库的支持,代码比较复杂。我们采取了简单的光电传感器测量的方式,目的同样方便实现但成本较低。具体方法如图10所示,在路边由近至远依次放置几个光电传感器,像图10中就是在道路两侧分别放置了传感器A、B和C,以及传感器5,6和7(图10中为避免接线干扰视线,各传感器没有完整连线)。每个传感器和上述的按键传感器一样,均有三个引脚,分别是Vcc、Gnd和Sig,代表供电、接地和信号,我们就是根据最后信号的高低电平来判断在放置传感器的位置是否停有车辆。如,右上传感器A、B和C都返回信号,说明在路口排队等待通行的汽车排到了C位置;而左下的传感器中只有6和7返回信号,传感器5没有接收到“存在汽车”的信号,显示这个方向车辆等待通行的数量要少。传感器引脚接口定义为:
constintCarDetectPinA=5; //thesepinsdetectsthecarexistornot,
constintCarDetectPinB=6; //检测汽车的存在
constintCarDetectPinC=7; //5,6,73个引脚

图10 道路上待行车辆的检测传感器布局示意图(左)和检测原理(右)
该红绿灯装置能够接受行人对装置的主动碰触或感应,并能对道路中等候的车辆数量进行感知,经过逻辑判断之后,需要对行人和车辆做出正确的指示。这就需要相应的用于输出信号的传感器模块。这里我们用到了红黄绿三色信号灯(交通信号灯)、两位数码显示管和用于播放提示语音的语音模块及喇叭,如图11所示。
//行人的指示灯
constintmanLedPinG=8; //行人的指示灯——绿色
constintmanLedPinY=9; //行人的指示灯——黄色
constintmanLedPinR=10; //行人的指示灯——红色
//汽车的指示灯
constintCarLedPinG=11; //汽车的指示灯——绿色
constintCarLedPinY=12; //汽车的指示灯——黄色
constintCarLedPinR=13; //汽车的指示灯——红色
//数码管 采用I2C通讯方式;
//语音播放功能是Arduino通过TTL串口控制语音模块实现。
其次,在连接好传感器之后,我们把这些传感器模块一一安装到仿真道路的适当位置。我们找来一个30cm×40cm的白色泡沫板,在长度方向的中间位置贴上黑色模拟道路的贴纸,目的是从原理上验证,并在功能上实现我们的智能红绿灯装置,因此制作了只有一个人行横道的双向两车道公路模型。单纯车道加多,如改为四车道或六车道,对功能没有任何影响,不需要增加更多的传感器。如果改成丁字路口或十字路口的道路模型,显然人行横道数目增加了,就需要增加1倍或2倍的传感器数目,但是我们红绿灯装置还是能很好地管控所有输入和输出信息,只须在程序代码里做适当调整,重新编译,就可正确运行。

图11 行人方向和车辆方向的红绿灯及其他声光指示图
我们把需要操作的按键、感应器和需要显示的红绿灯、数码管等模块安装在模拟道路的上表面,再用杜邦线连接到模拟道路泡沫板的下部,并用UNO扩展板和电子元件面包板把所有线缆分类连接在插槽的功能区中,用扎带或胶带约束好,再连接到Arduino开发板上预定的引脚上,使之成为一个整齐整洁的功能体,如图12所示。

图12 装置底部的控制器和语音模块及其接线图
当然,为了美观和逼真,还在道路两侧布置了仿真绿化树和仿真路灯,在路口粘贴了模拟行人的人偶。道路中的玩具车辆可以移动,在移动过程中可以触发检测车辆的传感器。图13是安装好各种传感器(由于模型空间有限,部分功能重复的传感器尚未布置,Arduino开发板在底部)的模拟道路的照片。

图13 仿真交通道路图及各种传感器
最后,我们对完成的红绿灯装置进行程序烧录和整体调试,使之可以自主控制信号灯的转换,引导行人和车辆快速通过路口。编写程序的软件有很多,有官方自带的字符型编写工具,也有各种图形化的编程工具,如Ardublock,Scratch的S4A、北师大的Mixly等。图形化工具不需要记忆语法关键词和编写代码,只要拖拉相应的积木块就可以快速创作,但是它们只支持部分硬件,且各个图形化编程工具创作的代码不互通。基于此,我们采用了官方的开源ArduinoIDE编写程序,其语法和C或C++非常相似,很多通用代码可以直接采用,比较方便实用。
以下是装置实现特定功能的部分代码片段。
初始化:
voidsetup(){
//通过串口命令控制音频播放模块,分别用五条语音指令
Serial.begin(9600);//设置波特率,常用的波特率有4800,9600等等
//initializetheLEDpinasoutput:
pinMode(manLedPinR,OUTPUT);
pinMode(manLedPinY,OUTPUT);
pinMode(manLedPinG,OUTPUT);
pinMode(CarLedPinR,OUTPUT);
pinMode(CarLedPinY,OUTPUT);
pinMode(CarLedPinG,OUTPUT);
//initializethepushbuttonpinasaninput:
pinMode(buttonPinX,INPUT);(https://www.daowen.com)
pinMode(buttonPinY,INPUT);
pinMode(CarDetectPin,INPUT); //检测汽车的存在
}
当行人按下按钮或在感应器前挥手后,装置接收到此触发信号,即lightState=1执行:
If(lightState==1)//接收到行人触发信号,则
{//---(B)
playWarn(2); //语音播报“行人请耐心等待,绿灯亮起后通行”
LED_flash(manLedPinY,3); //起始的过渡时间,黄灯亮起,默认3s
LED_flash(CarLedPinY,3);
manLedG_time=DetectMan(); //检测在路口等待的行人数量,优化时长10~30s
//---(C)
LED_off(CarLedPinG); //车辆关闭绿灯
LED_on(CarLedPinR); //汽车亮起红灯
playWarn(3);//语音播报“行人过马路请走人行横道,注意安全”
LED_off(manLedPinR); //行人关闭红灯
LED_onX(manLedPinG,manLedG_time); //行人绿灯的时间,由检测结果赋值
//CountDownSec(manLedG_time); //行人绿灯倒计时开始
carLedG_time=DetectCar(); //检测道路上等待的车辆数量,优化时长0~30s
//---(D)
LED_off(manLedPinG); //行人关闭绿灯
LED_on(manLedPinR); //行人亮起红灯
playWarn(4);//语音播报“等待车辆通过后,过马路请先按按钮或挥挥手”
LED_off(CarLedPinR); //车辆关闭红灯
LED_onX(carLedPinG,carLedG_time); //车辆绿灯的时间,由检测结果赋值
//CountDownSec(manLedG_time); //车辆绿灯倒计时开始
TriggerPressed=checkTrig(); //检测行人是否按按钮或挥手,为下次准备当前无动作
//---(E)
playWarn(5);//语音播报“行人小心车辆,过马路请先按按钮或挥挥手”
LED_flash(manLedPinY,3); //过渡时间,黄灯亮起,默认3s
LED_flash(CarLedPinY,3);
if(TriggerPressed==true)//如果行人在车通行时触发了设备,则
{lightState=1;}//下次进入行人过马路模式
else{lightState=0;}//如果没有人按键,则进入“车辆不间断通行模式”(默认)
}
LED灯的开启并延时,代码如下:
voidLED_onX(intPinNum,intSeconds)//点亮LED,并延时X秒
{
digitalWrite(PinNum,HIGH);
//延长时间,秒=Seconds
for(inti=0;i<=Seconds;i++)
{delay(1000);}//每次延时——1s
if(i>Seconds)//循环结束后,到时间关闭
{digitalWrite(PinNum,LOW);}//熄灭
}
LED灯的熄灭,代码如下:
voidLED_off(intPinNum)//关闭LED灯光
{
digitalWrite(PinNum,LOW);//熄灭
}