ubuntu 通过ros-noetic获取RTK模块的nmea格式数据

0、安装

复制代码
sudo apt-get install ros-noetic-nmea-msgs ros-noetic-serial

cd ~/catkin_ws/src
git clone https://github.com/ros-drivers/nmea_navsat_driver
cd ~/catkin_ws
catkin_make -DCATKIN_WHITELIST_PACKAGES='nmea_navsat_driver'

编译如果报错,AI解决一下,我是少安装了包ros-noetic-nmea-navsat-driver

复制代码
sudo apt-get install ros-noetic-nmea-navsat-driver
  1. roscore

2、第二个终端(开启rtk模块)

复制代码
rosrun nmea_navsat_driver nmea_serial_driver     _port:=/dev/ttyACM0     _baud:=115200     _frame_id:=gps     _useGGA:=true     _useRMC:=true     _useGSA:=true     _useGSV:=false

3、第三个终端

rostopic echo /fix

复制代码
---
header: 
  seq: 178
  stamp: 
    secs: 1769427995
    nsecs: 840435028
  frame_id: "gps"
status: 
  status: 0  //大于1才可能是开启RTK
  service: 1
latitude: 30.323176666666665
longitude: 120.360728
altitude: nan
position_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
position_covariance_type: 0

status.status = -1 表示 "无可用数据""服务不可用" 。在 sensor_msgs/NavSatFix 消息中,status.status 字段的值为:

  • -1: 无法定位(无可用数据)

  • 0: 未定位

  • 1: GPS 定位(单点定位)

  • 2: DGPS 定位(差分 GPS)

  • 4: RTK 固定解(厘米级精度)

  • 5: RTK 浮点解(亚米级精度)

cd /home/zeh/catkin_ws/script

./rtk_diagnostic.sh

诊断rtk状态

复制代码
#!/bin/bash

PORT="/dev/ttyACM0"
BAUD="115200"
LOG_FILE="rtk_diagnostic_$(date +%Y%m%d_%H%M%S).log"

echo "=== RTK 模块详细诊断 ===" | tee -a "$LOG_FILE"
echo "端口: $PORT" | tee -a "$LOG_FILE"
echo "波特率: $BAUD" | tee -a "$LOG_FILE"
echo "日志文件: $LOG_FILE" | tee -a "$LOG_FILE"
echo "时间: $(date)" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

# 1. 检查设备连接
echo "1. 检查设备连接..." | tee -a "$LOG_FILE"
if [ -c "$PORT" ]; then
    echo "   ✓ 设备 $PORT 存在" | tee -a "$LOG_FILE"
    echo "   设备信息:" | tee -a "$LOG_FILE"
    ls -l $PORT | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
else
    echo "   ✗ 设备 $PORT 不存在!" | tee -a "$LOG_FILE"
    echo "   请检查:" | tee -a "$LOG_FILE"
    echo "   1. USB 连接是否牢固" | tee -a "$LOG_FILE"
    echo "   2. 设备是否供电" | tee -a "$LOG_FILE"
    echo "   3. 使用 dmesg | grep tty 查看设备识别" | tee -a "$LOG_FILE"
    exit 1
fi

# 2. 设置串口参数
echo "2. 设置串口参数..." | tee -a "$LOG_FILE"
# 尝试设置串口参数,忽略错误(可能已经由其他程序设置)
stty -F $PORT raw 2>/dev/null
stty -F $PORT -echo -echoe -echok 2>/dev/null

# 3. 测试多个波特率
echo "3. 测试多个波特率..." | tee -a "$LOG_FILE"
echo "   每个波特率测试10秒..." | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

BAUD_RATES=(9600 19200 38400 57600 115200 230400 460800)
FOUND_DATA=0
BEST_BAUD=""

for baud in "${BAUD_RATES[@]}"; do
    echo "   测试波特率: $baud ..." | tee -a "$LOG_FILE"
    
    # 设置波特率
    stty -F $PORT $baud 2>/dev/null
    
    # 清空缓冲区
    timeout 0.1 cat $PORT > /dev/null 2>&1
    
    # 收集数据(10秒)
    echo "   正在接收数据 (10秒)..." | tee -a "$LOG_FILE"
    DATA=$(timeout 10 cat $PORT 2>&1 | tr -d '\000')
    
    if [ -n "$DATA" ]; then
        # 统计行数
        LINE_COUNT=$(echo "$DATA" | wc -l)
        
        # 检查是否有有效的NMEA语句
        NMEA_COUNT=$(echo "$DATA" | grep -c '^\$')
        
        echo "   ✓ 接收到 $LINE_COUNT 行数据,其中 $NMEA_COUNT 行是NMEA语句" | tee -a "$LOG_FILE"
        
        if [ $NMEA_COUNT -gt 0 ]; then
            FOUND_DATA=1
            BEST_BAUD=$baud
            echo "   ⭐ 找到有效数据!波特率可能为: $baud" | tee -a "$LOG_FILE"
            
            # 显示前几条NMEA语句
            echo "   示例数据:" | tee -a "$LOG_FILE"
            echo "$DATA" | grep '^\$' | head -5 | while read line; do
                echo "     $line" | tee -a "$LOG_FILE"
            done
            
            # 保存这个波特率的数据用于后续分析
            echo "$DATA" > "rtk_data_${baud}.txt"
            break
        else
            echo "   ⚠ 有数据但不是NMEA格式" | tee -a "$LOG_FILE"
            echo "   前100个字符: $(echo "$DATA" | head -c 100)" | tee -a "$LOG_FILE"
        fi
    else
        echo "   ✗ 没有数据" | tee -a "$LOG_FILE"
    fi
    
    echo "" | tee -a "$LOG_FILE"
done

echo "" | tee -a "$LOG_FILE"

if [ $FOUND_DATA -eq 0 ]; then
    echo "4. 诊断结果: 未找到有效NMEA数据" | tee -a "$LOG_FILE"
    echo "   可能原因:" | tee -a "$LOG_FILE"
    echo "   1. 波特率不匹配(尝试了所有常见波特率)" | tee -a "$LOG_FILE"
    echo "   2. 模块没有输出NMEA数据" | tee -a "$LOG_FILE"
    echo "   3. 模块需要配置才能输出NMEA" | tee -a "$LOG_FILE"
    echo "   4. 模块故障" | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
    
    echo "5. 建议操作:" | tee -a "$LOG_FILE"
    echo "   a) 使用Python脚本测试:" | tee -a "$LOG_FILE"
    cat > test_serial.py << 'EOF'
#!/usr/bin/env python3
import serial
import time

port = '/dev/ttyACM0'
baud_rates = [9600, 19200, 38400, 57600, 115200, 230400, 460800]

for baud in baud_rates:
    print(f"\n尝试波特率: {baud}")
    try:
        ser = serial.Serial(port, baud, timeout=2)
        print("连接成功,等待数据...")
        
        # 尝试读取20秒
        start_time = time.time()
        data_received = False
        
        while time.time() - start_time < 20:
            if ser.in_waiting > 0:
                try:
                    line = ser.readline().decode('ascii', errors='ignore').strip()
                    if line:
                        print(f"收到: {line[:80]}")
                        data_received = True
                        break
                except:
                    pass
            time.sleep(0.1)
        
        if not data_received:
            print("20秒内没有收到数据")
        
        ser.close()
        
    except Exception as e:
        print(f"连接失败: {e}")
EOF
    echo "   python3 test_serial.py" | tee -a "$LOG_FILE"
    
    echo "" | tee -a "$LOG_FILE"
    echo "   b) 检查设备是否被其他程序占用:" | tee -a "$LOG_FILE"
    echo "      sudo lsof $PORT" | tee -a "$LOG_FILE"
    echo "" | tee -a "$LOG_FILE"
    
    echo "   c) 检查设备原始数据(二进制):" | tee -a "$LOG_FILE"
    echo "      sudo od -x $PORT | head -20" | tee -a "$LOG_FILE"
    
    exit 1
fi

# 4. 分析NMEA数据
echo "4. 分析NMEA数据 (波特率: $BEST_BAUD)..." | tee -a "$LOG_FILE"
DATA_FILE="rtk_data_${BEST_BAUD}.txt"

if [ -f "$DATA_FILE" ]; then
    # 统计各种NMEA语句
    echo "   NMEA语句统计:" | tee -a "$LOG_FILE"
    for msg_type in GGA RMC GSV GSA GST GLL; do
        COUNT=$(grep -c "$msg_type" "$DATA_FILE" 2>/dev/null || echo 0)
        echo "     $msg_type: $COUNT" | tee -a "$LOG_FILE"
    done
    
    echo "" | tee -a "$LOG_FILE"
    
    # 分析最新的GGA语句
    LATEST_GGA=$(grep "GGA" "$DATA_FILE" | tail -1)
    if [ -n "$LATEST_GGA" ]; then
        echo "   最新GGA语句:" | tee -a "$LOG_FILE"
        echo "     $LATEST_GGA" | tee -a "$LOG_FILE"
        echo "" | tee -a "$LOG_FILE"
        
        # 解析GGA
        IFS=',' read -ra PARTS <<< "$LATEST_GGA"
        if [ ${#PARTS[@]} -gt 10 ]; then
            TIME="${PARTS[1]:-N/A}"
            LAT="${PARTS[2]:-N/A}${PARTS[3]:-}"
            LON="${PARTS[4]:-N/A}${PARTS[5]:-}"
            FIX_QUALITY="${PARTS[6]:-N/A}"
            SAT_COUNT="${PARTS[7]:-N/A}"
            HDOP="${PARTS[8]:-N/A}"
            ALT="${PARTS[9]:-N/A}${PARTS[10]:-}"
            
            echo "   解析结果:" | tee -a "$LOG_FILE"
            echo "     时间(UTC): $TIME" | tee -a "$LOG_FILE"
            echo "     纬度: $LAT" | tee -a "$LOG_FILE"
            echo "     经度: $LON" | tee -a "$LOG_FILE"
            echo "     定位质量: $FIX_QUALITY" | tee -a "$LOG_FILE"
            echo "     使用卫星数: $SAT_COUNT" | tee -a "$LOG_FILE"
            echo "     HDOP: $HDOP" | tee -a "$LOG_FILE"
            echo "     海拔: $ALT" | tee -a "$LOG_FILE"
            
            # 定位质量说明
            case $FIX_QUALITY in
                "0") echo "     状态: 无效定位" | tee -a "$LOG_FILE" ;;
                "1") echo "     状态: GPS单点定位" | tee -a "$LOG_FILE" ;;
                "2") echo "     状态: 差分GPS" | tee -a "$LOG_FILE" ;;
                "4") echo "     ✅ 状态: RTK固定解 (厘米级精度)" | tee -a "$LOG_FILE" ;;
                "5") echo "     ⚠ 状态: RTK浮点解 (亚米级精度)" | tee -a "$LOG_FILE" ;;
                "6") echo "     状态: 估算DR模式" | tee -a "$LOG_FILE" ;;
                *) echo "     状态: 未知 ($FIX_QUALITY)" | tee -a "$LOG_FILE" ;;
            esac
        fi
    else
        echo "   ⚠ 没有找到GGA语句" | tee -a "$LOG_FILE"
    fi
    
    echo "" | tee -a "$LOG_FILE"
    
    # 分析卫星信息
    LATEST_GSV=$(grep "GSV" "$DATA_FILE" | tail -4 | head -1)
    if [ -n "$LATEST_GSV" ]; then
        IFS=',' read -ra GSV_PARTS <<< "$LATEST_GSV"
        TOTAL_SATS="${GSV_PARTS[3]:-0}"
        echo "   卫星信息:" | tee -a "$LOG_FILE"
        echo "     可见卫星总数: $TOTAL_SATS" | tee -a "$LOG_FILE"
        
        if [ "$TOTAL_SATS" -lt 4 ]; then
            echo "     ⚠ 警告: 卫星少于4颗,无法定位" | tee -a "$LOG_FILE"
        elif [ "$TOTAL_SATS" -lt 6 ]; then
            echo "     ⚠ 注意: 卫星数较少,定位精度可能受影响" | tee -a "$LOG_FILE"
        else
            echo "     ✓ 卫星数量足够" | tee -a "$LOG_FILE"
        fi
    fi
    
    echo "" | tee -a "$LOG_FILE"
    
    # 检查是否有RTCM数据(RTK差分信号)
    RTCM_COUNT=$(grep -c "RTCM" "$DATA_FILE" 2>/dev/null || echo 0)
    if [ $RTCM_COUNT -gt 0 ]; then
        echo "   📡 检测到RTCM差分数据 ($RTCM_COUNT 条)" | tee -a "$LOG_FILE"
    else
        echo "   ⚠ 未检测到RTCM差分数据" | tee -a "$LOG_FILE"
        echo "     如果你使用网络RTK或基站RTK,请检查差分源" | tee -a "$LOG_FILE"
    fi
    
else
    echo "   ✗ 数据文件不存在" | tee -a "$LOG_FILE"
fi

echo "" | tee -a "$LOG_FILE"

# 5. 实时监控建议
echo "5. 实时监控 (运行以下命令):" | tee -a "$LOG_FILE"
echo "   # 查看原始NMEA数据:" | tee -a "$LOG_FILE"
echo "   stty -F $PORT $BEST_BAUD && cat $PORT" | tee -a "$LOG_FILE"
echo "" | tee -a "$LOG_FILE"

echo "   # 使用Python实时监控:" | tee -a "$LOG_FILE"
cat > realtime_monitor.py << 'EOF'
#!/usr/bin/env python3
import serial
import time
from datetime import datetime

port = '/dev/ttyACM0'
baud = 115200  # 根据上面检测到的波特率修改

try:
    ser = serial.Serial(port, baud, timeout=1)
    print(f"连接到 {port} ({baud} baud)")
    print("按 Ctrl+C 停止")
    print("-" * 80)
    
    while True:
        try:
            line = ser.readline().decode('ascii', errors='ignore').strip()
            if line:
                timestamp = datetime.now().strftime("%H:%M:%S")
                
                if line.startswith('$GNGGA') or line.startswith('$GPGGA'):
                    parts = line.split(',')
                    if len(parts) > 7:
                        fix_quality = parts[6]
                        sats = parts[7]
                        fix_desc = {
                            '0': '无效', '1': 'GPS', '2': '差分',
                            '4': 'RTK固定', '5': 'RTK浮点'
                        }.get(fix_quality, fix_quality)
                        
                        print(f"[{timestamp}] GGA: {fix_desc}解, {sats}颗卫星")
                
                elif line.startswith('$GPGSV'):
                    parts = line.split(',')
                    if len(parts) > 3:
                        total_sats = parts[3]
                        print(f"[{timestamp}] GSV: 总共{total_sats}颗可见卫星")
                
                elif line.startswith('$GPRMC'):
                    parts = line.split(',')
                    if len(parts) > 7:
                        speed_knots = float(parts[7]) if parts[7] else 0
                        speed_kmh = speed_knots * 1.852
                        print(f"[{timestamp}] RMC: 速度 {speed_kmh:.1f} km/h")
                
                else:
                    # 显示其他语句类型
                    msg_type = line[3:6] if len(line) > 6 else "???"
                    print(f"[{timestamp}] {msg_type}: {line[:60]}...")
                        
        except UnicodeDecodeError:
            continue
        except KeyboardInterrupt:
            print("\n停止监控")
            break
            
except Exception as e:
    print(f"错误: {e}")
EOF

echo "   python3 realtime_monitor.py" | tee -a "$LOG_FILE"

echo "" | tee -a "$LOG_FILE"
echo "=== 诊断完成 ===" | tee -a "$LOG_FILE"
echo "详细日志已保存到: $LOG_FILE" | tee -a "$LOG_FILE"
相关推荐
雨季6662 小时前
构建 OpenHarmony 简易密码强度指示器:用字符串长度实现直观反馈
android·开发语言·javascript
橘橙黄又青2 小时前
List和Map篇
java·开发语言·面试
曹牧2 小时前
Java:包含空字符字段的对象序列化为JSON字符串
java·开发语言
黎雁·泠崖2 小时前
Java方法重写Override:规则+底层本质+与重载区别
java·开发语言
猿小羽2 小时前
Spring AI + MCP 实战:构建标准化 AI 智能代理与上下文集成
java·spring boot·llm·ai agent·spring ai·anthropic·mcp
&活在当下&2 小时前
uniapp 选择城市区号索引列表实现
前端·uni-app
高山上有一只小老虎2 小时前
mybatisplus分页查询版本 3.5.8 以下和版本 3.5.9及以上的区别
java·spring boot·mybatis
哪里不会点哪里.2 小时前
Spring Boot 项目搭建过程
java·spring boot·后端
李少兄2 小时前
FHIR 资源查询实战指南:从 HTTP 接口到 Java 客户端的完整实现
java·网络协议·http