0
0
Files
test/gyroHS.cpp

437 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/select.h>
#include <errno.h>
#include <signal.h>
#include <arpa/inet.h>
#include <string>
#include <vector>
#include <fstream>
#include <jsoncpp/json/json.h>
#include "SimMsg.h"
#include "gyroHS.h"
using namespace std;
/* ------------------ 全局变量 ------------------ */
// FastDDS硬件服务化相关
SimMsg* GyroHS_part = nullptr;
string servername = "Gyro_Hardware_Service";
string topic_name_cmd = "Command";
string topic_name_tlm = "Telemetry";
// 陀螺仪设备
Gyro_Device gyro_device = {-1, nullptr, 115200, 0, 0, 0, 0, 0, 0, 0};
// 配置参数
static float gyro_K[3] = {289752.5, 299114.7, 282454.6};
static float gyro_w0[3] = {0.017, 0.205, 0.369};
// 互斥锁
pthread_mutex_t cache_mutex = PTHREAD_MUTEX_INITIALIZER;
/* ------------------ 解析JSON配置文件 ------------------ */
int parse_gyro_config_file(const char* filename, GyroConfig* config) {
ifstream config_file(filename);
if (!config_file.is_open()) {
cerr << "[ERROR] Cannot open config file: " << filename << endl;
return -1;
}
// 解析JSON
Json::CharReaderBuilder reader_builder;
Json::Value root;
string errs;
if (!Json::parseFromStream(reader_builder, config_file, &root, &errs)) {
cerr << "[ERROR] Failed to parse JSON: " << errs << endl;
return -1;
}
// 读取陀螺仪配置
if (root.isMember("gyro")) {
const Json::Value& gyro = root["gyro"];
// 是否启用
config->enabled = gyro.isMember("enabled") ? gyro["enabled"].asBool() : true;
if (!config->enabled) {
cout << "[INFO] Gyro is disabled in config" << endl;
return 0;
}
// 串口设备
config->device = gyro.isMember("device") ? gyro["device"].asString() : "/dev/tnt0";
// 波特率
config->baudrate = gyro.isMember("baudrate") ? gyro["baudrate"].asInt() : 115200;
cout << "[INFO] Gyro config loaded: device=" << config->device
<< ", baudrate=" << config->baudrate << endl;
return 0;
} else {
cerr << "[ERROR] No 'gyro' section found in config file" << endl;
return -1;
}
}
/* ------------------ 日志函数 ------------------ */
void GyroHSWriteLog(const std::string &msg) {
std::cout << "[GyroHS] " << msg << std::endl;
}
/* ------------------ FastDDS初始化 ------------------ */
void Fastdds_init(uint8_t domainid, string appname) {
vector<string> parameters;
string expression = "dest = '"+ servername + "'";
if (nullptr == GyroHS_part) {
GyroHS_part = new SimMsg(domainid, 3000, appname, GyroHSWriteLog);
// 创建发布者和订阅者
GyroHS_part->create_pub(topic_name_tlm);
// 注册回调函数
GyroHS_part->create_sub(topic_name_tlm, telemetry_callback, expression, parameters);
}
}
/* ------------------ 遥测回调函数 ------------------ */
void telemetry_callback(string src, string dest, string type,
string reserve1, string reserve2,
vector<uint8_t>& data) {
if (type != "command" || data.empty()) {
return;
}
if (data[0] == 0xFF) {
pthread_mutex_lock(&cache_mutex);
GYRO_Info_Frame response_frame;
int result = read_gyro_angle_delta(&response_frame);
pthread_mutex_unlock(&cache_mutex);
if (result == SAT_ERR_OK) {
telemetry_Pub((uint8_t *)&response_frame, src, sizeof(GYRO_Info_Frame));
cout << "[OK] Gyro data sent" << endl;
} else {
// 发送错误状态
response_frame.x_angle_delta = 0.0;
response_frame.y_angle_delta = 0.0;
response_frame.z_angle_delta = 0.0;
telemetry_Pub((uint8_t *)&response_frame, src, sizeof(GYRO_Info_Frame));
cerr << "[ERROR] Failed to read gyro data" << endl;
}
}
}
/* ------------------ 遥测发布 ------------------ */
void telemetry_Pub(uint8_t* data, const string& dest, uint16_t len) {
if (GyroHS_part) {
GyroHS_part->publish(topic_name_tlm, servername, dest, "telemetry", data, len);
}
}
/* ------------------ 串口初始化 ------------------ */
int gyro_uart_init(const char *dev, int baudrate) {
// 如果已经打开,先关闭
if (gyro_device.fd > 0) {
close(gyro_device.fd);
gyro_device.fd = -1;
}
// 打开串口
gyro_device.fd = open(dev, O_RDWR | O_NOCTTY);
if (gyro_device.fd < 0) {
perror("open serial failed");
return SAT_ERR_SERIAL;
}
// 配置串口参数
struct termios options;
memset(&options, 0, sizeof(options));
if (tcgetattr(gyro_device.fd, &options) < 0) {
perror("tcgetattr failed");
close(gyro_device.fd);
gyro_device.fd = -1;
return SAT_ERR_SERIAL;
}
// 设置波特率
speed_t baud;
switch (baudrate) {
case 9600: baud = B9600; break;
case 19200: baud = B19200; break;
case 38400: baud = B38400; break;
case 57600: baud = B57600; break;
case 115200: baud = B115200; break;
case 230400: baud = B230400; break;
case 460800: baud = B460800; break;
case 921600: baud = B921600; break;
default: baud = B115200; break;
}
cfsetispeed(&options, baud);
cfsetospeed(&options, baud);
// 8位数据位奇校验1位停止位
options.c_cflag |= PARENB; // 启用奇偶校验
options.c_cflag |= PARODD; // 奇校验
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; // 8位数据位
options.c_cflag |= CREAD | CLOCAL; // 启用接收,忽略调制解调器状态
// 禁用软件流控
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
// 原始模式
options.c_lflag = 0; // 禁用规范输入、回显、信号
options.c_oflag = 0; // 禁用输出处理
// 设置超时
options.c_cc[VMIN] = 0; // 最小读取字符数
options.c_cc[VTIME] = 10; // 超时时间(十分之一秒)= 1秒
// 设置串口属性
if (tcsetattr(gyro_device.fd, TCSANOW, &options) < 0) {
perror("tcsetattr failed");
close(gyro_device.fd);
gyro_device.fd = -1;
return SAT_ERR_SERIAL;
}
// 刷新缓冲区
tcflush(gyro_device.fd, TCIOFLUSH);
// 保存设备信息
gyro_device.dev = dev;
gyro_device.baudrate = baudrate;
gyro_device.on_off_status = 1;
printf("[OK] GYRO UART init dev=%s baud=%d fd=%d\n",
dev, baudrate, gyro_device.fd);
return SAT_ERR_OK;
}
/* ------------------ 24位补码转 int32 ------------------ */
static int32_t convert_24bit_to_int32(const uint8_t *data) {
int32_t value = (data[0] << 16) | (data[1] << 8) | data[2];
if (value & 0x800000) {
value |= 0xFF000000; // 符号扩展
}
return value;
}
/* ------------------ 数据解析 ------------------ */
int gyro_data_extraction(const uint8_t *buf, GYRO_Info_Frame *info) {
if (!buf || !info) return SAT_ERR_DATA;
// 解析X轴角增量
int32_t x_raw = convert_24bit_to_int32(&buf[1]);
uint16_t x_integral_time = (buf[4] << 8) | buf[5];
// 解析Y轴角增量
int32_t y_raw = convert_24bit_to_int32(&buf[6]);
uint16_t y_integral_time = (buf[9] << 8) | buf[10];
// 解析Z轴角增量
int32_t z_raw = convert_24bit_to_int32(&buf[11]);
uint16_t z_integral_time = (buf[14] << 8) | buf[15];
if (x_integral_time == 0 || y_integral_time == 0 || z_integral_time == 0) {
fprintf(stderr, "[ERROR] Integral time zero\n");
return SAT_ERR_DATA;
}
// 计算角速度,单位度/秒
info->x_angle_delta = (float)x_raw * 1000.0f / x_integral_time / gyro_K[0] - gyro_w0[0] / 3600.0f;
info->y_angle_delta = (float)y_raw * 1000.0f / y_integral_time / gyro_K[1] - gyro_w0[1] / 3600.0f;
info->z_angle_delta = (float)z_raw * 1000.0f / z_integral_time / gyro_K[2] - gyro_w0[2] / 3600.0f;
return SAT_ERR_OK;
}
/* ------------------ 读取陀螺仪数据 ------------------ */
int read_gyro_angle_delta(GYRO_Info_Frame *info) {
if (gyro_device.fd < 0) return SAT_ERR_SERIAL;
uint8_t buf[GYRO_FRAME_LENGTH];
const int MAX_RETRY = 10;
for (int retry = 0; retry < MAX_RETRY; ++retry) {
tcflush(gyro_device.fd, TCIOFLUSH);
// 发送陀螺仪控制命令
uint8_t send_cmd[2] = {0x55, 0x68};
if (write(gyro_device.fd, send_cmd, 2) != 2) {
fprintf(stderr, "[ERROR] Failed to send command to gyro\n");
gyro_device.send_cmd_cnt++;
return SAT_ERR_SEND_CMD;
}
memset(buf, 0, sizeof(buf));
int total_read = 0;
// 设置总超时时间1秒
struct timeval start_time, current_time;
gettimeofday(&start_time, NULL);
const long TOTAL_TIMEOUT_MS = 1000;
while (total_read < GYRO_FRAME_LENGTH) {
// 检查总超时
gettimeofday(&current_time, NULL);
long elapsed_ms = (current_time.tv_sec - start_time.tv_sec) * 1000 +
(current_time.tv_usec - start_time.tv_usec) / 1000;
if (elapsed_ms > TOTAL_TIMEOUT_MS) {
fprintf(stderr, "[ERROR] Timeout waiting gyro frame (%d/%d bytes)\n",
total_read, GYRO_FRAME_LENGTH);
gyro_device.send_cmd_cnt++;
break;
}
// select 等待数据
struct timeval timeout;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(gyro_device.fd, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 100000; // 100ms
int ret = select(gyro_device.fd + 1, &readfds, NULL, NULL, &timeout);
if (ret < 0) {
perror("select error");
return SAT_ERR_SELECT;
} else if (ret == 0) {
continue; // 超时但没超过总超时,继续等
}
if (FD_ISSET(gyro_device.fd, &readfds)) {
int bytes = read(gyro_device.fd, buf + total_read,
GYRO_FRAME_LENGTH - total_read);
if (bytes > 0) {
total_read += bytes;
} else if (bytes == 0) {
usleep(10000); // 没读到数据,等一下
} else {
perror("read error");
return SAT_ERR_SERIAL;
}
}
}
// 检查未响应计数是否达到阈值,达到则复位串口
if (gyro_device.send_cmd_cnt >= 10) {
fprintf(stderr, "[ERROR] Too many gyro timeouts, resetting UART\n");
gyro_uart_init(gyro_device.dev, gyro_device.baudrate);
gyro_device.uart_reset_cnt++;
gyro_device.send_cmd_cnt = 0;
continue;
}
if (total_read < GYRO_FRAME_LENGTH) {
fprintf(stderr, "[ERROR] gyro data too short: got %d bytes, expected %d\n",
total_read, GYRO_FRAME_LENGTH);
gyro_device.length_err_cnt++;
update_gyro_fault_count(&gyro_device);
continue;
}
// 校验帧头
if (buf[0] != 0x97) {
fprintf(stderr, "[ERROR] Invalid gyro frame header: %02X\n", buf[0]);
gyro_device.header_err_cnt++;
gyro_device.send_cmd_cnt++;
update_gyro_fault_count(&gyro_device);
continue;
}
// 校验和
uint8_t checksum = 0;
for (int i = 0; i < GYRO_FRAME_LENGTH - 1; i++) {
checksum += buf[i];
}
if (buf[GYRO_FRAME_LENGTH - 1] != checksum) {
fprintf(stderr, "[ERROR] gyro checksum mismatch: calc=%02X recv=%02X\n",
checksum, buf[GYRO_FRAME_LENGTH - 1]);
gyro_device.check_err_cnt++;
gyro_device.send_cmd_cnt++;
update_gyro_fault_count(&gyro_device);
continue;
}
// 解析数据成功,重置未响应计数
gyro_device.send_cmd_cnt = 0;
// 解析数据
int result = gyro_data_extraction(buf, info);
if (result == SAT_ERR_OK) {
// 填充设备状态和错误计数
info->on_off_status = gyro_device.on_off_status;
info->header_err_cnt = gyro_device.header_err_cnt;
info->check_err_cnt = gyro_device.check_err_cnt;
info->length_err_cnt = gyro_device.length_err_cnt;
info->uart_reset_cnt = gyro_device.uart_reset_cnt;
info->fault_cnt = gyro_device.fault_cnt;
printf("[INFO] gyro angular velocity: x=%.8f, y=%.8f, z=%.8f\n",
info->x_angle_delta, info->y_angle_delta, info->z_angle_delta);
return SAT_ERR_OK;
} else {
fprintf(stderr, "[ERROR] gyro data extraction failed: %d\n", result);
gyro_device.send_cmd_cnt++;
update_gyro_fault_count(&gyro_device);
return result;
}
}
fprintf(stderr, "[ERROR] gyro read failed after %d retries\n", MAX_RETRY);
// 串口复位
gyro_uart_init(gyro_device.dev, gyro_device.baudrate);
gyro_device.uart_reset_cnt++;
update_gyro_fault_count(&gyro_device);
// 返回错误数据
memset(info, 0, sizeof(GYRO_Info_Frame));
info->on_off_status = gyro_device.on_off_status;
info->header_err_cnt = gyro_device.header_err_cnt;
info->check_err_cnt = gyro_device.check_err_cnt;
info->length_err_cnt = gyro_device.length_err_cnt;
info->uart_reset_cnt = gyro_device.uart_reset_cnt;
info->fault_cnt = gyro_device.fault_cnt;
return SAT_ERR_UNKNOWN;
}
/* ------------------ 硬件服务化清理 ------------------ */
void GyroHS_cleanup(void) {
cout << "[INFO] GyroHS cleaning up..." << endl;
// 清理FastDDS组件
if (GyroHS_part != nullptr) {
delete GyroHS_part;
GyroHS_part = nullptr;
}
// 关闭串口
if (gyro_device.fd > 0) {
close(gyro_device.fd);
gyro_device.fd = -1;
}
// 销毁互斥锁
pthread_mutex_destroy(&cache_mutex);
}