首页/作品列表/人数统计装置
人数统计装置
13740 1
主要内容
目标
适用于多种用途的人数统计装置,如教室、图书馆、食堂、超市、会议场所、景区。只要有人的地方就有应用面。
原理
利用PIR检测人体并记录,上传至云端,通过微信小程序查看 目前可实现人体移动方向判断,从而较精确统计人数,并实时数据上传,微信小程序自动刷新数据
硬件组装
组装两个微机,分别叫做主机和从机,从机负责数据收集,主机进行数据上传
主机组装
将core、hub、USB、WIFI模块叠加
I2C与从机连接
从机组装
将core、hub、USB模块叠加
PIR接D10、D4接口
LED灯接D8
蜂鸣器接D6
I2C与主机相连

功能实现
从机代码
/******从机******/
#include
#include

#define humanHotSensor1 10 //PIR传感器D4
#define humanHotSensor2 4
#define lightPIN 8 //彩灯
#define buzzerPIN 6 //蜂鸣器
#define criticleNum 15 //防止人一直站在装置前的限制值
#define INTERVAL_NET 60000 //计数清0的上限时间
Adafruit_NeoPixel strip = Adafruit_NeoPixel(2, lightPIN, NEO_GRB + NEO_KHZ800);
//控制灯亮的函数;
unsigned long net_time1 = millis(); //用于判断时间
bool humanHotState1 = false; //储存人体红外的读数
bool humanHotState2 = false;
bool judge = false; //计数是否进行
bool isHuman = false;
int countRight=0; //记录某一方向的数值
int intervalCount=0; //用于特殊情况处理的计数

void setup() {
Serial.begin(115200); //串口初始化
pinMode(humanHotSensor1, INPUT); //将人体红外接口定义为输入信号
pinMode(humanHotSensor2, INPUT);
strip.begin(); //准备对灯珠进行数据发送
strip.show();
Wire.begin(8); //从机编号为8,可以随便写,只要主从机对应
Wire.onRequest(requestEvent); //响应主机请求,并调用括号中的函数
}

void loop() {
humanHotState1=digitalRead(humanHotSensor1);
humanHotState2=digitalRead(humanHotSensor2);
Serial.print(humanHotState1);
Serial.print(" ");
Serial.println(humanHotState2);
if(humanHotState1==1&&humanHotState2==0) { //判断条件一:右边有人,左边没人
delay(150);
Serial.print("round 1: ");
Serial.print(humanHotState1);
Serial.print(" ");
Serial.println(humanHotState2);
humanHotState1=digitalRead(humanHotSensor1);
humanHotState2=digitalRead(humanHotSensor2);
if(humanHotState1==1&&humanHotState2==1) { //判断条件二:两边都有人
Serial.print("round 2: "); //进行多次判断,以避免人移速过慢产生的误差
Serial.print(humanHotState1);
Serial.print(" ");
Serial.println(humanHotState2);
countRight++;
isHuman = true;
strip.setPixelColor(0,strip.Color(0, 255, 0)); //亮绿灯
strip.show();
Serial.println("hello");
Serial.print("countRight:");
Serial.println(countRight);
tone(buzzerPIN,523,100); //蜂鸣器发声
tone(buzzerPIN,587,100);
tone(buzzerPIN,659,100);
tone(buzzerPIN,698,100);
tone(buzzerPIN,784,100);
tone(buzzerPIN,880,100);
tone(buzzerPIN,988,100);
judge=1;
delay(50);
goto mark; //一旦有记录直接跳出
} else {
strip.setPixelColor(0,strip.Color(0, 0, 0)); //灯灭
strip.show();
}
delay(150);
humanHotState1=digitalRead(humanHotSensor1);
humanHotState2=digitalRead(humanHotSensor2);

if(humanHotState1==1&&humanHotState2==1&&judge==0) {
Serial.print("round 2: ");
Serial.print(humanHotState1);
Serial.print(" ");
Serial.println(humanHotState2);
countRight++;
isHuman = true;
strip.setPixelColor(0,strip.Color(0, 255, 0));
strip.show();
Serial.println("hello");
Serial.print("countRight:");
Serial.println(countRight);
tone(buzzerPIN,523,100);
tone(buzzerPIN,587,100);
tone(buzzerPIN,659,100);
tone(buzzerPIN,698,100);
tone(buzzerPIN,784,100);
tone(buzzerPIN,880,100);
tone(buzzerPIN,988,100);
delay(50);
judge=1;
} else {
strip.setPixelColor(0,strip.Color(0, 0, 0));
strip.show();
}
delay(150);
humanHotState1=digitalRead(humanHotSensor1);
humanHotState2=digitalRead(humanHotSensor2);

if(humanHotState1==1&&humanHotState2==1&&judge==0) {
Serial.print("round 2: ");
Serial.print(humanHotState1);
Serial.print(" ");
Serial.println(humanHotState2);
countRight++;
isHuman = true;
strip.setPixelColor(0,strip.Color(0, 255, 0));
strip.show();
Serial.println("hello");
Serial.print("countRight:");
Serial.println(countRight);
tone(buzzerPIN,523,100);
tone(buzzerPIN,587,100);
tone(buzzerPIN,659,100);
tone(buzzerPIN,698,100);
tone(buzzerPIN,784,100);
tone(buzzerPIN,880,100);
tone(buzzerPIN,988,100);
delay(50);
judge=1;
} else {
strip.setPixelColor(0,strip.Color(0, 0, 0));
strip.show();
}
}
else
{
strip.setPixelColor(0,strip.Color(0, 0, 0));
strip.show();
}
if(humanHotState1==1&&humanHotState2==1) { //特殊情况:两边一直感应到人
intervalCount++; //每记录一定次数才增加计数
if(intervalCount>=criticleNum) {
countRight+=intervalCount/10;
isHuman = true;
Serial.print("countRight:");
Serial.println(countRight);
intervalCount=0;
}
delay(500);
}
if(humanHotState1==0&&humanHotState2==0) { //只要有一次没人,计数归零
intervalCount=0;
judge = false;
}
mark:judge = false; //跳出后的位置
if (net_time1 > millis()) net_time1 = millis(); //一定时间的计数器归零
if (millis() - net_time1 > INTERVAL_NET)
{
net_time1 = millis();
countRight=0;
}
}
void requestEvent() { //响应主机请求的函数
if(isHuman) //只有记录过,才发送数据
Wire.write(countRight); //否则会造成相同数据重复传输
else
Wire.write(0);
isHuman = false;
}​
主机代码
#include
#include "./ESP8266.h"

#define SSID "yjk" //修改为自己的WIFI名
#define PASSWORD "142857369" //修改密码
#define IDLE_TIMEOUT_MS 500
#define HOST_NAME "api.heclouds.com"
#define DEVICEID "22798310" //修改设备ID
#define PROJECTID "111337" //修改产品ID
#define HOST_PORT (80)
String jsonToSend;
String apiKey="BFb=zNe1zrgvKvXQf8pSGPzJFEw="; //修改APIKey
char buf[10];
SoftwareSerial mySerial(2, 3); //RX:D3, TX:D2
ESP8266 wifi(mySerial);
String postString;

#define INTERVAL_NET 60000 //定义计数器归零时间间隔
unsigned long net_time1 = millis();
unsigned long lastTime = millis();
int sum=0; //记录总数
int count=0; //记录每分钟人数
int c=0; //储存从机发送的数据
int d=0; //记录上次接收的数据
unsigned long int perNum=0; //每分钟人数值

void setup() {
Serial.begin(115200);
Wire.begin(); //加入无线网
while(!Serial);
Serial.print("setup begin\r\n");
Serial.print("FW Version:");
Serial.println(wifi.getVersion().c_str());
if (wifi.setOprToStationSoftAP()) {
Serial.print("to station + softap ok\r\n");
} else {
Serial.print("to station + softap err\r\n");
}
if (wifi.joinAP(SSID, PASSWORD)) {
Serial.print("Join AP success\r\n");
Serial.print("IP: ");
Serial.println(wifi.getLocalIP().c_str());
} else {
Serial.print("Join AP failure\r\n");
}
if (wifi.disableMUX()) {
Serial.print("single ok\r\n");
} else {
Serial.print("single err\r\n");
}
Serial.print("setup end\r\n");
}

void loop() {
Wire.requestFrom(8, 1); //向8号从机发送请求,接收1B数据
while (Wire.available()) {
c = Wire.read();
if(c>d) { //用于记录总数和每分钟人数
sum+=c-d;
count+=c-d;
}
else {
sum+=c;
count+=c;
}
perNum=count*60000/(millis()-lastTime);//计算人体流动速度
Serial.print("time ");
Serial.println(millis()-lastTime);
Serial.print("c ");
Serial.println(c);
Serial.print("d ");
Serial.println(d);
if(c!=0) d=c;
}
updateSensorData();
if (net_time1 > millis()) net_time1 = millis();
if (millis() - net_time1 > INTERVAL_NET)
{
Serial.println("sent data");
net_time1 = millis();
lastTime = millis();
count=0;
}
Serial.print("sum ");
Serial.println(sum);
Serial.print("count ");
Serial.println(count);
delay(200);
}
void updateSensorData() { //发送数据的函数
if (wifi.createTCP(HOST_NAME, HOST_PORT)) { //建立TCP连接,如果失败,不能发送该数据
Serial.print("create tcp ok\r\n");

jsonToSend="{\"TotalNumber\":";
dtostrf(sum,1,0,buf);
jsonToSend+="\""+String(buf)+"\"";
jsonToSend+=",\"PerNumber\":";
dtostrf(perNum,1,0,buf);
jsonToSend+="\""+String(buf)+"\"";
jsonToSend+="}";

postString="POST /devices/";
postString+=DEVICEID;
postString+="/datapoints?type=3 HTTP/1.1";
postString+="\r\n";
postString+="api-key:";
postString+=apiKey;
postString+="\r\n";
postString+="Host:api.heclouds.com\r\n";
postString+="Connection:close\r\n";
postString+="Content-Length:";
postString+=jsonToSend.length();
postString+="\r\n";
postString+="\r\n";
postString+=jsonToSend;
postString+="\r\n";
postString+="\r\n";
postString+="\r\n";

const char *postArray = postString.c_str(); //将str转化为char数组
Serial.println(postArray);
wifi.send((const uint8_t*)postArray, strlen(postArray)); //send发送命令,参数必须是这两种格式,尤其是(const uint8_t*)
Serial.println("send success");
if (wifi.releaseTCP()) { //释放TCP连接
Serial.print("release tcp ok\r\n");
}
else {
Serial.print("release tcp err\r\n");
}
postArray = NULL; //清空数组,等待下次传输数据
} else {
Serial.print("create tcp err\r\n");
}
}​

本产品基于onenet,需要在上面注册
目前基于微信小程序查看数据(以下为自动刷新部分代码)
var that = this;
this.data.interval = setInterval(function(){
that.setData({ time: that.data.time+1 })
if ((that.data.time)%5 == 0){
that.setData({
total: app.globalData.total.datapoints[0].value,
text2: app.globalData.num.datapoints[0].value,
AT: app.globalData.total.datapoints[0].at
})
const requestTask = wx.request({
url: 'https://api.heclouds.com/devices/**/datapoints?datastream_id=TotalNumber,PerNumber&limit=15', //**为设备ID
header: {
'content-type': 'application/json',
'api-key': '*****************' //填写api-key
},
success: function (res) {
app.globalData.total = res.data.data.datastreams[0]
app.globalData.num = res.data.data.datastreams[1]
},
fail: function (res) {
console.log("fail!!!")
},
complete: function (res) {
console.log("end")
}
})
if (that.data.time == 5){
that.setData({ time: 0 })
}
}
},1000)
项目演示


团队故事
主要障碍在于方向判断、人多时误差大、WiFi上传用时长、实时数据显示。为此,我们自学了很多东西。最难的要数实时数据更新,硬件要上传实时数据,微信要自动刷新。由于WiFi时间问题,单一微机会在上传时出现一段真空期,无法收集数据。只好分成两个,一个收集,一个发送。微信自动刷新也是特别费劲,有一天熬到两点才完成。不过大部分困难都克服了,之后可以再考虑升级探测装置,使数据更加准确。
代码展示

1. 从机程序

编程语言: C/C++(Arduino)

软件工具:Arduino IDE 1.6.9


附件下载
暂无数据!
0

hachiko

您好,我想请问下,您这个是不是用了mcotton的那个物联网公有云,有没有什么教程

回复0

大牛,别默默的看了,快登录帮我点评一下吧!

立即注册