diff --git a/GPIOSignal/bin/sendGpioSignal b/GPIOSignal/bin/sendGpioSignal index e4280fa..a0d5e33 100755 Binary files a/GPIOSignal/bin/sendGpioSignal and b/GPIOSignal/bin/sendGpioSignal differ diff --git a/GPIOSignal/src/sendGpioSignal.cpp b/GPIOSignal/src/sendGpioSignal.cpp index 530bcb5..0553e74 100644 --- a/GPIOSignal/src/sendGpioSignal.cpp +++ b/GPIOSignal/src/sendGpioSignal.cpp @@ -1,7 +1,5 @@ /* - 本程序用于读取配置文件 - 根据配置文件发送高低电平 - 发送引脚固定:7,8 + 本程序用于控制引脚输出高低电平 */ #include @@ -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; } diff --git a/GPIOSignal/src/sendGpioSignal.cpp.bak2 b/GPIOSignal/src/sendGpioSignal.cpp.bak2 new file mode 100644 index 0000000..4d8d14c --- /dev/null +++ b/GPIOSignal/src/sendGpioSignal.cpp.bak2 @@ -0,0 +1,116 @@ +/* + 本程序用于控制引脚输出高低电平 +*/ + +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/InitAuth/conf/.env b/InitAuth/conf/.env index 3a48366..cc82f8d 100644 --- a/InitAuth/conf/.env +++ b/InitAuth/conf/.env @@ -5,7 +5,7 @@ UUID:null ServerPwd:"17227ca72f30f8bca8158bb78f25b43e" #以下配置存储GPIO输出高低电平--状态机 -outPutMode:true +outPutMode:false #以下配置存储报警距离 NEAR_THRESHOLD=3 diff --git a/VideoProsessing/bin/video b/VideoProsessing/bin/video index 8a4a671..848a6cb 100755 Binary files a/VideoProsessing/bin/video and b/VideoProsessing/bin/video differ diff --git a/VideoProsessing/src/main.cpp b/VideoProsessing/src/main.cpp index 739199d..6d0128c 100644 --- a/VideoProsessing/src/main.cpp +++ b/VideoProsessing/src/main.cpp @@ -3,7 +3,8 @@ 1.推流摄像头画面,使用UDP原生协议进行推流,交由YOLO模型进行处理 2.接收YOLO传来的坐标和度数据 3.根据获取到的数据绘制边框和相应数据 -4.将绘制完毕的视频流继续推流至RTSP服务器用于输出 +4.根据距离信息进行报警和图片视频保存 +5.将绘制完毕的视频流继续推流至RTSP服务器用于输出 */ #include @@ -55,6 +56,8 @@ mutex alertMutex; // 保护alertQueue的互斥锁 condition_variable alertcv; // 通知报警线程有新任务 queue alertQueue; // 存放解析后的数据 std::atomic alertWorkerRunning{false}; // 工作线程运行标志 +atomic outPutMode = false; // 保存报警输出false--电平 +// atomic 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 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(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 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 destCopy; - + // 读取最新检测:短锁获取并将结果拷贝到本地变量 { lock_guard 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 lk(detMutex); + latestDection.clear(); + } // 可选:显示窗口 // imshow("测试画面", frame);