[MCU] 基于瑞萨CPKCOR-RA8D1的RTK系统设计

[复制链接]
731|0
abner_ma 发表于 2025-11-9 20:37 | 显示全部楼层 |阅读模式
   GNSS RTK(Global Navigation Satellite System Real-Time Kinematic,全球导航卫星系统实时动态差分)是一种高精度定位技术,通过基站与流动站的协同工作,可实现厘米级甚至毫米级的实时定位精度,广泛应用于测绘、精准农业、自动驾驶、工程施工等领域 。 基于瑞萨RA8D1微控制器设计GNSS RTK接收机,依靠瑞萨RA8D1单片机的高性能处理能力、丰富外设接口及低功耗特性,搭配GNSS模组(如UM982)实现实时动态差分定位。
   

一、系统设计目标
    支持RTK差分定位(固定解精度达厘米级)。实现基站与流动站数据交互(如RTCM数据传输)。支持RS232,RS485,CAN,RJ45多种输出,支持ROS系统。具备高效数据处理、存储及外设扩展能力。满足低功耗、小型化及工业级可靠性要求。
二、硬件架构设计
      设计框图:


  1. 核心控制器:基于瑞萨CPKCOR-RA8D1开发板,搭载瑞萨RA8D1高性能单片机,基于ARM CortexM85内核(最高240MHz主频),支持单精度浮点运算(FPU),适合RTK解算辅助处理;内置丰富外设(UART、SPI、Ethernet、CAN、ADC等),满足多模组互联需求;支持安全加密(TrustZoneM),适合户外设备安全防护。支持单 / 双精度 FPU 和 DSP 指令,可辅助 RTK 解算中的浮点运算(如载波相位差分、基线解算),可以快速解析复杂的 RTCM3.x 帧结构。RA 系列内置多达 8 个 UART 接口,支持硬件流控(RTS/CTS)和 IrDA 模式,可直接通过外部电平转换芯片(如 MAX232/MAX485)实现 RS232/RS485 通信。UART 波特率最高可达 3Mbps,满足 RTK 差分数据(如 RTCM3.2)的高速传输需求;支持中断 / DMA 接收,避免数据丢包(关键于 RTK 固定解稳定性)。内置 2-6 个 CAN FD 控制器(兼容传统 CAN 2.0),支持最高 8Mbps 速率,具备错误检测、自动重传功能,适合工业环境下的多节点通信(如车载 RTK 与自动驾驶系统互联)。内置 10/100Mbps 以太网 MAC+PHY,支持 IEEE 1588 PTP 精确时间同步,可通过 TCP/UDP 协议传输海量差分数据(如基站向多个流动站广播 RTCM)。
   2. GNSS模组接口(UM982)
   通信接口:主UART(如UART0):连接UM982的TX/RX,传输原始观测数据(如UBX格式)和配置指令,波特率设为115200bps。  PPS同步:UM982的PPS(秒脉冲)输出连接RA8D1的GPIO(如P100),用于时间同步,确保基站与流动站时钟对齐 (  RTK解算关键)。  
  天线接口:UM982外接高增益GNSS天线(支持多星座:GPS、北斗、GLONASS、Galileo),通过SMA接口连接,需匹配低噪声放大器(LNA)减少信号损耗。
  3. 差分数据传输模块
   基站→流动站数据链路:  
   无线传输:若为移动场景,通过RA8D1的UART1连接4G/5G模组(如移远EC20)或LoRa模组,传输RTCM3.2差分数据(波特率9600115200bps)。  
   有线传输:固定场景可通过RA8D1的Ethernet接口(内置MAC+PHY)连接局域网,基于TCP/UDP协议传输差分数据。  
接口保护:在UART/Ethernet接口处添加TVS管(如SMBJ6.5A)和ESD保护电路,增强户外抗干扰能力。

4. 存储模块
  数据记录:通过SPI连接NOR Flash(W25Q128)存储配置参数、日志及历史定位数据;或通过SDIO接口连接SD卡,存储大容量原始观测数据(供后处理分析)。  
  实时时钟(RTC):外接低功耗RTC芯片,在GNSS信号丢失时提供时间基准,通过I2C接口与RA8D1通信。
5. 电源与外围电路
宽压输入:支持9-60V直流输入(适应车载/工业电源),通过DC-DC转换器(如LM2596)转换为5V,再经LDO输出3.3V给RA8D1、GNSS模组等。  
指示灯:通过RA8D1的GPIO控制LED,指示系统供电、GNSS信号强度、RTK固定解状态(如固定解时绿灯常亮,浮点解时闪烁)。  


三、软件系统设计
1. 开发环境与底层驱动
开发工具:使用瑞萨e² studio IDE,基于FreeRTOS实时操作系统(RA8D1官方支持),实现多任务调度。  
外设驱动:  
   配置UART中断接收GNSS数据(UM982的UBX/RTCM帧),通过DMA减少CPU占用。  
   实现SPI/I2C驱动,控制Flash、RTC等外设。  
   开发网络驱动(Ethernet/LoRa/4G),封装TCP/UDP协议栈(如lwIP)用于差分数据传输。

2. GNSS数据处理流程
数据解析:在FreeRTOS任务中解析UM982输出的UBX格式数据(如导航电文、原始伪距、载波相位),提取卫星信息、时间戳、位置初值。  
RTK解算辅助:  
   若作为基站:RA8D1接收UM982的原始数据,结合已知基站坐标生成RTCM3.2差分电文(如1005、1077帧),通过传输模块发送给流动站。  
   若作为流动站:接收基站RTCM数据,与本地UM982的观测数据融合,通过RA8D1的FPU加速差分算法(或调用UM982内置RTK解算功能,直接获取固定解结果)。  
解状态判断:解析UM982的RTK状态帧(如UBXNAVRTK),获取解类型(固定解/浮点解/单点解),通过LED或串口上报。
  1. #include "hal_data.h"
  2. #include "FreeRTOS.h"
  3. #include "task.h"
  4. #include "queue.h"
  5. #include <string.h>
  6. #include <stdio.h>

  7. // 宏定义
  8. #define UART_GNSS_BAUDRATE     115200    // UM982通信波特率
  9. #define UART_DIFF_BAUDRATE     115200    // 差分数据传输波特率
  10. #define MAX_GNSS_BUF_LEN       512       // GNSS数据缓冲区大小
  11. #define RTK_FIXED_STATE        3         // 固定解状态码(参考UM982手册)
  12. #define PPS_GPIO_PORT          BSP_IO_PORT_01    // PPS信号引脚(示例)

  13. // UM982 UBX帧结构(简化)
  14. typedef struct {
  15.     uint8_t class;       // 消息类(如0x01=NAV)
  16.     uint8_t id;          // 消息ID(如0x02=POSLLH)
  17.     uint16_t len;        //  payload长度
  18.     uint8_t payload[256];// 数据载荷
  19.     uint16_t checksum;   // 校验和
  20. } ubx_frame_t;

  21. // RTK状态信息
  22. typedef struct {
  23.     uint8_t rtk_stat;    // 0=单点解, 1=浮点解, 3=固定解
  24.     double lat;          // 纬度(度)
  25.     double lon;          // 经度(度)
  26.     double alt;          // 高程(米)
  27. } rtk_info_t;

  28. // 全局变量
  29. QueueHandle_t g_gnss_queue;       // GNSS数据队列
  30. rtk_info_t g_rtk_info = {0};      // RTK状态全局变量
  1. void hardware_init(void) {
  2.     // 初始化GPIO(PPS信号输入)
  3.     R_IOPORT_Open(&g_ioport_ctrl, g_ioport.p_cfg);
  4.     R_IOPORT_PinCfg(&g_ioport_ctrl, PPS_GPIO_PORT, IOPORT_CFG_PORT_DIRECTION_INPUT);

  5.     // 初始化GNSS UART(连接UM982)
  6.     g_uart0.p_api->open(g_uart0.p_ctrl, g_uart0.p_cfg);
  7.     g_uart0.p_api->baudSet(g_uart0.p_ctrl, UART_GNSS_BAUDRATE, NULL);

  8.     // 初始化差分数据UART(传输RTCM)
  9.     g_uart1.p_api->open(g_uart1.p_ctrl, g_uart1.p_cfg);
  10.     g_uart1.p_api->baudSet(g_uart1.p_ctrl, UART_DIFF_BAUDRATE, NULL);

  11.     // 创建FreeRTOS队列(用于传递GNSS数据)
  12.     g_gnss_queue = xQueueCreate(10, MAX_GNSS_BUF_LEN);
  13.     if (g_gnss_queue == NULL) {
  14.         // 队列创建失败处理
  15.         while(1);
  16.     }
  17. }
  1. // UART0中断回调(接收UM982输出的UBX/RTCM数据)
  2. void uart0_callback(uart_callback_args_t *p_args) {
  3.     static uint8_t gnss_buf[MAX_GNSS_BUF_LEN] = {0};
  4.     static uint16_t buf_idx = 0;

  5.     if (p_args->event == UART_EVENT_RX_CHAR) {
  6.         // 接收单字节数据
  7.         gnss_buf[buf_idx++] = (uint8_t)p_args->data;

  8.         // 缓冲区满或检测到UBX帧尾(0x1B)时,发送到队列
  9.         if (buf_idx >= MAX_GNSS_BUF_LEN || gnss_buf[buf_idx-1] == 0x1B) {
  10.             xQueueSendFromISR(g_gnss_queue, gnss_buf, NULL);
  11.             buf_idx = 0;
  12.             memset(gnss_buf, 0, MAX_GNSS_BUF_LEN);
  13.         }
  14.     }
  15. }
  1. // 校验UBX帧校验和
  2. static bool ubx_checksum_valid(ubx_frame_t *frame) {
  3.     uint8_t ck_a = 0, ck_b = 0;
  4.     // 计算校验和(覆盖class、id、len、payload)
  5.     ck_a += frame->class;
  6.     ck_b += ck_a;
  7.     ck_a += frame->id;
  8.     ck_b += ck_a;
  9.     ck_a += (frame->len >> 8) & 0xFF;
  10.     ck_b += ck_a;
  11.     ck_a += frame->len & 0xFF;
  12.     ck_b += ck_a;
  13.     for (int i=0; i<frame->len; i++) {
  14.         ck_a += frame->payload[i];
  15.         ck_b += ck_a;
  16.     }
  17.     // 对比帧中校验和
  18.     return (ck_a == (frame->checksum >> 8)) && (ck_b == (frame->checksum & 0xFF));
  19. }

  20. // 解析UBX-NAV-RTK帧(获取RTK状态)
  21. static void parse_ubx_nav_rtk(uint8_t *data, uint16_t len) {
  22.     if (len < 4) return; // 最小长度检查
  23.     // RTK状态码位于payload第3字节(参考UM982手册)
  24.     g_rtk_info.rtk_stat = data[3];
  25.     // 打印状态(调试用)
  26.     switch(g_rtk_info.rtk_stat) {
  27.         case 0: printf("RTK状态:单点解\n"); break;
  28.         case 1: printf("RTK状态:浮点解\n"); break;
  29.         case 3: printf("RTK状态:固定解\n"); break;
  30.         default: printf("RTK状态:未知\n");
  31.     }
  32. }

  33. // 解析UBX-NAV-POSLLH帧(获取经纬度)
  34. static void parse_ubx_nav_posllh(uint8_t *data, uint16_t len) {
  35.     if (len < 28) return; // 确保数据完整
  36.     // 纬度(1e-7度):payload[8-11]为int32_t
  37.     int32_t lat_raw = *(int32_t*)(data + 8);
  38.     g_rtk_info.lat = lat_raw / 1e7;
  39.     // 经度(1e-7度):payload[12-15]
  40.     int32_t lon_raw = *(int32_t*)(data + 12);
  41.     g_rtk_info.lon = lon_raw / 1e7;
  42.     // 高程(毫米):payload[20-23]
  43.     int32_t alt_raw = *(int32_t*)(data + 20);
  44.     g_rtk_info.alt = alt_raw / 1000.0;
  45.     printf("位置:%.8f, %.8f, %.2f米\n", g_rtk_info.lat, g_rtk_info.lon, g_rtk_info.alt);
  46. }

  47. // 主解析函数
  48. void parse_gnss_data(uint8_t *buf, uint16_t len) {
  49.     ubx_frame_t frame;
  50.     // 查找UBX帧头(0xB5, 0x62)
  51.     for (int i=0; i<len-2; i++) {
  52.         if (buf[i] == 0xB5 && buf[i+1] == 0x62) {
  53.             // 解析帧结构
  54.             frame.class = buf[i+2];
  55.             frame.id = buf[i+3];
  56.             frame.len = (buf[i+4] << 8) | buf[i+5];
  57.             memcpy(frame.payload, &buf[i+6], frame.len);
  58.             frame.checksum = (buf[i+6+frame.len] << 8) | buf[i+7+frame.len];
  59.             
  60.             // 校验并解析特定帧
  61.             if (ubx_checksum_valid(&frame)) {
  62.                 if (frame.class == 0x01 && frame.id == 0x39) { // NAV-RTK帧
  63.                     parse_ubx_nav_rtk(frame.payload, frame.len);
  64.                 } else if (frame.class == 0x01 && frame.id == 0x02) { // NAV-POSLLH帧
  65.                     parse_ubx_nav_posllh(frame.payload, frame.len);
  66.                 }
  67.             }
  68.             break;
  69.         }
  70.     }
  71. }
  1. // 任务1:接收GNSS数据并解析
  2. void gnss_parse_task(void *pvParameters) {
  3.     uint8_t rx_buf[MAX_GNSS_BUF_LEN];
  4.     while(1) {
  5.         // 从队列读取数据
  6.         if (xQueueReceive(g_gnss_queue, rx_buf, portMAX_DELAY) == pdPASS) {
  7.             parse_gnss_data(rx_buf, MAX_GNSS_BUF_LEN);
  8.             memset(rx_buf, 0, MAX_GNSS_BUF_LEN);
  9.         }
  10.     }
  11. }

  12. // 任务2:基站模式下发送RTCM差分数据
  13. void base_station_task(void *pvParameters) {
  14.     uint8_t rtcm_buf[MAX_GNSS_BUF_LEN];
  15.     while(1) {
  16.         // 若为基站,将UM982生成的RTCM数据转发给流动站
  17.         // (实际应用中需过滤RTCM帧,此处简化为直接转发)
  18.         if (xQueueReceive(g_gnss_queue, rtcm_buf, portMAX_DELAY) == pdPASS) {
  19.             // 检查是否为RTCM帧(帧头0xD3)
  20.             if (rtcm_buf[0] == 0xD3) {
  21.                 g_uart1.p_api->write(g_uart1.p_ctrl, rtcm_buf, MAX_GNSS_BUF_LEN, NULL);
  22.             }
  23.             memset(rtcm_buf, 0, MAX_GNSS_BUF_LEN);
  24.         }
  25.         vTaskDelay(pdMS_TO_TICKS(10)); // 10ms间隔
  26.     }
  27. }

  28. // 任务3:LED状态指示(固定解亮绿灯,否则闪烁)
  29. void led_indicator_task(void *pvParameters) {
  30.     while(1) {
  31.         if (g_rtk_info.rtk_stat == RTK_FIXED_STATE) {
  32.             // 固定解:绿灯常亮
  33.             R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02, BSP_IO_LEVEL_HIGH);
  34.             vTaskDelay(pdMS_TO_TICKS(500));
  35.         } else {
  36.             // 非固定解:绿灯闪烁
  37.             R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02, BSP_IO_LEVEL_HIGH);
  38.             vTaskDelay(pdMS_TO_TICKS(200));
  39.             R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02, BSP_IO_LEVEL_LOW);
  40.             vTaskDelay(pdMS_TO_TICKS(200));
  41.         }
  42.     }
  43. }


3. 系统功能模块
配置管理:通过串口指令或Web服务器(基于RA8D1的Ethernet)配置GNSS参数(如星座选择、更新率)、差分数据传输协议(TCP/UDP端口)。  
日志记录:将定位结果(时间、经纬度、高程、解状态)按格式写入Flash/SD卡,支持后期数据导出分析。  
异常处理:检测GNSS信号丢失、差分链路中断等故障,触发重试机制或报警(如蜂鸣器)。

成果展示:



  GPS Count 当前接收到有效信号的 GPS 卫星数量充足,GPS Lock3D RTK 固定解、HDOP/VDOP 数值小,说明当前定位精度高、可靠性强;Course Over Ground 则用于指示移动方向,适合导航或轨迹记录场景。

四、创新点
1. 时间同步:利用UM982的PPS信号与RA8D1的定时器同步,确保基站与流动站观测数据的时间戳误差小于1ms(RTK解算精度关键)。  
2. 差分数据完整性:在无线传输中加入校验(如CRC),避免数据丢包导致解算失败;实现数据缓存机制,应对短时间链路中断。  
3. 低功耗优化:通过RA8D1的睡眠模式(如STOP模式),在GNSS信号稳定时降低CPU主频,关闭闲置外设(如Ethernet),延长户外设备续航。  
4. 抗干扰设计:硬件上增加电源滤波电容、信号屏蔽层;软件上采用数据平滑算法(如卡尔曼滤波),减少多路径效应影响。
5.多通信接口输出,依靠瑞萨RA1丰富的通信接口,输出RS232.485,CANFD协议,RJ45,
五、应用场景
精准农业:流动站安装在农机上,通过RTK定位实现厘米级作业路径控制。  
工程测量:基站固定于已知点,流动站手持或车载,快速获取测点精确坐标。  
智能驾驶:通过RA8D1的CAN接口连接车载总线,或添加IMU(如BNO055)实现GNSS/IMU组合导航,提升遮挡场景下的定位连续性。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:项目经理
简介:资深嵌入式开发工程师

113

主题

201

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部