交通灯信息系统
组件和用品
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
应用和在线服务
| ||||
| ||||
|
关于这个项目
介绍
交通有能力刺激我们中最好的人,而且情况越来越糟。如果这可以通过智能交通灯改变呢?我们创建了一个交通灯信息系统,让驾驶员知道他需要以什么速度行驶才能到达路口并在不超过最大速度限制的情况下通过绿灯。而当司机不得不等待不可避免的红灯时,它会让他知道什么时候灯快变绿了。
交通灯将有关保持绿色的时间或下一次绿灯前的时间等数据发送到在线数据库。 GPS 或智能手机上的应用程序将从数据库中检索数据并计算通过绿灯所需的速度。当您不可避免地必须等待时,它将显示直到红灯阶段结束的剩余等待时间。
例子
您正在 70 公里/小时的区域内行驶,并保持在极限。您前面的交通灯是红色的,并且灯将在 30 秒内变绿。您距离红绿灯 500 米,因此系统会建议您以 60 公里/小时的速度驶向红绿灯。
项目演示
我们是如何做到的?
为了演示我们的项目,我们使用 Arduino Yun 创建了一个交通灯。交通灯由 3 个 LED 和一个实时时钟组成。灯光将在给定的时间间隔内发生变化。 Arduino Yun 节省了交通灯变为绿色/红色的时间。然后,它运行一个 PHP 文件,该文件连接到在线 MySQL 数据库并插入从 Arduino Yun 接收到的数据。 Android 应用程序(使用 Android Studio 创建)将从该数据库中检索日期。这是通过另一个 PHP 文件完成的,该文件以 JSON 格式返回交通灯数据。该应用程序计算所需的速度,当您无法通过绿灯时,它会显示一个倒数计时器。
要计算所需的速度,应用程序需要知道到交通灯的距离。这是通过根据 GPS 坐标计算距离来完成的。但不幸的是,智能手机中的 GPS 不够精确,无法证明我们的概念,因为我们的工作规模很小。这就是我们使用超声波测距模块 (HC-SR04) 的原因。 Arduino Yun 通过 433 MHz 射频模块接收汽车和交通灯之间的距离。每次 Yun 收到另一个 Arduino 的新测量值时,它都会更新数据库中的数据。现在,该应用程序能够计算所需的速度。
说明
1) 创建一个在线 MySQL 数据库
(我们使用了 freemysqlhosting.net )
2) 在数据库中添加一个表 'TrafficL_data':
3) 设置硬件(发射器)
您可以在此处找到原理图“Arduino 发射器”。
4) 将“Arduino 发射器代码”上传到 Arduino
你可以在这里找到代码。
5) 将 Arduino Yun 连接到您的 WiFi 网络
6) 使用 Putty 访问 Arduino YUN 的 Linux 服务器:
opkg update opkg install php5-mod-mysqli opkg install php5-cli nano /mnt/sda1/MySQL_UpdateTrafficLData.php
您可以在此处找到“MySQL_UpdateTrafficLData.php”。
如果你看到这个错误:'-ash:nano:not found',你必须安装'nano'(这是一个基本的文本编辑器):
opkg install nano
chmod 755 /mnt/sda1/MySQL_UpdateTrafficLData.php/mnt/sda1/MySQL_UpdateTrafficLData.phpnano /mnt/sda1/MySQL_UpdateDistance.php
您可以在此处找到“MySQL_UpdateDistance.php”。
chmod 755 /mnt/sda1/MySQL_UpdateDistance.php/mnt/sda1/MySQL_UpdateDistance.php
7) 设置硬件(Arduino Yun 接收器)
您可以在此处找到原理图“Arduino Yun 接收器”。
8) 上传'Arduino Receiver &MySQLdb'到Arduino Yun
你可以在这里找到代码。
9) 打开串口监视器
您应该会看到类似的内容:
11) Android Studio 文件
- activity_main.xml
- MainActivity.java*
- AndroidManifest.xml
- strings.xml
*别忘了修改网址
你可以在这里找到“EchoJSON.php”。
12) 将 Android Studio 项目上传到您的智能手机
ESP8266 说明 [附加]
可以使用基于 ESP8266 的模块而不是更昂贵的 Arduino Yun:
1. 在 https://www.000webhost.com 上创建一个帐户
2.创建网站
3.新建一个数据库
4. 使用文件管理器上传“CreateTable.php”和“PostDemo.php”。更改两个文件中的“用户名”、“密码”和“数据库名”。
CreateTable.php:
connect_error) { die("Connection failed:" . $conn->connect_error);}//traffl_data_v2 是表名$sql ="CREATE TABLE trafficl_data_v2 (UnixTime_green_1 INT(12) NOT NULL, UnixTime_red_1 INT(12) NOT NULL, UnixTime_green_2 INT(12) NOT NULL, UnixTime_red_2 INT(12) NOT NULL, Distance INT(12) NOT NULL, id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY )";if ($conn->query($sql) ===TRUE) { echo "表创建成功!";} else { echo "错误创建表:" . $conn->error;}$conn->close();?>
PostDemo.php:
connect_error) { die("数据库连接失败:" . $conn->connect_error); }if (!empty($_POST['UnixTime_green_1']) &&!empty($_POST['UnixTime_red_1']) &&!empty($_POST['UnixTime_green_2']) &&!empty($_POST['UnixTime_red_2']) ) { $UnixTime_green_1 =$_POST['UnixTime_green_1']; $UnixTime_red_1 =$_POST['UnixTime_red_1']; $UnixTime_green_2 =$_POST['UnixTime_green_2']; $UnixTime_red_2 =$_POST['UnixTime_red_2']; $sql ="UPDATE `trafficl_data_v2` SET `UnixTime_green_1`='5',`UnixTime_red_1`='6',`UnixTime_green_2`='7',`UnixTime_red_2`='8',`Distance`='99' WHERE 1 ”; if ($conn->query($sql) ===TRUE) { echo "数据插入成功!"; } else { 回声“错误:”。 $sql 。 “
”。 $conn->错误; }}else { echo "FAILED:不正确的参数";}$conn->close();?>
5.新建表:选择'CreateTable.php'并点击'view'
6.在arduino中安装ESP8266的包
添加此 URL 文件--> 首选项:
http://arduino.esp8266.com/stable/package_esp8266com_index.json
7.
[2019 年 2 月 9 日更新]
选择您的开发板、COM 端口...并将 ESP8266PostDemo.ino 上传到您的基于 ESP8266 的开发板。我正在使用 NodeMcu V3 ESP8266 12E。下面的代码应该适用于几乎所有基于 ESP8266 的开发板。
因为我手头不再有时钟,所以我更改了代码,以便使用随机值每 10 秒更新一次数据库。
ESP8266PostDemo.ino:
#include #include #include #include #define ARRAYSIZE 4 // 4 个参数const char* ssid ="yourSSID"; const char* password ="yourPassword";const char* dest ="http://xxxxx.000webhostapp.com/xxxxx/ ... /xxxxx.php"; // 你的请求 destinationconst char* argument_names[ARRAYSIZE] ={"UnixTime_green_1","UnixTime_red_1","UnixTime_green_2","UnixTime_red_2"};const String equals_sign ="=";const Stringampersand_sign ="&";void setup() {延迟(1000); Serial.begin(115200); WiFi.mode(WIFI_OFF); //防止重新连接问题(连接时间过长) delay(1000); WiFi.mode(WIFI_STA); //此行隐藏ESP作为wifi热点的查看 WiFi.begin(ssid, password); Serial.println(""); Serial.print("连接");而(WiFi.status()!=WL_CONNECTED){延迟(500); Serial.print("."); Serial.println(""); Serial.print("连接到"); Serial.println(ssid); Serial.print("IP地址:"); Serial.println(WiFi.localIP()); }void loop() { HTTPClient http;字符串参数 ="";参数 +=argument_names[0] +equals_sign+ (int)random(100); for(int i=1; i
php文件:
connect_error) { die("Database Connection failed:" . $conn->connect_error); } if (!empty($_POST["UnixTime_green_1"]) &&!empty($_POST["UnixTime_red_1"]) &&!empty($_POST["UnixTime_green_2"]) &&!empty($_POST["UnixTime_red_2"]) ) { $UnixTime_green_1 =$_POST["UnixTime_green_1"]; $UnixTime_red_1 =$_POST["UnixTime_red_1"]; $UnixTime_green_2 =$_POST["UnixTime_green_2"]; $UnixTime_red_2 =$_POST["UnixTime_red_2"]; $sql ="更新 TrafficL_data SET UnixTime_green_1='$UnixTime_green_1', UnixTime_red_1='$UnixTime_red_1',UnixTime_green_2='$UnixTime_green_2', UnixTime_red_2='$UnixTime_red_2' WHERE id=1"; if ($conn->query($sql) ===TRUE) { echo "OK"; } else { 回声“错误:”。 $sql 。 “
”。 $conn->错误; } }?>
如果您已经成功更新数据库,您可以在'Arduino Receiver &MySQLdb'的arduino代码中修改以下程序:
- void MySQL_UpdateTrafficLData()
- void MySQL_UpdateDistance()
请注意,如果您想复制项目,一次实施所有内容并不是一个好主意。首先尝试分别测试每个组件。如果它们都运行良好,您可以从组合不同的组件开始。请随时在评论部分寻求帮助,并尽量详细描述您的问题。
代码
- Arduino 发射器代码
- Arduino 接收器和 MySQLdb
- MySQL_UpdateTrafficLData.php
- MySQL_UpdateDistance.php
- EchoJSON
- MainActivity.java
- AndroidManifest.xml
- strings.xml
- activity_main.xml
Arduino 发射器代码Arduino
/* IOTOPIA - 2016-2017 - 交通灯信息系统(发射器)* by Pieter Luyten &Joppe Smeets * * 通过 RF 433MHz 模块将距离发送到另一个 arduino * * RF 433MHz 模块:* tx_pin --> 引脚 3 * * HC-SR04 模块:* trig_pin --> pin 5 * echo_pin --> pin 6 * */#define tx_pin 3#define trig_pin 5#define echo_pin 6#include// RF 433 MHz 模块库#include "HCSR04.h" // HC-SR04 模块库HCSR04 超声波(trig_pin,echo_pin); int distance;char CharMsg[21];void setup() { Serial.begin(9600); vw_setup(2000); // 每秒比特数 vw_set_tx_pin(tx_pin);}void loop() { distance =Ultrasonic.Ranging(CM); // 以厘米为单位测量距离 while(distance <0){ // 避免错误读数,再次测量距离 distance =Ultrasound.Ranging(CM); } sprintf(CharMsg, "%d,", 距离); vw_send((uint8_t *)CharMsg, strlen(CharMsg)); // 发送距离 vw_wait_tx(); // 等到整个消息消失 Serial.print("Distance (cm):"); Serial.println(距离);延迟(250);}
Arduino 接收器和 MySQLdbArduino
/* IOTOPIA - 2016-2017 - 交通灯信息系统(接收器 + 上传到 MySQLdb)* by Pieter Luyten &Joppe Smeets * * 通过 RF 从另一个 arduino 接收距离 * 将交通灯数据和距离上传到 MySQL 数据库 * * RF 433MHz 模块:* rx_pin --> 引脚 3 * * 交通灯(3 个 LED):* RedLED --> 引脚 5 * OrangeLED --> 引脚 6 * GreenLED --> 引脚 7 * * DS3231(实时时钟) :* SCL --> SCL(Arduino Yun 的引脚 3)* SDA --> SDA(Arduino Yun 的引脚 2)* * SD 卡 - Arduino Yun * SD 卡(带 PHP 文件)--> 集成 SD 插槽* /#define RedLED 5#define OrangeLED 6#define GreenLED 7#define rx_pin 9#include// RF 433 MHz 模块#include // Alarms#include // I2C通信#include "RTClib.h" // 实时时钟#include // 在AR9331 上运行Linux 进程// UnixTime:时间,定义为自1970 年1 月1 日以来经过的秒数long UnixTime_green_1; // 下一个绿灯(在 UnixTime 中)long UnixTime_red_1; // 下一个红灯(在 UnixTime 中)long UnixTime_green_2; // 下一个绿灯(在 UnixTime 中)long UnixTime_red_2; // 下一个红灯(在 UnixTime 中)long s_till_orange; // 秒到 orangeRTC_DS3231 rtc;char StringReceived[22];boolean i;int interval =5; // 以秒为单位的距离; // 在 cmvoid setup() { rtc.begin(); //rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); Serial.begin(9600); Bridge.begin(); // 初始化桥 vw_setup(2000); // 每秒位数 vw_set_rx_pin(rx_pin); vw_rx_start(); Alarm.timerRepeat(interval, UpdateTrafficLData); // 更新交通灯数据(下一个绿灯/红灯...) Alarm.timerRepeat(1,PrintCurrentTime); // 每 x 秒打印一次当前时间 pinMode(GreenLED, OUTPUT); pinMode(橙色LED,输出); pinMode(红色LED,输出);数字写入(绿色LED,低);数字写入(橙色LED,低);数字写入(红色LED,低); Serial.println("设置完成");}void loop() { Alarm.delay(0); // 应使用此延迟而不是正常的 Arduino delay(),// 用于及时处理警报和计时器。您可以传递 0 以获得最小延迟。 RF_Listen(); }void RF_Listen(){ uint8_t buf[VW_MAX_MESSAGE_LEN]; uint8_t buflen =VW_MAX_MESSAGE_LEN; if (vw_get_message(buf, &buflen)) { int a; for (a =0; a 0) { char c =p.read(); Serial.print(c); } // 确保发送最后一位数据。 Serial.flush();}void MySQL_UpdateDistance(){ 进程 p; p.begin("/mnt/sda1/MySQL_UpdateDistance.php"); p.addParameter(String(distance)); p.run(); // 读取反馈(用于调试) while (p.available()> 0) { char c =p.read(); Serial.print(c); } // 确保发送最后一位数据。 Serial.flush();}void PrintCurrentTime() { DateTime now =rtc.now(); SetLEDsTrafficL(); Serial.print(now.hour(), DEC); Serial.print(':'); Serial.print(now.minute(), DEC); Serial.print(':'); Serial.print(now.second(), DEC); Serial.print(" "); Serial.println(now.unixtime());}void SetLEDsTrafficL() { DateTime now =rtc.now(); s_till_orange =UnixTime_red_1 - now.unixtime(); if (i ==0) { digitalWrite(GreenLED, LOW);数字写入(橙色LED,低);数字写入(红色LED,高); } if (i ==1 &&s_till_orange <=3) { digitalWrite(GreenLED, LOW);数字写入(橙色LED,高);数字写入(红色LED,低); } if (i ==1 &&s_till_orange> 3) { digitalWrite(GreenLED, HIGH);数字写入(橙色LED,低);数字写入(红色LED,低); }}
MySQL_UpdateTrafficLData.phpPHP
#!/usr/bin/php-cliconnect_error) { trigger_error('数据库连接失败:' . $conn->connect_error, E_USER_ERROR);} $sql="UPDATE TrafficL_data SET UnixTime_green_1='$UnixTime_green_1', UnixTime_red_1='$UnixTime_red_1',UnixTime_green_2='$UnixTime_green_2', UnixTime_red_2='$UnixTime_red_2' WHERE id=1";if($conn->query($sql) ) ===false) { trigger_error('错误的 SQL:' . $sql . ' 错误:' . $conn->error, E_USER_ERROR);}else{echo "数据插入!\n";} ?>
MySQL_UpdateDistance.phpPHP
#!/usr/bin/php-cliconnect_error) { trigger_error('数据库连接失败:' . $conn->connect_error, E_USER_ERROR );}$sql="UPDATE TrafficL_data SET Distance='$Distance'WHERE id=1";if($conn->query($sql) ===false) { trigger_error('Wrong SQL:' . $sql . ' 错误:' . $conn->error, E_USER_ERROR);}else{echo "距离插入!\n";}?>
EchoJSONPHP
MainActivity.javaJava
package com.example.xxx.xxx;//改xxx xxximport android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.widget.TextView;import com .android.volley.RequestQueue;import com.android.volley.Response;import com.android.volley.VolleyError;import com.android.volley.toolbox.JsonArrayRequest;import com.android.volley.toolbox.Volley;import org. json.JSONArray;import org.json.JSONException;import org.json.JSONObject;//import java.text.DateFormat;import java.util.Date;import java.util.Timer;//import java.util.TimerTask; import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class MainActivity extends AppCompatActivity { // 将显示字符串“data " 保存结果 TextView 结果; //保存推荐速度的textview TextView recSpeed; // 要解析的对象的 URL String JsonURL ="YourURLhere"; // 这个字符串将保存结果 String data =""; // 定义并发处理URL请求的Volley请求队列 RequestQueue requestQueue; //定时器对象每秒更新一次数据 //Timer timer; //speedLimit(cm/s) private final static double maxSpeed =18; //推荐速度私人双速; //表中的次数 public final static int NUMBER_OF_ENTRIES =2; //带绿色时间的数组 long[] unixTimesGreen =new long[NUMBER_OF_ENTRIES]; //数组为红色 long[] unixTimesRed =new long[NUMBER_OF_ENTRIES]; //保存距离私有双距离的变量; //重复updateTable的变量 private final ScheduledExecutorService scheduler =Executors.newSingleThreadScheduledExecutor(); // 用于测试:私有 Future>timingTask;公共无效滴答(长毫秒){timingTask =scheduler.scheduleAtFixedRate(new Runnable() { public void run() { updateTable(); } }, 0, 毫秒, TimeUnit.MILLISECONDS); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //textViews 将结果转换为 results =(TextView) findViewById(R.id.jsonData); recSpeed =(TextView) findViewById(R.id.recommendedSpeed); //初始化表updateTable(); //每100毫秒更新一次应用程序tick(500); //用于使用定时器对象重复更新 /** timer =new Timer("Timer"); timer.schedule(new UpdateTable(),(long)100,(long)100); */ } //用于使用定时器对象重复更新 /** 私有类 UpdateTable extends TimerTask{ public void run(){ updateTable(); } } */ private void updateTable(){ //重置字符串数据 =""; // 创建 Volley 请求队列 requestQueue =Volley.newRequestQueue(this); // 用于测试 /** // 将结果投射到主布局 XML 中找到的 TextView 中,id 为 jsonData results =(TextView) findViewById(R.id.jsonData); */ // 创建名为arrayreq 的JsonArrayRequest 类,传递需要的参数 //JsonURL 是要从JsonArrayRequest 中获取的URL arrayreq =new JsonArrayRequest(JsonURL, // 第二个参数Listener 覆盖方法onResponse() 并传递 //JSONArray作为参数 new Response.Listener() { // 从 JSON 请求中获取响应 @Override public void onResponse(JSONArray response) { try { // 检索外部数组中的第一个 JSON 对象 JSONObject TrafficLObj =response.getJSONObject( 0); // 从 JSON 对象中检索“trafficArry” JSONArray trafficArry =TrafficLObj.getJSONArray("TrafficLArray"); // 遍历 JSON 数组获取对象并将它们添加到列表视图中,直到没有更多对象TrafficArry for (int i =0; i maxSpeed) speed =maxSpeed; else speed =distance/((unixTimesGreen[interval]-time));速度=速度*5; }}
AndroidManifest.xmlXML
//更改xxx xxx
strings.xmlXML
“NooitRood”,意思是:“NeverRed”NooitRood
activity_main.xmlXML
示意图
RF 433MHz module:tx_pin --> pin 3
HC-SR04 module:
trig_pin --> pin 5
echo_pin --> pin 6 RF 433MHz module:
rx_pin --> pin 3
TrafficLight (3 LEDs):
RedLED --> pin 5
OrangeLED --> pin 6
GreenLED --> pin 7
DS3231 (Real-Time-Clock):
SCL --> SCL (pin 3 on Arduino Yun)
SDA --> SDA (pin 2 on Arduino Yun)
制造工艺