报警输出完成

This commit is contained in:
2025-11-19 15:52:19 +08:00
parent 8530821351
commit 18885439e6
6 changed files with 317 additions and 64 deletions

Binary file not shown.

View File

@@ -1,7 +1,5 @@
/*
本程序用于读取配置文件
根据配置文件发送高低电平
发送引脚固定:7,8
本程序用于控制引脚输出高低电平
*/
#include <iostream>
@@ -13,12 +11,6 @@
using namespace std;
using namespace QCL;
/*
Parmas:
argv[1]: GPIO引脚编号
argv[2]: 设置引脚为高/低电平
*/
const string SetFile = "/home/orangepi/RKApp/InitAuth/conf/.env";
// 初始化GPIO引脚
@@ -35,14 +27,11 @@ int main(int argc, char *argv[])
int GPIO_Pin1 = 7;
int GPIO_Pin2 = 8;
int value = 0;
cout << "[sendGpioSignal] 启动,读取配置: " << SetFile << endl;
if (GetOutValue(value) == false)
if (argc < 2)
{
cerr << "[sendGpioSignal] 未读取到 outPutMode程序退出" << endl;
cerr << "传入参数错误" << endl;
return -1;
}
cout << "[sendGpioSignal] 读取到 outPutMode=" << (value == 1 ? "true" : "false") << endl;
// 初始化GPIO引脚
if (InitGpio(GPIO_Pin1, GPIO_Pin2) != 0)
@@ -50,14 +39,48 @@ int main(int argc, char *argv[])
cout << "Error: Failed to initialize GPIO pin " << endl;
return 1;
}
// 写入GPIO引脚
cout << "[sendGpioSignal] 设置 GPIO(" << GPIO_Pin1 << "," << GPIO_Pin2 << ") 为 "
<< (value == 1 ? "HIGH" : "LOW") << endl;
WriteGpio(GPIO_Pin1, value);
WriteGpio(GPIO_Pin2, value);
cout << "[sendGpioSignal] 完成" << endl;
this_thread::sleep_for(chrono::milliseconds(100));
WriteGpio(GPIO_Pin1, stoi(argv[1]));
WriteGpio(GPIO_Pin2, stoi(argv[1]));
return 0;
// int value = 0;
// bool useArg = false;
// // 修改点:如果传入了参数,直接使用参数作为电平值 (1 或 0)
// if (argc > 1)
// {
// value = atoi(argv[1]);
// useArg = true;
// cout << "[sendGpioSignal] 使用命令行参数: " << value << endl;
// }
// else
// {
// // 原有的读取文件逻辑
// cout << "[sendGpioSignal] 启动,读取配置: " << SetFile << endl;
// if (GetOutValue(value) == false)
// {
// cerr << "[sendGpioSignal] 未读取到 outPutMode程序退出" << endl;
// return -1;
// }
// cout << "[sendGpioSignal] 读取到 outPutMode=" << (value == 1 ? "true" : "false") << endl;
// }
// // 初始化GPIO引脚
// if (InitGpio(GPIO_Pin1, GPIO_Pin2) != 0)
// {
// cout << "Error: Failed to initialize GPIO pin " << endl;
// return 1;
// }
// // 写入GPIO引脚
// cout << "[sendGpioSignal] 设置 GPIO(" << GPIO_Pin1 << "," << GPIO_Pin2 << ") 为 "
// << (value == 1 ? "HIGH" : "LOW") << endl;
// WriteGpio(GPIO_Pin1, value);
// WriteGpio(GPIO_Pin2, value);
// cout << "[sendGpioSignal] 完成" << endl;
// this_thread::sleep_for(chrono::milliseconds(100));
return 0;
}

View File

@@ -0,0 +1,116 @@
/*
本程序用于控制引脚输出高低电平
*/
#include <iostream>
#include <thread>
#include <wiringPi.h>
#include "/home/orangepi/RKApp/softWareInit/NetraLib/include/Netra.hpp"
using namespace std;
using namespace QCL;
const string SetFile = "/home/orangepi/RKApp/InitAuth/conf/.env";
// 初始化GPIO引脚
int InitGpio(int GPIO_Pin1, int GPIO_Pin2);
// 写入GPIO引脚
void WriteGpio(int GPIO_Pin, int value);
// 获取输出模式
bool GetOutValue(int &value);
int main(int argc, char *argv[])
{
int GPIO_Pin1 = 7;
int GPIO_Pin2 = 8;
int value = 0;
bool useArg = false;
// 修改点:如果传入了参数,直接使用参数作为电平值 (1 或 0)
if (argc > 1)
{
value = atoi(argv[1]);
useArg = true;
cout << "[sendGpioSignal] 使用命令行参数: " << value << endl;
}
else
{
// 原有的读取文件逻辑
cout << "[sendGpioSignal] 启动,读取配置: " << SetFile << endl;
if (GetOutValue(value) == false)
{
cerr << "[sendGpioSignal] 未读取到 outPutMode程序退出" << endl;
return -1;
}
cout << "[sendGpioSignal] 读取到 outPutMode=" << (value == 1 ? "true" : "false") << endl;
}
// 初始化GPIO引脚
if (InitGpio(GPIO_Pin1, GPIO_Pin2) != 0)
{
cout << "Error: Failed to initialize GPIO pin " << endl;
return 1;
}
// 写入GPIO引脚
cout << "[sendGpioSignal] 设置 GPIO(" << GPIO_Pin1 << "," << GPIO_Pin2 << ") 为 "
<< (value == 1 ? "HIGH" : "LOW") << endl;
WriteGpio(GPIO_Pin1, value);
WriteGpio(GPIO_Pin2, value);
cout << "[sendGpioSignal] 完成" << endl;
this_thread::sleep_for(chrono::milliseconds(100));
return 0;
}
// 获取输出模式
bool GetOutValue(int &value)
{
bool flag = true;
// 读取文件
ReadFile rf(SetFile);
if (rf.Open() == false)
{
cerr << "读取文件失败" << endl;
flag = false;
}
auto str = rf.ReadLines();
for (auto &ii : str)
{
if (ii.find("outPutMode") != string::npos)
{
value = (ii.substr(string("outPutMode:").size()) == "true" ? 1 : 0);
}
}
rf.Close();
return flag;
}
// 初始化GPIO引脚
int InitGpio(int GPIO_Pin1, int GPIO_Pin2)
{
// 使用物理引脚编号,确保与实际排针一致
if (wiringPiSetupPhys() != 0)
{
return -1; // 初始化失败
}
pinMode(GPIO_Pin1, OUTPUT);
pinMode(GPIO_Pin2, OUTPUT);
digitalWrite(GPIO_Pin1, LOW); // 默认设置为低电平
digitalWrite(GPIO_Pin2, LOW); // 默认设置为低电平
return 0; // 初始化成功
}
// 写入GPIO引脚
void WriteGpio(int GPIO_Pin, int value)
{
digitalWrite(GPIO_Pin, value == 1 ? HIGH : LOW);
}

View File

@@ -5,7 +5,7 @@ UUID:null
ServerPwd:"17227ca72f30f8bca8158bb78f25b43e"
#以下配置存储GPIO输出高低电平--状态机
outPutMode:true
outPutMode:false
#以下配置存储报警距离
NEAR_THRESHOLD=3

Binary file not shown.

View File

@@ -3,7 +3,8 @@
1.推流摄像头画面,使用UDP原生协议进行推流,交由YOLO模型进行处理
2.接收YOLO传来的坐标和度数据
3.根据获取到的数据绘制边框和相应数据
4.将绘制完毕的视频流继续推流至RTSP服务器用于输出
4.根据距离信息进行报警和图片视频保存
5.将绘制完毕的视频流继续推流至RTSP服务器用于输出
*/
#include <iostream>
@@ -55,6 +56,8 @@ mutex alertMutex; // 保护alertQueue的互斥锁
condition_variable alertcv; // 通知报警线程有新任务
queue<nlohmann::json> alertQueue; // 存放解析后的数据
std::atomic<bool> alertWorkerRunning{false}; // 工作线程运行标志
atomic<bool> outPutMode = false; // 保存报警输出false--电平
// atomic<bool> currentFrameHasDanger{false}; // 是否进行了报警
// mqtt初始化
void MqttInit();
@@ -72,8 +75,14 @@ void mainLoop(VideoCapture &cap, FILE *pipe);
void getMsgCallback(mqtt::const_message_ptr msg);
// 绘制矩形方框和深度信息
void drawRect(int x, int y, int w, int h, double distance);
// 获取报警距离
// 报警线程
void warnThread();
// 获取报警距离和输出模式
bool GetDistance();
// 调用报警输出程序
void setGPIOLevel(int level);
// // 状态机
// void warnStatus();
int main()
{
@@ -102,6 +111,135 @@ int main()
return 0;
}
// 调用报警输出程序
void setGPIOLevel(int level)
{
string cmd = "echo 'orangepi' | sudo -S /home/orangepi/RKApp/GPIOSignal/bin/sendGpioSignal " + to_string(level);
system(cmd.c_str());
}
// // 状态机
// void warnStatus()
// {
// thread([]()
// {
// bool isAlarm = false;
// auto lastDangerTime = chrono::steady_clock::now();
// while(alertWorkerRunning.load())
// {
// } });
// }
// 报警线程
void warnThread()
{
// 开启报警线程
thread([]()
{
//状态变量
bool isAlarming = false; //报警状态
auto lastDangerTime = chrono::steady_clock::now(); //上次报警时间
//读取配置设置初始状态
GetDistance();
int normalLevel = outPutMode?0:1; //false:正常高,输出低,true:正常低,输出高
int alarmLevel = outPutMode?1:0; //报警输出,true:报警高,false:报警低
cout << "normalLevel = " << normalLevel <<",alarmLevel = " << alarmLevel << endl;
//设置初始状态为正常状态
setGPIOLevel(normalLevel);
while (alertWorkerRunning.load())
{
unique_lock<mutex> lk(alertMutex);
// 等待条件,队列非空或者收到停止信号
if(isAlarming)
{ //如果触发报警,就每每100ms检查一次
alertcv.wait_for(lk,100ms,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
}
else{
//没有触发报警,就死等
alertcv.wait(lk,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
}
//如果线程应退出切队列为空,退出循环
if(alertQueue.empty() && !alertWorkerRunning.load())
break;
//当前帧是否触发报警
bool currentFrameHasDanger = false;
//处理队列中的所有信号
while(!alertQueue.empty())
{
auto job = move(alertQueue.front());
alertQueue.pop(); //释放空指针
//解锁,以便于增加队列任务
lk.unlock();
//报警处理函数
try
{
//获取报警距离
GetDistance();
// 更新电平定义(防止运行时修改了配置文件)
normalLevel = outPutMode ? 0 : 1;
alarmLevel = outPutMode ? 1 : 0;
for(auto&ii:job)
{
if(ii["distance"] <= dis.danger)
{ //触发警报
currentFrameHasDanger = true;
}
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
lk.lock(); //重新上锁,以继续处理下个任务
}
//逻辑处理,状态机
if(currentFrameHasDanger)
{
lastDangerTime = chrono::steady_clock::now();
if(!isAlarming)
{
//刚进入报警状态
isAlarming = true;
setGPIOLevel(alarmLevel);
}
}
else
{
//当前帧没有危险,检测是否需要恢复
if(isAlarming)
{
auto now = chrono::steady_clock::now();
auto dur = chrono::duration_cast<chrono::seconds>(now - lastDangerTime).count();
if(dur >= 2)
{//超过两秒恢复正常
isAlarming=false;
setGPIOLevel(normalLevel);
}
}
}
} })
.detach();
}
// 获取报警距离
bool GetDistance()
{
@@ -123,6 +261,12 @@ bool GetDistance()
dis.warn = stoi(line.substr(sizeof("MID_THRESHOLD=") - 1));
else if (line.find("MAX_DISTANCE=") != string::npos)
dis.safe = stoi(line.substr(sizeof("MAX_DISTANCE=") - 1));
else if (line.find("outPutMode:") != string::npos)
{
// 确认输电平模式
string val = line.substr(sizeof("outPutMode:"));
outPutMode = (val == "true");
}
}
rf.Close();
@@ -148,7 +292,7 @@ void drawRect(int x, int y, int w, int h, double distance)
sca = Scalar(0, 255, 0);
rectangle(handleFrame, r, sca, 2);
putText(handleFrame,to_string(distance),Point(x,y),FONT_HERSHEY_SIMPLEX,0.35,Scalar(0,0,0));
putText(handleFrame, to_string(distance), Point(x, y), FONT_HERSHEY_SIMPLEX, 0.35, Scalar(0, 0, 0));
}
// mqtt初始化
@@ -163,43 +307,10 @@ void MqttInit()
client.connect()->wait();
client.subscribe(Topic, Qos)->wait();
// 开启报警线程
thread([]()
{
while (alertWorkerRunning.load())
{
unique_lock<mutex> lk(alertMutex);
// 等待条件,队列非空或者收到停止信号
alertcv.wait(lk,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
alertWorkerRunning = true;
//如果线程应退出切队列为空,退出循环
if(alertQueue.empty() && !alertWorkerRunning.load())
break;
//处理队列中的所有信号
while(!alertQueue.empty())
{
auto job = move(alertQueue.front());
alertQueue.pop(); //释放空指针
//解锁,以便于增加队列任务
lk.unlock();
//报警处理函数
try
{
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
lk.lock(); //重新上锁,以继续处理下个任务
}
} })
.detach();
// 开启线程
warnThread();
}
// mqtt接收订阅消息的回调
@@ -316,9 +427,8 @@ bool processFrame(VideoCapture &cap, FILE *pipe, Mat &frame, int64 &count, chron
// 拷贝视频帧
handleFrame = frame;
// 读取最新检测:短锁获取并将结果拷贝到本地变量
vector<Dection> destCopy;
// 读取最新检测:短锁获取并将结果拷贝到本地变量
{
lock_guard<mutex> lk(detMutex);
destCopy = latestDection; // 复制到本地后释放锁
@@ -330,7 +440,11 @@ bool processFrame(VideoCapture &cap, FILE *pipe, Mat &frame, int64 &count, chron
drawRect(ii.x, ii.y, ii.w, ii.h, ii.distance);
}
latestDection.clear();
// 短锁进行清除
{
lock_guard<mutex> lk(detMutex);
latestDection.clear();
}
// 可选:显示窗口
// imshow("测试画面", frame);