[C++/ROS]通过socket控制科星WIFI继电器
????????最近到手一款科星的2路網絡繼電器,官方有提供上位機方便調試,但是要運用在具體項目中就需要自己編寫程序,本文基于ROS平臺通過C++編寫程序通過socket控制該繼電器。
目錄
(一)測試報文
(二)創建調試節點
(三)繼電器控制節點
3.1 入口
3.2 初始化
3.2 判斷調試命令
3.4 連接網絡
3.5 執行命令與讀取繼電器狀態
(四)運行結果
(一)測試報文
??????? 首先通過官方上位機對繼電器繼續配置,設定好繼電器連接的wifi網絡以及自身的ip和端口,再切換到ubuntu系統,下載安裝網絡調試助手,根據官方提供的指令集詳解中的報文進行測試
(二)創建調試節點
????????在正式開始編寫繼電器的控制程序前,先創建一個調試節點,用于對繼電器控制節點發送命令,控制繼電器開關,通過四位數控制繼電器的各個功能。
#include <iostream> #include "ros/ros.h" #include "std_msgs/Int64.h"int main(int argc, char *argv[]){setlocale(LC_ALL, "");ros::init(argc, argv, "manage");ros::NodeHandle nh;ros::Publisher manage_pub = nh.advertise<std_msgs::Int64>("io_cmd", 10);ros::Rate loop_rate(10);std::cout << "選擇輸入: 編號+控制字,例如1001" << std::endl;std::cout << "請先輸入 x+000 連接網絡" << std::endl;std::cout << "001 ——打開DO1"<< std::endl;std::cout << "002 ——關閉DO1"<< std::endl;std::cout << "010 ——打開DO2"<< std::endl;std::cout << "020 ——關閉DO2"<< std::endl;std::cout << "011 ——全開"<< std::endl;std::cout << "022 ——全閉"<< std::endl;std::cout << "066 ——讀取繼電器狀態"<< std::endl;std::cout << "077 ——讀取開光量狀態"<< std::endl;std::cout << "099 ——斷開連接"<< std::endl;while (ros::ok()){std_msgs::Int64 msg;std::cout << "命令輸入:";std::cin >> msg.data;manage_pub.publish(msg);ros::spinOnce();loop_rate.sleep();}return 0; }(三)繼電器控制節點
3.1 入口
int main(int argc, char *argv[]) {setlocale(LC_ALL, "");ros::init(argc, argv, "relay");ros::NodeHandle nh("~");init(nh);ros::Subscriber relay_sub = nh.subscribe("/io_cmd", 10, flag_message);ros::spin(); }?? ????????重點在于初始化和訂閱上面的調試節點獲得命令。
3.2 初始化
void init(ros::NodeHandle &nh) {nh.param<std::string>("relay_addr_1", relay_addr_1, "192.168.1.18");nh.param<std::string>("relay_addr_2", relay_addr_2, "192.168.1.19");relay_pub = nh.advertise<std_msgs::Int64>("status_out", 10);ROS_INFO("Relay node initialization completed!"); }??????? 這里的初始化比較簡單,主要是通過param傳入多個繼電器的ip,實現一次性通訊多個WIFI繼電器,另外是定義了一個發布話題,將后面獲取的繼電器狀態發布出去,方便在項目中應用。
3.2 判斷調試命令
void flag_message(const std_msgs::Int64::ConstPtr& manage) {int control_msg = manage->data;int relay_num = (int)control_msg/1000;// std::cout << relay_num <<std::endl;int control_instruction = control_msg%1000;// std::cout << control_instruction <<std::endl;if(control_instruction == 0 && !network_connections){ //連接網絡recovery(relay_num);send_topic_msg(relay_num*1000);// x000 繼電器聯網成功反饋current_sockfd_num = relay_num;return;}else if(control_instruction != 0 && !network_connections){ROS_INFO("請先連接網絡");return;}if(current_sockfd_num == relay_num && network_connections){switch(control_instruction){case 1: //打開DO1send_relay_msg({ 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x01, 0x00,0x01,0xA4,0x48 });read_feedback_status(relay_num);break;case 2: //關閉DO1send_relay_msg( { 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x00, 0x00,0x01,0xA3,0x46 });read_feedback_status(relay_num);break;case 3: //反轉send_relay_msg({ 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x01, 0x00,0x03,0xA6,0x4C });read_feedback_status(relay_num);break;case 4: //反轉send_relay_msg({ 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x02, 0x00,0x03,0xA7,0x4E });read_feedback_status(relay_num);break;case 10: //打開DO2send_relay_msg( { 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x02, 0x00,0x02,0xA6,0x4C });read_feedback_status(relay_num);break;case 20: //關閉DO2send_relay_msg( { 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x00, 0x00,0x02,0xA4,0x48 });read_feedback_status(relay_num);break;case 11: //全開send_relay_msg({ 0xCC, 0xDD, 0xA1, 0x01, 0xFF, 0xFF, 0xFF,0xFF,0x9E,0x3C });//CC DD A1 01 FF FF FF FF 9E 3Cread_feedback_status(relay_num);break;case 22: //全閉send_relay_msg({ 0xCC, 0xDD, 0xA1, 0x01, 0x00, 0x00, 0xFF,0xFF,0xA0,0x40 });//CC DD A1 01 00 00 FF FF BE 7Cread_feedback_status(relay_num);break;case 66: //讀取繼電器狀態send_relay_msg({ 0xCC, 0xDD, 0xB0, 0x01, 0x00, 0x00, 0x00,0x0D,0xBE,0x7C });read_out_status(relay_num);break;case 77: //讀取開關狀態send_relay_msg( {0xCC, 0xDD, 0xC0, 0x01, 0x00, 0x00, 0x00,0x0D,0xCE,0x9C });read_in_status(relay_num);break;case 99: //斷開連接close(sockfd);network_connections = false ;send_topic_msg(relay_num*1000 + 99);// x099 繼電器斷開連接成功反饋ROS_INFO("斷開連接");break;default:ROS_WARN("[WIFI relay]Abnormal control status of WIFI repeater!");}}else{ROS_WARN("[WIFI relay]Abnormal control status of WIFI repeater!");} }??????? 將main中訂閱的話題消息傳入這個回調函數,根據調試節點中規定的命令條件編寫判斷,分別進行不同功能。
3.4 連接網絡
void recovery(const int &relay_num){if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);exit(0);}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;if(relay_num == 1){servaddr.sin_addr.s_addr = inet_addr( relay_addr_1.c_str());servaddr.sin_port = htons(50000);}else if(relay_num == 2){servaddr.sin_addr.s_addr = inet_addr( relay_addr_2.c_str());servaddr.sin_port = htons(50000); }else{ROS_WARN("WIFI relay No. %u failed to connect to the network",relay_num);return;}if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){printf("connect error: %s(errno: %d)\n",strerror(errno),errno);exit(0);}network_connections = true;ROS_INFO("%u號繼電器連接網絡",relay_num); }??????? 繼電器與主機的通訊依靠socket通信,在接受到連接網絡的命令后創建一個套接字(目前只預留了兩個位置,同時只能連接一個),后面對這個套接字進行操作,關閉網絡連接時注銷這個套接字。
3.5 執行命令與讀取繼電器狀態
void send_relay_msg(const buff_send &relay_msg){send(sockfd, relay_msg.msgs, sizeof(relay_msg),0); }void read_out_status(const int &relay_num){unsigned char buff_recv[4096];int t = recv(sockfd, buff_recv, MAXLINE, 0);if(t > 0){int status_bit = (unsigned int)buff_recv [5];switch(status_bit){case 0:send_topic_msg(relay_num*1000 + 1);ROS_INFO("DO1 OFF,DO2 OFF");break;case 1:send_topic_msg(relay_num*1000 + 2);ROS_INFO("DO1 ON,DO2 OFF");break;case 2:send_topic_msg(relay_num*1000 + 3);ROS_INFO("DO1 OFF,DO2 ON");break;case 3:send_topic_msg(relay_num*1000 + 4);ROS_INFO("DO1 ON,DO2 ON");break;default:ROS_WARN("[WIFI relay]Abnormal WIFI relay status!");return;}}else{ROS_WARN("[WIFI relay]Abnormal reading of WIFI relay data status!");} }void read_in_status(const int &relay_num){unsigned char buff_recv[4096];int t = recv(sockfd, buff_recv, MAXLINE, 0);if(t > 0){int status_bit = (unsigned int)buff_recv [5];switch(status_bit){case 0:send_topic_msg(relay_num*1000 + 10);ROS_INFO("DI1 OFF,DI2 OFF");break;case 1:send_topic_msg(relay_num*1000 + 20);ROS_INFO("DI1 ON,DI2 OFF");break;case 2:send_topic_msg(relay_num*1000 + 30);ROS_INFO("DI1 OFF,DI2 ON");break;case 3:send_topic_msg(relay_num*1000 + 40);ROS_INFO("DI1 ON,DI2 ON");break;default:ROS_WARN("[WIFI relay]Abnormal WIFI relay status!");return;}}else{ROS_WARN("[WIFI relay]Abnormal reading of WIFI relay data status!");} }void read_feedback_status(const int &relay_num){char buff_recv[4096];int t = recv(sockfd, buff_recv, MAXLINE, 0);if(t > 0){send_topic_msg(relay_num*1000 + 88);// x088 繼電器執行成功反饋// std::cout << buff_recv << std::endl;ROS_INFO("Sending msg :%c%c!",buff_recv[0],buff_recv[1]);} }在完成3.2的判斷之后,將下發的命令對應的報文通過socket的send發送到網絡繼電器,同時通過read讀取網絡繼電器回饋的報文,可以判斷命令是否成功執行。并可以通過查詢繼電器狀態的報文主動獲取網絡繼電器當前的狀態。
(四)運行結果
由于沒有連接上網絡繼電器,第一次發送命令時會直接崩潰,第二次直接發送指令報文,能正確識別并提醒。
總結
以上是生活随笔為你收集整理的[C++/ROS]通过socket控制科星WIFI继电器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单片机php-cgi,STM32: 基于
- 下一篇: 关于basler相机传输速度过慢/传输丢