|
@@ -0,0 +1,452 @@
|
|
|
+/*
|
|
|
+ * Copyright : Cookoo Science, All Rights Reserved ©2022
|
|
|
+ *
|
|
|
+ * cookoo_cam.cpp
|
|
|
+ *
|
|
|
+ * Author cookoo
|
|
|
+ * 本代码展示cookoo-接口+F9K的使用
|
|
|
+ */
|
|
|
+#include <stdio.h>
|
|
|
+#include <signal.h>
|
|
|
+#include <string.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <sys/types.h>
|
|
|
+#include <sys/socket.h>
|
|
|
+#include <sys/un.h>
|
|
|
+#include <stddef.h>
|
|
|
+#include <thread>
|
|
|
+#include <chrono>
|
|
|
+#include <iostream>
|
|
|
+#include "cookoo_sdk.h"
|
|
|
+
|
|
|
+using namespace cookoo;
|
|
|
+
|
|
|
+static const char* str_imu_auto_sw[] =
|
|
|
+{
|
|
|
+ "\033[41mOFF\033[0m",
|
|
|
+ "\033[42mON\033[0m"
|
|
|
+};
|
|
|
+
|
|
|
+static const char* str_imu_status[] =
|
|
|
+{
|
|
|
+ "\033[41mOFF\033[0m",
|
|
|
+ "\033[43mINITIALIZING\033[0m",
|
|
|
+ "\033[43mINITIALIZING\033[0m",
|
|
|
+ "\033[44mCOARSE\033[0m",
|
|
|
+ "\033[42mFINE\033[0m"
|
|
|
+};
|
|
|
+
|
|
|
+volatile bool sStop = false;
|
|
|
+static void sig_handler(int sign)
|
|
|
+{
|
|
|
+ switch (sign) {
|
|
|
+ case SIGINT:
|
|
|
+ case SIGTERM:
|
|
|
+ sStop = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SIGALRM:
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// UNX Domain Socket 封装
|
|
|
+// #define RECV_USE_SELECT
|
|
|
+struct SENSSION
|
|
|
+{
|
|
|
+ void* addr;
|
|
|
+ int len;
|
|
|
+};
|
|
|
+
|
|
|
+class Uds
|
|
|
+{
|
|
|
+public:
|
|
|
+ Uds();
|
|
|
+ ~Uds();
|
|
|
+
|
|
|
+public:
|
|
|
+ int Bind(const std::string& path);
|
|
|
+ void Close();
|
|
|
+ SENSSION AddSenssion(const std::string& path);
|
|
|
+ void DelSenssion(SENSSION& senssion);
|
|
|
+ int Recv(void* data, int len);
|
|
|
+ int Send(const SENSSION& senssion, const void* data, int len);
|
|
|
+
|
|
|
+private:
|
|
|
+ int m_local_fd = -1;
|
|
|
+ std::string m_path;
|
|
|
+};
|
|
|
+
|
|
|
+Uds::Uds()
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+Uds::~Uds()
|
|
|
+{
|
|
|
+ Close();
|
|
|
+}
|
|
|
+
|
|
|
+int Uds::Bind(const std::string& path)
|
|
|
+{
|
|
|
+ if (m_local_fd > 0)
|
|
|
+ {
|
|
|
+ perror("alrady binded!");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ m_local_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
|
|
+ if (m_local_fd < 0)
|
|
|
+ {
|
|
|
+ perror("socket failed");
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct sockaddr_un local;
|
|
|
+ memset(&local, 0, sizeof(local));
|
|
|
+ local.sun_family = AF_UNIX;
|
|
|
+
|
|
|
+ if (strlen(path.c_str()) > sizeof(local.sun_path) - 1)
|
|
|
+ {
|
|
|
+ perror("Server socket path too long");
|
|
|
+ close(m_local_fd);
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+
|
|
|
+ //服务器先删除了与该地址匹配的路径名,以防出现这个路径名已经存在的情况
|
|
|
+ char cmd[256] = {0};
|
|
|
+ snprintf(cmd, sizeof(cmd), "rm -rf %s > /dev/null 2>&1", path.c_str());
|
|
|
+ system(cmd);
|
|
|
+ strcpy(local.sun_path, path.c_str());
|
|
|
+ // delete socket file if such already exists
|
|
|
+ unlink(path.c_str());
|
|
|
+ int reuse = 1;
|
|
|
+ if ( setsockopt(m_local_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0 )
|
|
|
+ {
|
|
|
+ close(m_local_fd);
|
|
|
+ perror("setsockopt failed");
|
|
|
+ return -4;
|
|
|
+ }
|
|
|
+
|
|
|
+ // bind socket to address in UNIX domain
|
|
|
+ if ( bind(m_local_fd, (struct sockaddr*)&local, sizeof(struct sockaddr_un)) < 0 )
|
|
|
+ {
|
|
|
+ close(m_local_fd);
|
|
|
+ perror("error: bind failed");
|
|
|
+ return -5;
|
|
|
+ }
|
|
|
+
|
|
|
+ snprintf(cmd, sizeof(cmd), "chmod 777 %s > /dev/null 2>&1", path.c_str());
|
|
|
+ system(cmd);
|
|
|
+ m_path = path;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void Uds::Close()
|
|
|
+{
|
|
|
+ unlink(m_path.c_str());
|
|
|
+ if (m_local_fd > 0)
|
|
|
+ {
|
|
|
+ close(m_local_fd);
|
|
|
+ m_local_fd = -1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+SENSSION Uds::AddSenssion(const std::string& path)
|
|
|
+{
|
|
|
+ SENSSION ret;
|
|
|
+ struct sockaddr_un* addr = new struct sockaddr_un;
|
|
|
+ memset(addr, 0, sizeof(struct sockaddr_un));
|
|
|
+ addr->sun_family = AF_UNIX;
|
|
|
+ strcpy(addr->sun_path, path.c_str());
|
|
|
+
|
|
|
+ ret.addr = addr;
|
|
|
+ ret.len = sizeof(struct sockaddr_un);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void Uds::DelSenssion(SENSSION& senssion)
|
|
|
+{
|
|
|
+ if (senssion.addr)
|
|
|
+ {
|
|
|
+ struct sockaddr_un* tmp = (struct sockaddr_un*)senssion.addr;
|
|
|
+ delete tmp;
|
|
|
+ senssion.addr = nullptr;
|
|
|
+ }
|
|
|
+ senssion.len = 0;
|
|
|
+}
|
|
|
+
|
|
|
+int Uds::Recv(void* data, int len)
|
|
|
+#ifdef RECV_USE_SELECT
|
|
|
+{
|
|
|
+ if (!data || len < 1)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ int ret = -1;
|
|
|
+ struct timeval tv;
|
|
|
+ fd_set readfds;
|
|
|
+
|
|
|
+ tv.tv_sec = 0;
|
|
|
+ tv.tv_usec = 100;
|
|
|
+
|
|
|
+ FD_ZERO(&readfds);
|
|
|
+ FD_SET(m_local_fd, &readfds);
|
|
|
+ int nSelRet = select(m_local_fd + 1, &readfds, NULL, NULL, &tv);
|
|
|
+ if (nSelRet < 0 )
|
|
|
+ {
|
|
|
+ printf("Error select\n");
|
|
|
+ }
|
|
|
+ else if (nSelRet == 0)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if( FD_ISSET(m_local_fd, &readfds) )
|
|
|
+ {
|
|
|
+ ret = recvfrom(m_local_fd, data, len, 0, 0, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+ if (data && len > 0)
|
|
|
+ {
|
|
|
+ ret = recvfrom(m_local_fd, data, len, 0, 0, 0);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+int Uds::Send(const SENSSION& senssion, const void* data, int len)
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+ if (senssion.addr && senssion.len > 0 && data && len > 0)
|
|
|
+ {
|
|
|
+ ret = sendto(m_local_fd, data, len, 0, (struct sockaddr*)senssion.addr, senssion.len);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static float vv6Speed = 0;// 车速 km/h
|
|
|
+// demo程序以测试车-VV6为例从底盘CAN上获取车速
|
|
|
+// VV6测试使用,其他车型不适用
|
|
|
+void speed_vv6()
|
|
|
+{
|
|
|
+ cookoo::Ck_Can can0(cookoo::Ck_Can::CK_CAN(0), 500000);
|
|
|
+ cookoo::Ck_Can::ck_can_frame can_recv = {0};
|
|
|
+ uint8_t DIR;
|
|
|
+
|
|
|
+ while (!sStop)
|
|
|
+ {
|
|
|
+ //VV6读车速--方向
|
|
|
+ if ( can0.Read(can_recv) > 0 )
|
|
|
+ {
|
|
|
+ if(can_recv.can_id == 0x240)
|
|
|
+ {
|
|
|
+ //车速 km/h
|
|
|
+ vv6Speed = (((can_recv.data[7] & 0xF8) >> 3) | (can_recv.data[6] << 5)) * 0.05625f;
|
|
|
+ // 倒车
|
|
|
+ DIR = can_recv.data[1] & 0x03;
|
|
|
+ if (0x02 == DIR)
|
|
|
+ {
|
|
|
+ vv6Speed = -vv6Speed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
+ }
|
|
|
+}
|
|
|
+//通过OBD获得车速
|
|
|
+int obdSpeed = 0;
|
|
|
+void speed_obd()
|
|
|
+{
|
|
|
+ cookoo::Ck_Can can0(cookoo::Ck_Can::CK_CAN(1), 500000);
|
|
|
+ cookoo::Ck_Can::ck_can_frame can_send = {0};
|
|
|
+ cookoo::Ck_Can::ck_can_frame can_recv = {0};
|
|
|
+ can_send.can_id = 0x07DF;
|
|
|
+ can_send.can_dlc = 8;
|
|
|
+ can_send.data[0] = 0x02;
|
|
|
+ can_send.data[1] = 0x01;
|
|
|
+ can_send.data[2] = 0x0D;
|
|
|
+ can_send.data[3] = 0x00;
|
|
|
+ can_send.data[4] = 0x00;
|
|
|
+ can_send.data[5] = 0x00;
|
|
|
+ can_send.data[6] = 0x00;
|
|
|
+ can_send.data[7] = 0x00;
|
|
|
+
|
|
|
+ uint32_t cnt = 0;
|
|
|
+ while (!sStop)
|
|
|
+ {
|
|
|
+ //发送OBD查询车速
|
|
|
+ if (++cnt % 50 == 0)
|
|
|
+ {
|
|
|
+ can0.Write(can_send);
|
|
|
+ }
|
|
|
+ //读车速
|
|
|
+ if ( can0.Read(can_recv) > 0 )
|
|
|
+ {
|
|
|
+ if(can_recv.can_id == 0x07E8)
|
|
|
+ {
|
|
|
+ //车速 km/h
|
|
|
+ obdSpeed = can_recv.data[3];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static inline void PrintDetail()
|
|
|
+{
|
|
|
+ printf("********************************************************************\n");
|
|
|
+ printf(" APP Name : COOKOO-GPS(F9K)-DEMO\n");
|
|
|
+ printf(" Custom : COOKOO\n");
|
|
|
+ printf(" Version : 0.9.11\n");
|
|
|
+ printf(" Compile : %s-%s\n", __DATE__, __TIME__);
|
|
|
+ printf(" Copyright : Cookoo Science, All Rights Reserved ©2023\n");
|
|
|
+ printf("*********************************************************************\n");
|
|
|
+}
|
|
|
+
|
|
|
+static inline void print_usage(const char* str)
|
|
|
+{
|
|
|
+ printf("=====================================================================\n");
|
|
|
+ printf("Usage:\n");
|
|
|
+ printf(" sudo %s RUN_MOD SPEED_MOD [CALI_PARAM]\n", str);
|
|
|
+ printf(" RUN_MOD : 1-正常模式, 2-标定模式\n");
|
|
|
+ printf(" SPEED_MOD: 0-不输入; 1-软件接口输入车速; 2-硬件输入脉冲\n");
|
|
|
+ printf(" CALI_PARAM:安装测量距离参数, 6个值, 单位cm, RUN_MOD为2时需要输入\n");
|
|
|
+ printf(" 例:\n");
|
|
|
+ printf(" 正常模式+无车速 sudo %s 1 0\n", str);
|
|
|
+ printf(" 标定模式+无车速 sudo %s 2 0 0 0 50 0 0 95\n", str);
|
|
|
+ printf("=====================================================================\n");
|
|
|
+ printf(" 步骤:\n");
|
|
|
+ printf(" 1. 运行本程序,输入RUN_MOD为2,进行标定\n");
|
|
|
+ printf(" 2. 标定根据SPEED_MOD不同分为3个模式\n");
|
|
|
+ printf(" 3. 运行程序标定, 以软件输入车速为例:运行程序输入 2 1 0 0 50 0 0 95\n");
|
|
|
+ printf(" 4. 跑车标定,左右转弯,转弯时车速尽量大一些\n");
|
|
|
+ printf(" 5. 查看输出状态(IMU AUTO Alignment, Alignment Status 已高亮变色),\n");
|
|
|
+ printf(" %s-标定中, %s-粗略标定, %s-精确标定\n", str_imu_status[1], str_imu_status[3], str_imu_status[4]);
|
|
|
+ printf(" 6. Ctrl+C 停止程序, 程序会自动保存当前标定结果\n");
|
|
|
+ printf(" 7. 停止程序后,等待30秒,下电重启机器\n");
|
|
|
+ printf(" 8. 上电后,再次运行程序, 本示例采用软件车速模式, 输入 1 1 运行\n");
|
|
|
+ printf(" 9. 跑车采集数据, 数据自动按照[GPS-{MOD}-{时间}.txt]的形式命名\n");
|
|
|
+ printf("10. 过程中可使用UI程序实时查看车辆行驶轨迹\n");
|
|
|
+ printf("11. 若车速一种车速模式测试完毕,需要测试另一个车速模式,重复步骤3-10即可\n");
|
|
|
+ printf(" 若不需要改变车速模式,并且安装位置没有变化,重复步骤8-10即可\n");
|
|
|
+ printf(" 标定: 2 0 或 2 1 或 2 2\n");
|
|
|
+ printf(" 采集: 1 0 或 1 1 或 1 2\n");
|
|
|
+ printf(" \033[31m!注意:标定时用的哪个车速模式,采集时与之相对应\033[0m\n");
|
|
|
+ printf("=====================================================================\n");
|
|
|
+ printf("硬件输入脉冲时,需要工装配合\n");
|
|
|
+ printf("软件输入车速时,需要接VV6底盘CAN或OBD CAN\n");
|
|
|
+ printf("详细接口使用参考源码cookoo_gps.cpp\n");
|
|
|
+ printf("\033[31m注意!RUN_MOD输入2会清除原标定结果且不可恢复,需要重新跑车标定\033[0m\n");
|
|
|
+ printf("=====================================================================\n");
|
|
|
+}
|
|
|
+
|
|
|
+static inline std::string GetTimeStr()
|
|
|
+{
|
|
|
+ struct timeval tv;
|
|
|
+ gettimeofday(&tv, nullptr);
|
|
|
+ struct tm now_time;
|
|
|
+ localtime_r (&tv.tv_sec, &now_time);
|
|
|
+ char dateTime[30];
|
|
|
+ strftime(dateTime, 30, "%Y_%m_%d_%H%M%S", &now_time);
|
|
|
+ char str[64];
|
|
|
+ snprintf(str, sizeof(str),"%s_%03lu", dateTime, tv.tv_usec / 1000);
|
|
|
+
|
|
|
+ return str;
|
|
|
+}
|
|
|
+
|
|
|
+static inline uint64_t GetTimeU64()
|
|
|
+{
|
|
|
+ struct timeval tv;
|
|
|
+ gettimeofday(&tv, nullptr);
|
|
|
+ return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ std::string ip = "116.63.46.168";
|
|
|
+ int port = 8002;
|
|
|
+ std::string user = "63ae1792";
|
|
|
+ std::string passwd = "97786";
|
|
|
+ std::string mountpoint = "RTCM32GGB";
|
|
|
+
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_Ntrip(ip, port, user, passwd, mountpoint);
|
|
|
+
|
|
|
+
|
|
|
+ // IMU数据输出,0-不输出
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_IMU_DATA_OUT(1);
|
|
|
+
|
|
|
+ // 设置车速输入模式,0-不输入; 1-软件接口输入车速; 2-硬件输入脉冲
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_SPD_IN_MOD(0);
|
|
|
+
|
|
|
+ // 设置NMEA输出频率30Hz
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_NMEA_FREQ(30);
|
|
|
+ // 设置NMEA输出报文 GGA RMC ...
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_NMEA_MSG("GGA", true);
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Set_NMEA_MSG("RMC", true);
|
|
|
+
|
|
|
+ // 开始运行
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Start();
|
|
|
+
|
|
|
+
|
|
|
+ int speed = 0;
|
|
|
+ char* uds_send_data = new char[4096];
|
|
|
+ // 保存的文件名
|
|
|
+
|
|
|
+ uint64_t last_time = 0;
|
|
|
+ uint64_t curr_time = 0;
|
|
|
+ uint8_t imu_stat = 0;
|
|
|
+ // 读取数据
|
|
|
+ while (!sStop)
|
|
|
+ {
|
|
|
+ // 车速VV6底盘或者OBD
|
|
|
+ speed = vv6Speed;
|
|
|
+ // 读取GPS NMEA数据
|
|
|
+ std::string gps_str = cookoo::Ck_GPS::GetInstance()->Read_GPS();
|
|
|
+ if ( gps_str.length() )
|
|
|
+ {
|
|
|
+
|
|
|
+ printf("%s", gps_str.data());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 获取IMU状态, 1秒1次
|
|
|
+ curr_time = GetTimeU64();
|
|
|
+ if (curr_time >= last_time + 1000)
|
|
|
+ {
|
|
|
+ last_time = curr_time;
|
|
|
+ imu_stat = cookoo::Ck_GPS::GetInstance()->Get_IMU_STATE();
|
|
|
+ // IMU状态 高4位-AUTO 自动标定开关, 低4位 3-COARSE, 4-FINE
|
|
|
+ printf("IMU AUTO Alignment: %s, Alignment Status: %s\n",
|
|
|
+ str_imu_auto_sw[imu_stat >> 4 & 0x01],
|
|
|
+ str_imu_status[imu_stat & 0x07]);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ cookoo::Ck_GPS::GetInstance()->Stop();
|
|
|
+ cookoo::Ck_GPS::DelInstance();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|