Skip to content

航位推算

功能介绍

航位推算(Dead Reckoning) 是车载多源融合定位 SDK,在 GNSS、IMU、车身信号与地图匹配反馈基础上输出连续、稳定的车辆位姿。

能力 说明
多源融合 GNSS、陀螺仪、加速度计、车速/档位等
位置输出 经纬高、航向、速度、姿态、精度、解算状态
地图匹配闭环 接收地图匹配反馈,提升隧道与复杂路网定位连续性,见地图匹配
日志回放 路测日志录制与离线回放验证

时序图

航位推算时序图


核心接口

对外唯一入口类com.telenav.auto.dr.DrEngineManager(单例)。初始化、获取数据通道、注册输出监听均通过该类完成;涉及的数据类型在对应方法下展开说明。

1
2
3
4
5
6
7
8
9
DrEngineManager.getInstance()
    ├── init(DrEngineConfig)          → DrEngineConfig / DrEngineInitStatus / CustomParam
    ├── getGnssDataSender()           → GnssDataSender → GnssFixBean
    ├── getSensorDataSender()         → SensorDataSender
    ├── getVehicleDataSender()        → VehicleDataSender → VehicleDataBean
    ├── getMapMatchingFeedbackSender()→ MapMatchingFeedbackSender → MapMatchingFeedbackPositionBean
    ├── addDrOutListener()            → DrOutListener → VehiclePositionBean
    ├── addDrReplayStatusListener()   → DrReplayStatusListener
    └── destroy()

DrEngineManager

项目 说明
类型 public class,单例
职责 引擎生命周期、分发 *Sender、注册 *Listener

getInstance()

1
public static DrEngineManager getInstance()

获取全局唯一实例,后续所有操作均通过该对象进行。


init(DrEngineConfig drEngineConfig)

1
public DrEngineInitStatus init(@NonNull DrEngineConfig drEngineConfig)
项目 说明
调用时机 应用或定位 Service 启动时,同步调用
返回值 DrEngineInitStatus,仅 Success 后可获取 Sender
重复调用 已成功初始化后直接返回 Success,不重新加载配置;需重启请先 destroy()

关联类:DrEngineConfig

通过 DrEngineConfig.newBuilder(context).build() 构建,传给 init()

Builder 方法 类型 默认值 说明
setMode DrEngineMode GNSS_3GYRO_3ACC_ODM_MODE 传感器组合,须与实车一致
setConfigName ConfigName Default 车型预置配置,见下文 ConfigName
setConfigFilePath String {externalFilesDir}/drEngine 配置根目录;build() 自动追加 /config
setLogPath String .../logs/drEngine 日志目录
setDiagnosticPath String .../diagnosticPath 诊断数据目录
setTrigger Trigger Period Period 周期输出 / Event 事件输出
setPeriod int 100 周期 ms,建议 ≥ 50
setReplay boolean false 回放模式
setReplayDataPath String 同 logPath replay=true 时必填
setDrEngineLogEnabled boolean false 日志总开关
setLogicLogLevel LogicLogLevel Disable DisableDebug
setCustomParam CustomParam null 见下文

DrEngineModesetMode 使用)

常量 传感器组合
ONLY_GNSS_MODE 仅 GNSS
GNSS_3GYRO_3ACC_ODM_MODE GNSS + 三轴陀螺 + 三轴加速度 + 里程(默认
GNSS_GYRO_2ACC_ODM_MODE GNSS + 单轴陀螺 + 双轴加速度 + 里程
GNSS_GYRO_1ACC_ODM_MODE GNSS + 单轴陀螺 + 单轴加速度 + 里程
GNSS_GYRO_ODM_MODE GNSS + 单轴陀螺 + 里程
GNSS_4W1S_MODE GNSS + 四轮速 + 方向盘转角
GNSS_2RW_MODE GNSS + 后轮双轮速

ConfigNamesetConfigName 使用)

ConfigName 为顶层枚举(com.telenav.auto.dr.ConfigName),通过 setConfigName 指定 SDK 内置的车型预置配置:

枚举值 说明
Default 默认车型配置
1
2
3
4
5
import com.telenav.auto.dr.ConfigName;

DrEngineConfig.newBuilder(context)
        .setConfigName(ConfigName.Default)
        .build();

build() 会将 SDK 内对应配置拷贝到 setConfigFilePath 指定目录;本地已存在且版本未变则跳过拷贝。

关联类:CustomParam(可选,经 setCustomParam 传入)

子类型 说明
MountingAngles IMU 相对车体安装角 pitch / roll / yaw(°),三者须齐全
LeverArm gnssCoordinates GNSS 天线在 IMU 系下 x/y/z(m)
LeverArm vrpCoordinates 车辆参考点(后轴中心)在 IMU 系下 x/y/z(m)

返回值:DrEngineInitStatus

枚举值 含义 处理建议
Success 成功 注册 Listener、获取 Sender
ConfigNotFound 配置缺失 检查 ConfigName、存储权限
LogPathNotSet 未设日志路径 开日志时调用 setLogPath
ReplayDataPathNotSet / ReplayDataNotFound 回放路径/数据异常 检查 setReplayDataPath
ConfigNotSet / TriggerNotSet / PeriodNotSet 配置项缺失 补全 Builder
NoDrProxy / UnknownInitError 其它错误 查日志

init(Context context)

1
public void init(@NonNull Context context)

使用 SDK 内置默认 DrEngineConfig 初始化,等价于 init(DrEngineConfig.newBuilder(context).build())。快速验证可用,量产建议使用带车型配置的 init(DrEngineConfig)


destroy()

1
public void destroy()

关闭引擎并释放资源;应用或定位 Service 退出时必须调用。销毁后 getXxxDataSender() 返回 null,需重新 init()


getGnssDataSender()

1
2
@Nullable
public GnssDataSender getGnssDataSender()
项目 说明
前置条件 init() 返回 Success
返回值 GnssDataSender 实例;未初始化时为 null
用途 将 GNSS 定位结果送入 DR

关联接口:GnssDataSender

1
void onLocationChanged(@NonNull GnssFixBean location);

关联类:GnssFixBeancom.telenav.auto.dr.bean

使用 GnssFixBean.newBuilder()...build() 构建。

Builder / 字段 说明
setTimestamp(long) 必填SystemClock.elapsedRealtime()
setUtcTimestamp(long) UTC 毫秒
setLatitude / setLongitude / setAltitude 位置
setSpeed(float) m/s,调用后标记速度有效
setHeading(float) °,北 0、顺时针 0–359
setAccuracy(h, v) 水平/垂直精度 m
setSatelliteInUse / setSatelliteInView 不可用填 -1

getSensorDataSender()

1
2
@Nullable
public SensorDataSender getSensorDataSender()

关联接口:SensorDataSender

方法 参数说明
onGyroscopeDataReceived(gx, gy, gz, timestamp) 角速度 rad/stimestamp = elapsedRealtime
onAccelerometerDataReceived(ax, ay, az, timestamp) 加速度 m/s²
onPressureDataReceived(pressure, timestamp) 气压 hPa(可选)

getVehicleDataSender()

1
2
@Nullable
public VehicleDataSender getVehicleDataSender()

关联接口:VehicleDataSender

1
void onVehicleDataReceived(@NonNull VehicleDataBean vehicleDataBean);

关联类:VehicleDataBean

Builder 方法 说明
setTimestamp(long) elapsedRealtime
setSpeed(float) 车速 m/s
setGearStatus(GearStatus) GEAR_PARK / NEUTRAL / REVERSE / DRIVE
setWheelSpeed(fl, fr, rl, rr) 四轮速 m/s(GNSS_4W1S_MODE 等)
setSteeringAngle(float) 方向盘转角 °
setAngularRate(float) 垂向陀螺 Z,rad/s
setHorizontalAcceleration(ax, ay) 水平加速度 m/s²

getMapMatchingFeedbackSender()

1
2
@Nullable
public MapMatchingFeedbackSender getMapMatchingFeedbackSender()

可选能力,接入地图匹配闭环时使用。

关联接口:MapMatchingFeedbackSender

1
void onMapMatchingFeedback(@NonNull MapMatchingFeedbackPositionBean bean);

关联类:MapMatchingFeedbackPositionBean

Builder 方法 说明
setTimestamp(long) elapsedRealtime
setDrTimestamp(long) 与最近一次 VehiclePositionBean.drTimestamp 一致
setRawLat/Lon/Heading/... DR 原始位姿
setMmLat/Lon/Heading/Speed 匹配后位姿
setMmConfidence(int) 0–6
setMmProbability(int) 0–30
setOffRoad / setInTunnel 离路 / 隧道
setRoadCandidates(int) 0 表示离路

addDrOutListener / removeDrOutListener

1
2
public void addDrOutListener(@NonNull DrOutListener drOutListener)
public void removeDrOutListener(@NonNull DrOutListener drOutListener)
项目 说明
调用时机 init 成功前后均可注册;建议 init 后立即 add
线程 回调可能在非主线程,更新 UI 需切换主线程
多监听 支持注册多个 DrOutListener

关联接口:DrOutListener

1
void onVehiclePositionReceived(@NonNull VehiclePositionBean vehiclePositionBean);

关联类:VehiclePositionBean(输出)

字段 类型 说明
timestamp long UTC ms
drTimestamp long 与 MM 同步用,回灌时原样传入
latitude / longitude / altitude 位置
speed float m/s
heading float 航向 °,与档位对齐
yaw float 偏航 °,与档位无关
horizontalPrecision float 水平精度 m
drStatus DrStatus DR_STATUS_GPS / DR_STATUS_DR / DR_STATUS_DR_GPS / DR_STATUS_DR_MMF
synchronousCount int 0–255,与 MM 同步
satelliteNum int 0 表示 GNSS 无效

addDrReplayStatusListener / removeDrReplayStatusListener

1
2
public void addDrReplayStatusListener(@NonNull DrReplayStatusListener listener)
public void removeDrReplayStatusListener(@NonNull DrReplayStatusListener listener)

关联接口:DrReplayStatusListener

1
void onReplayLogFinished();

仅在 DrEngineConfig.setReplay(true) 时有效,表示离线日志回放结束。


resetForReplay(String replayDataPath)

1
public void resetForReplay(@NonNull String replayDataPath)
项目 说明
用途 运行中切换回放数据目录
前置条件 init() 已成功,否则抛 IllegalStateException
配置 须与 setReplay(true)setReplayDataPath 配合使用

示例代码

以下示例以 DrEngineManager 为入口,演示初始化、注册输出、通过各 *Sender 喂数及 MM 回灌。完整工程可参考 app 模块中的 com.telenav.dr.DrClient

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import android.content.Context;
import android.os.SystemClock;
import android.util.Log;

import androidx.annotation.NonNull;

import com.telenav.auto.dr.ConfigName;
import com.telenav.auto.dr.DrEngineConfig;
import com.telenav.auto.dr.DrEngineInitStatus;
import com.telenav.auto.dr.DrEngineManager;
import com.telenav.auto.dr.DrEngineMode;
import com.telenav.auto.dr.DrOutListener;
import com.telenav.auto.dr.GnssDataSender;
import com.telenav.auto.dr.MapMatchingFeedbackSender;
import com.telenav.auto.dr.SensorDataSender;
import com.telenav.auto.dr.VehicleDataSender;
import com.telenav.auto.dr.bean.GnssFixBean;
import com.telenav.auto.dr.bean.MapMatchingFeedbackPositionBean;
import com.telenav.auto.dr.bean.VehicleDataBean;
import com.telenav.auto.dr.bean.VehiclePositionBean;

/**
 * 航位推算 SDK 接入示例(Java)
 */
public class DrLocationHelper {

    private static final String TAG = "DrLocationHelper";

    private final Context context;
    private long lastDrTimestamp;

    private final DrOutListener drOutListener = new DrOutListener() {
        @Override
        public void onVehiclePositionReceived(@NonNull VehiclePositionBean position) {
            onDrPosition(position);
        }
    };

    public DrLocationHelper(@NonNull Context context) {
        this.context = context.getApplicationContext();
    }

    /** 启动 DR:init + 注册输出监听 */
    public void start() {
        DrEngineConfig config = DrEngineConfig.newBuilder(context)
                .setMode(DrEngineMode.GNSS_3GYRO_3ACC_ODM_MODE)
                .setConfigName(ConfigName.Default)
                .setTrigger(DrEngineConfig.Trigger.Period)
                .setPeriod(100)
                .setDrEngineLogEnabled(false)
                .build();

        DrEngineInitStatus status = DrEngineManager.getInstance().init(config);
        if (status == DrEngineInitStatus.Success) {
            DrEngineManager.getInstance().addDrOutListener(drOutListener);
            Log.i(TAG, "DR engine started");
        } else {
            Log.e(TAG, "DR init failed: " + status);
        }
    }

    /** 停止 DR */
    public void stop() {
        DrEngineManager.getInstance().removeDrOutListener(drOutListener);
        DrEngineManager.getInstance().destroy();
    }

    /** GNSS 定位回调中调用 */
    public void onGnssUpdate(double lat, double lon, double alt, float speedMps) {
        GnssDataSender sender = DrEngineManager.getInstance().getGnssDataSender();
        if (sender == null) {
            return;
        }
        long ts = SystemClock.elapsedRealtime();
        GnssFixBean.Builder builder = GnssFixBean.newBuilder()
                .setTimestamp(ts)
                .setUtcTimestamp(System.currentTimeMillis())
                .setLatitude(lat)
                .setLongitude(lon)
                .setAltitude(alt);
        if (speedMps >= 0f) {
            builder.setSpeed(speedMps);
        }
        sender.onLocationChanged(builder.build());
    }

    /** IMU 传感器回调中调用 */
    public void onImuUpdate(float gx, float gy, float gz,
                            float ax, float ay, float az) {
        SensorDataSender sender = DrEngineManager.getInstance().getSensorDataSender();
        if (sender == null) {
            return;
        }
        long ts = SystemClock.elapsedRealtime();
        sender.onGyroscopeDataReceived(gx, gy, gz, ts);
        sender.onAccelerometerDataReceived(ax, ay, az, ts);
    }

    /** 车身信号回调中调用 */
    public void onVehicleUpdate(float speedMps, @NonNull VehicleDataBean.GearStatus gear) {
        VehicleDataSender sender = DrEngineManager.getInstance().getVehicleDataSender();
        if (sender == null) {
            return;
        }
        VehicleDataBean data = VehicleDataBean.newBuilder()
                .setTimestamp(SystemClock.elapsedRealtime())
                .setSpeed(speedMps)
                .setGearStatus(gear)
                .build();
        sender.onVehicleDataReceived(data);
    }

    private void onDrPosition(@NonNull VehiclePositionBean position) {
        lastDrTimestamp = position.drTimestamp;
        // 送给导航 / 地图匹配
        // mapMatching.update(position.latitude, position.longitude, position.heading, ...);
    }

    /** 地图匹配结果回调中调用 */
    public void onMapMatchingResult(double mmLat, double mmLon, float mmHeading,
                                    double rawLat, double rawLon, float rawHeading,
                                    int confidence) {
        MapMatchingFeedbackSender sender =
                DrEngineManager.getInstance().getMapMatchingFeedbackSender();
        if (sender == null) {
            return;
        }
        MapMatchingFeedbackPositionBean feedback = MapMatchingFeedbackPositionBean.newBuilder()
                .setTimestamp(SystemClock.elapsedRealtime())
                .setDrTimestamp(lastDrTimestamp)
                .setRawLat(rawLat)
                .setRawLon(rawLon)
                .setRawHeading(rawHeading)
                .setMmLat(mmLat)
                .setMmLon(mmLon)
                .setMmHeading(mmHeading)
                .setMmConfidence(confidence)
                .build();
        sender.onMapMatchingFeedback(feedback);
    }
}

注意事项

初始化与生命周期

  • 必须先 init() 且返回 Success,再获取 getXxxDataSender();否则返回 null
  • 已成功初始化后再次 init() 会直接返回 Success,不会重新加载配置;需重启请先 destroy()init()

时间戳与数据质量

  • 传感器 / 车身 timestamp 必须使用 elapsedRealtime
  • MM 反馈的 drTimestamp 必须与最近一次 VehiclePositionBean.drTimestamp 一致。

线程与回调

  • onVehiclePositionReceived 可能在非主线程触发,更新 UI 需切换主线程。
  • Listener 内勿做阻塞操作,避免拖慢引擎回调。

配置与存储

  • 需保证 configFilePathlogPath 对应目录可写;
  • 开启日志(setDrEngineLogEnabled(true))时必须设置 setLogPath

回放模式

  • setReplay(true) 时必须设置有效的 setReplayDataPath
  • resetForReplay(path) 仅在初始化成功后调用,否则抛 IllegalStateException

兼容性

  • SDK API 为 Java 实现,可直接在 Java 或 Kotlin 工程中调用。