Detour-API:修订间差异
Huangzhaowei(讨论 | 贡献) 无编辑摘要 |
|||
| (未显示3个用户的19个中间版本) | |||
| 第1行: | 第1行: | ||
= 1. 前言 = | |||
Detour在4321端口启动Web API服务,为上层应用提供定位、配置和辅助功能。 | |||
= 2. 接口定义 = | |||
== 2.1 定位 == | |||
''' | === 2.1.1 读取位姿 === | ||
'''方法''':GET '''路径''':/getPos '''返回''':JSON | |||
= | 举例:<syntaxhighlight lang="js"> | ||
GET http://127.0.0.1:4321/getPos | |||
{ | |||
"x": 190702.844, // 位置单位是毫米,使用直角坐标系 | |||
"y": 336956.9, | |||
"th": 113.340424, // 角度单位是度 | |||
"l_step": 27, // 定位步长,=2表示定位正常,=9999表示手动输入位置 | |||
// >2表示回环失败,此时机器人位置附近的关键帧配准得分低于阈值, | |||
// 或关键帧计算出的位姿与当前位姿偏差过大而被过滤。l_step值 | |||
// 越大表示回环失败时间越长。一般而言,在行驶时,可能存在 | |||
// 短暂的激光SLAM定位不良区域,l_step<15可继续行驶,用 | |||
// 激光里程计继续输出位姿,此时激光里程计累计误差较小。 | |||
// l_step>15时应停车,重新定位成功后继续。 | |||
"tick": 63855102200497 // 时间戳,系统时间的Tick | |||
} | |||
// 如果发生错误,比如激光雷达停止发送测量数据,则error属性 | |||
// 显示错误。使用位姿接口数据时,应校验error字段,如非null则位姿不可用。 | |||
{ | |||
"x": 129163.734, | |||
"y": 416628.938, | |||
"th": 138.75148, | |||
"l_step": 200, | |||
"tick": 63855105852361, | |||
"error": "Timeout" | |||
} | |||
</syntaxhighlight>说明: | |||
* 使用l_step判断建图质量。建图后遥控移动机器人沿工作路线走一圈,观察l_step值,由于不存在理想的SLAM环境,因此l_step值会短暂>2,一般<7以内可认为SLAM稳定工作。如在固定路段出现回环失败现象,则要考虑应对措施,比如用挡板改善环境轮廓、用反光棒切换到有反SLAM。 | |||
* 在运行时,可根据l_step结合运动状态判断“盲目行驶”风险,如l_step>15且在移动,应停车报警,恢复定位后继续行驶。l_step计算涉及多个因素,因此用范围来判断,如给出的<15区间,可根据实际情况调整区间使用。 | |||
* 激光SLAM以激光里程计输出位姿(x, y, theta)。激光里程计根据相邻激光雷达帧点云计算位移(距离和角度),积分以推算移动机器人航迹,激光里程计持续输出位姿。回环线程则搜索移动机器人附近的关键帧(路标),计算激光雷达帧点云与它们的配准程度,锁定配准得分高于阈值且最高的关键帧,以此修正激光里程计的累积误差,这个过程称为回环。l_step=2表示移动机器人当前位姿附近的关键帧被锁定,因而获得精确位置。l_step>2则表示回环失败,激光里程计继续输出位姿,但是关键帧锁定失败,因此累积误差不能消除,其值越大,输出位姿的误差性可能越大。l_step<15是我们给出的经验区间。 | |||
''' | === 2.1.2 暂停定位 === | ||
'''方法''':GET '''路径''':/pause '''返回''':JSON | |||
= | 举例:<syntaxhighlight lang="js"> | ||
GET http://127.0.0.1:4321/pause | |||
{ | |||
"success": true, | |||
"id": 0 | |||
} | |||
</syntaxhighlight>说明: | |||
* 与“恢复定位”接口配套使用。在Detour发布“紧耦合”特性之前,此接口用于暂停Detour定位功能(包括激光里程计和回环功能),改用目标跟随、巡线或轮里程计等其他定位手段行驶,通过特定场景后恢复定位,并用“指定位置重定位”功能重定位,以恢复激光SLAM功能。 | |||
* 暂停定位接口相当于关闭Detour,使其不再输出位姿,此时“读取位姿”接口将返回"timeout"错误。 | |||
=== 2.1.3 恢复定位 === | |||
'''方法''':GET '''路径''':/resume '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/resume | |||
{ | |||
"success": true, | |||
"id": 0 | |||
} | |||
</syntaxhighlight> | |||
=== ''' | === 2.1.4 全局重定位 === | ||
'''方法''':GET '''路径''':/relocalize '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/relocalize | |||
{ | |||
"performed": true // 执行成功 | |||
} | |||
</syntaxhighlight>说明: | |||
* 全局重定位指令Detour搜索所有关键帧,取与当前点云配准分数最高者锁定,获得移动机器人当前位姿。如果点云与关键帧配准分数均低于阈值,则重定位失败。 | |||
* 全局重定位应用在环境轮廓稳定且有独特几何特征区域。如果环境轮廓与数个关键帧相似,且得分相差无几,则会定位到错误位置。建议在固定位置使用重定位接口,比如在干道旁设置固定的重定位站点。 | |||
''' | === 2.1.5 指定位置重定位 === | ||
'''方法''':GET '''路径''':/setLocation '''返回''':JSON | |||
= | 举例:<syntaxhighlight lang="js"> | ||
// 以(x, y, th)设定移动机器人当前位姿,注意它们都是float类型,值都应有小数点后1位。 | |||
// 激光里程计的航迹切到给定位姿。 | |||
// 如果给定位姿与实际位姿的距离过大,将导致回环失败(可锁定关键帧给出的观测位姿与当前位姿差 | |||
// 大于误差范围时,关键帧将被丢弃,见detour参数说明)。 | |||
GET http://127.0.0.1:4321/setLocation?x=100.0&y=100.0&th=90.0 | |||
{ | |||
"x": 102.061165, | |||
"y": 97.67917, | |||
"th": 90.0271454, | |||
"l_step": 10000, | |||
"tick": 63855111242596 | |||
} | |||
</syntaxhighlight>说明: | |||
* 一般用于SLAM不良区域。比如潜伏式牵引车使用目标跟踪功能从料车缓存机构走出时(料车腿和缓存机构遮挡雷达视野而导致定位错误),指定位置使激光SLAM重新定位。 | |||
''' | === 2.1.6 指定关键帧回环 === | ||
'''方法''':GET '''路径''':/relocalize '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// 指示激光SLAM优先选用给定的关键帧。 | |||
// preferredKfId赋值为逗号分隔的关键帧Id集合。 | |||
// 给定的关键帧被列入优先选用集合,提高其匹配权重。 | |||
GET http://127.0.0.1:4321/setPreferredKFID?preferredKfiId=1130788673,1815389948 | |||
{ | |||
"success": true | |||
} | |||
</syntaxhighlight>说明: | |||
* 如果同一个站点的停准精度差异是锁定不同关键帧所致,可使用此接口指示激光SLAM选用特定的关键帧,以提高SLAM精度稳定性。在有限视野场景下(如180度激光雷达视野,或周围环境轮廓不良),可能会锁定不同关键帧(如站点前关键帧由于点云配准分数较低而未选用)而带来厘米级定位误差。此接口用于提高特定关键帧权重,以稳定锁定该关键帧,获得稳定的位姿。 | |||
''' | === 2.1.7 启停回环功能 === | ||
'''方法''':GET '''路径''':/switchPosMatch '''返回''':JSON | |||
== | 举例:<syntaxhighlight lang="js"> | ||
// 启用(或停用)给定图层的回环功能。 | |||
// disable=false表示启用,true表示停用。 | |||
// name是图层名称(单线激光SLAM标签的Lidar点云图层) | |||
GET http://127.0.0.1:4321/switchPosMatch?disabled=false&name=mainmap | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight>说明: | |||
* 停用给定图层的回环功能时,激光SLAM不再搜索该图层的关键帧。 | |||
* 本接口与暂停定位接口的差异在于,前者只是停用指定图层回环功能,激光里程计继续输出位姿;后者停止激光里程计和回环,输出位姿不可使用。 | |||
''' | === 2.1.8 开启建图/锁定图层 === | ||
*'''方法''':GET '''路径''':/call?cmd=ground.SwitchMode(1) '''返回''':{"result":"void"} 举例:<syntaxhighlight lang="js"> | |||
// 开启或关闭建图 | |||
// 一般ground表示地纹图层名称,mainmap是激光图层名称 | |||
// 0是建图 1锁定图层 | |||
GET http:/call?cmd=ground.SwitchMode(1) | |||
return | |||
{ | |||
"result":"void" | |||
} | |||
</syntaxhighlight>说明: | |||
** 注意图层名称,开启建图和锁定UI界面的状态并不会变化。 | |||
== 2.2 配置 == | |||
=== 2.2.1 加载地图 === | |||
'''方法''':GET '''路径''':/loadMap '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// 指定图层加载激光地图。 | |||
// name是图层名称,fn是激光地图文件名称。 | |||
GET http://127.0.0.1:4321/loadMap?name=mainmap&fn=mainmap.2dlm | |||
{ | |||
"performed": true, | |||
"success": false | |||
} | |||
</syntaxhighlight>说明: | |||
* 可用于激光地图切换场景。比如移动机器人乘坐电梯到二楼时,把激光地图从一楼切换到二楼。 | |||
=== ''' | === 2.2.2 保存地图 === | ||
'''方法''':GET '''路径''':/saveMap '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/saveMap?name=mainmap&fn=mainmap.2dlm | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight>说明: | |||
* 图层的激光地图修改后,使用本接口将其存入激光地图文件。 | |||
2dlm地图格式可以参考该C#代码:[https://dev.lessokaji.com/index.php?topic=249.0 2dlm地图文件格式 (lessokaji.com]) | |||
''' | === 2.2.3 读取配置文件 === | ||
'''方法''':GET '''路径''':/getConf '''返回''':JSON | |||
= | 举例:<syntaxhighlight lang="js"> | ||
GET http://127.0.0.1:4321/getConf | |||
{ | |||
"overrideLanguage": "/", | |||
"license": "", | |||
"initX": 15659.2, | |||
"initY": 2436.9, | |||
"initTh": 11.7, | |||
"recordLastPos": true, | |||
"layout": { | |||
"chassis": { | |||
"width": 1200.0, | |||
"length": 2000.0, | |||
"contour": [ | |||
-445.0, | |||
330.0, | |||
445.0, | |||
330.0, | |||
445.0, | |||
-330.0, | |||
-445.0, | |||
-330.0 | |||
] | |||
}, | |||
"components": [ | |||
] | |||
}, | |||
"odometries": [ | |||
], | |||
"positioning": [ | |||
], | |||
"autoStart": true, | |||
"debug": true, | |||
"useGPU": true, | |||
"TCtimeWndSz": 150, | |||
"TCtimeWndLimit": 700, | |||
"useTC": true, | |||
"guru": { | |||
"SpatialIndex2StageCache": 4194304, | |||
"SpatialIndex1StageCache": 1048576, | |||
"ICPFastIterFac": 0.8, | |||
"ICPUseFastMode": false, | |||
"ICP2DMaxIter": 16, | |||
"RippleEnableEqualize": true, | |||
"Lidar2dMapMaxIter": 50, | |||
"phaseLockLvl": 3, | |||
"rotMapProjectionLength": 500.0, | |||
"gicp_p2pfac": 0.02, | |||
"extractPlaneThresE": 700.0, | |||
"lo3dlineWeightScale": 0.3, | |||
"inputScale": 1.0, | |||
"Lidar2DRippleDistDecay": 15000.0, | |||
"Lidar2DRippleScale": 1.0, | |||
"SI2DRectSmall": 130, | |||
"SI2DRectBig": 600, | |||
"TCVarMax": 1600.0, | |||
"TCMaxBadEdges": 3, | |||
"TCKalmanUseCurrentFac": 0.2, | |||
"debugReg2D": true, | |||
"ICP2ddebugSource": -1, | |||
"ICP2dReflexWeightTranslateFac": 3.0, | |||
"TCInterconnectType": 0, | |||
"TCAutoCaliberation": false, | |||
"dumpCriticalData": false, | |||
"dumpLocation": false, | |||
"logKeepDays": 7, | |||
"GOAllowSO3": false, | |||
"TCAllowSO3": true, | |||
"MaxTCIters": 1000, | |||
"GOStopMvmt": 1.0, | |||
"TCDiscardFactor": 0.4, | |||
"TCCouplingSigmaVXY": 0.2, | |||
"TCCouplingSigmaVTh": 0.5 | |||
}, | |||
"recordPosInterval": 500, | |||
"minimized": false | |||
} | |||
</syntaxhighlight>说明: | |||
* 本接口返回Detour使用的配置文件内容,一般是detour.json。 | |||
* 可结合本接口和组件属性赋值接口实现激光雷达自动标定功能。首先读出配置,解析出要标定的激光雷达外参值(x, y, th),根据激光雷达外参标定方法实现移动机器人的标定行走功能,使用读取位姿、启停回环功能、组件属性赋值等接口计算并设置外参。 | |||
''' | === 2.2.4 组件属性赋值 === | ||
'''方法''':GET '''路径''':/set '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// 可设置以下组件的属性值: | |||
// - 车体部件。车体布局编辑器中列出的车体部件,一般是激光雷达,比如frontlidar。 | |||
// - 里程计。里程计标签中的里程计。 | |||
// - 地图。单线激光SLAM标签中的Lidar点云图层,比如mainmap。 | |||
// path是对象属性,本例是frontlidar.x,即激光雷达的x外参。 | |||
// val是值。 | |||
GET http://127.0.0.1:4321/set?path=frontlidar.x&val=500 | |||
{ | |||
"success": true | |||
} | |||
</syntaxhighlight>说明: | |||
* Detour使用该接口配置DetourLite参数。由于组件属性赋值不支持创建组件,因此在Detour创建激光雷达时,该雷达不会同步给DetourLite,进而触发对该雷达属性赋值时报“DetourLite参数设置错误”提示。 | |||
''' | === 2.2.5 上传资源 === | ||
'''方法''':POST '''路径''':/uploadRes '''返回''':JSON | |||
< | 举例:<syntaxhighlight lang="js"> | ||
// fn是资源文件名。 | |||
// POST Body是上传的资源文件内容。 | |||
POST http://127.0.0.1:4321/uploadRes?fn=foo | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight>说明: | |||
* 本接口可向Detour所在目录上传文件。比如激光地图文件。 | |||
=== 2.2.6 下载资源 === | |||
'''方法''':GET '''路径''':/downloadRes '''返回''':字节流 | |||
< | 举例:<syntaxhighlight lang="js"> | ||
GET http://127.0.0.1:4321/downloadRes?fn=foo | |||
// 返回foo文件内容的字节流 | |||
< | </syntaxhighlight> | ||
''' | === 2.2.7 保存导航配置 === | ||
'''方法''':Get'''路径''':/set '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// | |||
// 比如保存雷达名称,就可以保存所有配置信息到本地了 | |||
Get http://127.0.0.1:4321/set?path=frontlidar.name&val=frontlidar | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight> | |||
=== ''' | === 2.2.8 外部加载二维码地图 === | ||
'''方法''':Get'''路径''':/call?cmd=tagmap.load()'''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// load 里面输入二维码地图路径即可 | |||
Get 127.0.0.1:4321/call?cmd=tagmap.load(d:/src/detour/build/fuck.json) | |||
re | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight> | |||
== 2.3 状态 == | |||
''' | === 2.3.1 读取运行统计 === | ||
'''方法''':GET '''路径''':/getStat '''返回''':JSON | |||
= | 举例:<syntaxhighlight lang="js"> | ||
GET http://127.0.0.1:4321/getStat | |||
{ | |||
"runningSeconds": 878.7448942, | |||
"layoutStat": { | |||
"frontlidar": { | |||
"status": "等待帧", | |||
"lidar_tick": 2542, | |||
"interval": 77, | |||
"validPoints": 196, | |||
"preprocessTime": 0.0, | |||
"timeBudget": 81.036527022839024, | |||
"reflexN": 0.0, | |||
"selfFitting": 0.0 | |||
}, | |||
"cart_odometry": { | |||
"status": "初始化捕捉完毕", | |||
"use": true, | |||
"feedstate": "未开始捕获", | |||
"time": 0, | |||
"type": "/", | |||
"counter": 0, | |||
"pos": "/", | |||
"selfFitting": 0.0 | |||
} | |||
}, | |||
"odoStat": { | |||
"odometry_0": { | |||
"reg_ms": 6.0, | |||
"loop_ms": 136.0, | |||
"interval": 1, | |||
"reg_mode": 0, | |||
"kf_state": "10011/+1", | |||
"SeqScore": 0.950587451, | |||
"LOScore": 0.9299651, | |||
"kfreason": ".", | |||
"otherDebug": "", | |||
"status": "waitframe", | |||
"pause": false | |||
} | |||
}, | |||
"posStat": {}, | |||
"TCStat": { | |||
"commitId": 1394, | |||
"computeStat": "tcfrontlidar...tp", | |||
"fitmethod": 1, | |||
"goIters": 0, | |||
"discarding": "", | |||
"fitexplain": "frontlidar:5L/1.61", | |||
"poseEstim": "/", | |||
"TCPerf": "rigid:0.054,go:0.0622,post:0.0188", | |||
"CouplingScores": "frontlidar(5):1.00/1.00", | |||
"TCVar": 0.0, | |||
"err": 0.0, | |||
"historyLs": "frontlidar:N1/5", | |||
"powers": "True:(,()" | |||
}, | |||
"GOStat": { | |||
"maxTension": 0.0, | |||
"edgeN": 0, | |||
"OPS": 8, | |||
"Use": true | |||
}, | |||
"licence": "DID:4D222EB2BEE27897", | |||
"globalStat": { | |||
"paused": false, | |||
"IsSettingPosition": false | |||
} | |||
} | |||
</syntaxhighlight>说明: | |||
* 返回结果与Detour上相应对象的状态一致。 | |||
''' | === 2.3.2 导出工作区 === | ||
'''方法''':GET '''路径''':/dumpWorkspace '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/dumpWorkspace | |||
OK | |||
< | </syntaxhighlight>说明: | ||
* 在Detour的log/workspace目录下生成图像日志,包括一张PNG图片,内容为Detour主界面的地图;一个运行日志文件。 | |||
''' | === 2.3.3 读取点云 === | ||
'''方法''':GET '''路径''':/getSensors '''返回''':字节流 | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/getSensors | |||
// 返回字节流是点云数据,伪代码表述格式如下: | |||
[ | |||
{ // 激光雷达 | |||
lidar.name : String; // 雷达名称,C# String类型 | |||
keyFrame.x : float; // 关键帧位姿 | |||
keyFrame.y : float; | |||
keyFrame.th : float; | |||
pointCloud.length : int; // 点云数组长度 | |||
[ | |||
point.x : float; // 测量点坐标 | |||
point.y : float; | |||
] | |||
} | |||
] | |||
</syntaxhighlight>说明: | |||
* Detour使用此接口读取DetourLite点云数据。 | |||
* 调用该接口的频率应控制在2Hz以内,以免干扰Detour内核计算性能。 | |||
* 非必要不使用原则。如,在丢定位时(如l_step>15),在管控的维护功能界面显示点云,以帮助操作者识别移动机器人实际位姿,然后使用指定位置重定位接口找回定位。在这个场景中,只需在处理定位问题时读取点云,处理完毕后停止调用接口。 | |||
''' | === 2.3.4 读取版本 === | ||
'''方法''':GET '''路径''':/getVersion '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
GET http://127.0.0.1:4321/getVersion | |||
shicong-liu@2024-06-26T13:25:22+08|master_b8dc | |||
< | </syntaxhighlight> | ||
== 2.4 操作 == | |||
''' | === 2.4.1 调用方法 === | ||
'''方法''':GET '''路径''':/call '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// 调用对象方法。 | |||
// cmd是对象方法。本例是调用cart_odometry.capture()方法,即 | |||
// 触发外部定位源cart_odometry(轮里程计)的捕获方法。 | |||
GET http://127.0.0.1:4321/call?cmd=cart_odometry.capture() | |||
// 返回该方法的返回值 | |||
{ | |||
"result": "void" | |||
} | |||
</syntaxhighlight>说明: | |||
* 本接口相当于RPC(Remote Procedure Call)调用。应根据代码调用。 | |||
''' | === 2.4.2 设置激光雷达蒙板 === | ||
'''方法''':POST '''路径''':/setLidar2DOdometryMask '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// odometry是里程计标签中的里程计名称。本例的odometry_0是默认激光里程计名称。 | |||
// POST Body是蒙板顶点数组,用于构造出封闭多边形,落在多边形内的点云都会被过滤。 | |||
POST http://127.0.0.1:4321/setLidar2DOdometryMask?odometry=odometry_0 | |||
[ | |||
{ | |||
"X": 123, | |||
"Y": 456 | |||
}, | |||
{ | |||
"X": 123, | |||
"Y": 456 | |||
}, | |||
{ | |||
"X": 123, | |||
"Y": 456 | |||
} | |||
] | |||
{ | |||
< | "success": true | ||
} | |||
</syntaxhighlight>说明: | |||
* 本接口只影响内存中的配置,不会存入配置文件。 | |||
* 坐标参考车体编辑器,直角坐标系的原点在底盘几何中心。 | |||
= 2.4 定位 = | |||
=== 2.4.1 外部定位源 === | |||
输入外部定位源前,首先要在车体编辑器里增加对应的“外部定位源”部件 | |||
'''方法''':POST '''路径''':/postExternPosition '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// name是外部定位源。本例的cart_odometry是IMU轮里程计。 | |||
// POST Body是外部定位源的航迹。 | |||
POST http://127.0.0.1:4321/postExternPosition?name=cart_odometry | |||
{ | |||
"name": "cart_odometry", // 轮里程计+IMU对应在Detour中的部件名 | |||
"counter": 0, // 单调+1 | |||
"hasTranslation": true, // 可移动,(x, y) | |||
"hasRotation": true, // 可旋转,(th) | |||
"is3D": false, // 在三维平面运动,输出(x, y, z, th) | |||
"is2D": true, // 在二维平面运动,输出(x, y, th) | |||
"integrated": true, // 是否通过积分得到的位姿(轮里程计通过积分获得,gps是绝对位置) | |||
"startingTick": 0, // 时间戳,不变则表示这是一条航迹。程序启动时可用系统Ticks为初始值 | |||
"x": 0.0, // 当前位姿 | |||
"y": 0.0, | |||
"z": 0.0, // 二维平面的z总是0 | |||
"th": 0.0, | |||
} | |||
{ | |||
"performed": true | |||
} | |||
</syntaxhighlight> | |||
说明: | |||
* 向Detour推送外部定位源的位姿。外部定位源一般是IMU轮里程计、GNSS RTK。Detour紧耦合功能融合多个里程计,择优输出一个位姿。 | |||
* IMU轮里程计的位姿发布频率建议20Hz(经测试获得的经验值)。 | |||
* 外部定位源的inputType="web",默认是"internal"(表示从Medulla发布)。设置错误将导致接口调用失败。 | |||
* 集成外部定位源时,应测试其发布频率,以免过快或过慢频率干扰紧耦合错误选用里程计。 | |||
* 以下是外部定位源表: | |||
{| class="wikitable" | |||
|+定位源类型和设置方法 | |||
! | |||
!hasTranslation | |||
!hasRotation | |||
!is3D | |||
!is2D | |||
!integrated | |||
!toRemap | |||
|- | |||
|GNSS定位 | |||
|true | |||
|true | |||
如果有的话 | |||
|false | |||
|true | |||
|false | |||
|true | |||
经纬度-地图位置需要标定:[[使用手册 - 卫星或基站定位标定|使用手册]] | |||
|- | |||
|轮编里程计(须自行融合IMU) | |||
|true | |||
|true | |||
|false | |||
|true | |||
|true | |||
须自行积分,直接从0开始积分即可 | |||
| | |||
|} | |||
''' | === 2.4.2 外部二维码输入 === | ||
'''方法''':Get'''路径''':/call?cmd=lesstag.inputextern(id,x,y,th) '''返回''':JSON | |||
举例:<syntaxhighlight lang="js"> | |||
// id,x,y,th分别表示二维码的tag,xyth数值。 | |||
Get http://127.0.0.1:4321/call?cmd=lesstag.inputextern(id,x,y,th) | |||
{ | |||
"result": true | |||
} | |||
</syntaxhighlight> | |||
说明: | |||
* 配置此项功能需要把D参数中二维码配置useExtern改成true才可以生效 | |||
2025年4月28日 (一) 16:34的最新版本
1. 前言
Detour在4321端口启动Web API服务,为上层应用提供定位、配置和辅助功能。
2. 接口定义
2.1 定位
2.1.1 读取位姿
方法:GET 路径:/getPos 返回:JSON
举例:
GET http://127.0.0.1:4321/getPos
{
"x": 190702.844, // 位置单位是毫米,使用直角坐标系
"y": 336956.9,
"th": 113.340424, // 角度单位是度
"l_step": 27, // 定位步长,=2表示定位正常,=9999表示手动输入位置
// >2表示回环失败,此时机器人位置附近的关键帧配准得分低于阈值,
// 或关键帧计算出的位姿与当前位姿偏差过大而被过滤。l_step值
// 越大表示回环失败时间越长。一般而言,在行驶时,可能存在
// 短暂的激光SLAM定位不良区域,l_step<15可继续行驶,用
// 激光里程计继续输出位姿,此时激光里程计累计误差较小。
// l_step>15时应停车,重新定位成功后继续。
"tick": 63855102200497 // 时间戳,系统时间的Tick
}
// 如果发生错误,比如激光雷达停止发送测量数据,则error属性
// 显示错误。使用位姿接口数据时,应校验error字段,如非null则位姿不可用。
{
"x": 129163.734,
"y": 416628.938,
"th": 138.75148,
"l_step": 200,
"tick": 63855105852361,
"error": "Timeout"
}
说明:
- 使用l_step判断建图质量。建图后遥控移动机器人沿工作路线走一圈,观察l_step值,由于不存在理想的SLAM环境,因此l_step值会短暂>2,一般<7以内可认为SLAM稳定工作。如在固定路段出现回环失败现象,则要考虑应对措施,比如用挡板改善环境轮廓、用反光棒切换到有反SLAM。
- 在运行时,可根据l_step结合运动状态判断“盲目行驶”风险,如l_step>15且在移动,应停车报警,恢复定位后继续行驶。l_step计算涉及多个因素,因此用范围来判断,如给出的<15区间,可根据实际情况调整区间使用。
- 激光SLAM以激光里程计输出位姿(x, y, theta)。激光里程计根据相邻激光雷达帧点云计算位移(距离和角度),积分以推算移动机器人航迹,激光里程计持续输出位姿。回环线程则搜索移动机器人附近的关键帧(路标),计算激光雷达帧点云与它们的配准程度,锁定配准得分高于阈值且最高的关键帧,以此修正激光里程计的累积误差,这个过程称为回环。l_step=2表示移动机器人当前位姿附近的关键帧被锁定,因而获得精确位置。l_step>2则表示回环失败,激光里程计继续输出位姿,但是关键帧锁定失败,因此累积误差不能消除,其值越大,输出位姿的误差性可能越大。l_step<15是我们给出的经验区间。
2.1.2 暂停定位
方法:GET 路径:/pause 返回:JSON
举例:
GET http://127.0.0.1:4321/pause
{
"success": true,
"id": 0
}
说明:
- 与“恢复定位”接口配套使用。在Detour发布“紧耦合”特性之前,此接口用于暂停Detour定位功能(包括激光里程计和回环功能),改用目标跟随、巡线或轮里程计等其他定位手段行驶,通过特定场景后恢复定位,并用“指定位置重定位”功能重定位,以恢复激光SLAM功能。
- 暂停定位接口相当于关闭Detour,使其不再输出位姿,此时“读取位姿”接口将返回"timeout"错误。
2.1.3 恢复定位
方法:GET 路径:/resume 返回:JSON
举例:
GET http://127.0.0.1:4321/resume
{
"success": true,
"id": 0
}
2.1.4 全局重定位
方法:GET 路径:/relocalize 返回:JSON
举例:
GET http://127.0.0.1:4321/relocalize
{
"performed": true // 执行成功
}
说明:
- 全局重定位指令Detour搜索所有关键帧,取与当前点云配准分数最高者锁定,获得移动机器人当前位姿。如果点云与关键帧配准分数均低于阈值,则重定位失败。
- 全局重定位应用在环境轮廓稳定且有独特几何特征区域。如果环境轮廓与数个关键帧相似,且得分相差无几,则会定位到错误位置。建议在固定位置使用重定位接口,比如在干道旁设置固定的重定位站点。
2.1.5 指定位置重定位
方法:GET 路径:/setLocation 返回:JSON
举例:
// 以(x, y, th)设定移动机器人当前位姿,注意它们都是float类型,值都应有小数点后1位。
// 激光里程计的航迹切到给定位姿。
// 如果给定位姿与实际位姿的距离过大,将导致回环失败(可锁定关键帧给出的观测位姿与当前位姿差
// 大于误差范围时,关键帧将被丢弃,见detour参数说明)。
GET http://127.0.0.1:4321/setLocation?x=100.0&y=100.0&th=90.0
{
"x": 102.061165,
"y": 97.67917,
"th": 90.0271454,
"l_step": 10000,
"tick": 63855111242596
}
说明:
- 一般用于SLAM不良区域。比如潜伏式牵引车使用目标跟踪功能从料车缓存机构走出时(料车腿和缓存机构遮挡雷达视野而导致定位错误),指定位置使激光SLAM重新定位。
2.1.6 指定关键帧回环
方法:GET 路径:/relocalize 返回:JSON
举例:
// 指示激光SLAM优先选用给定的关键帧。
// preferredKfId赋值为逗号分隔的关键帧Id集合。
// 给定的关键帧被列入优先选用集合,提高其匹配权重。
GET http://127.0.0.1:4321/setPreferredKFID?preferredKfiId=1130788673,1815389948
{
"success": true
}
说明:
- 如果同一个站点的停准精度差异是锁定不同关键帧所致,可使用此接口指示激光SLAM选用特定的关键帧,以提高SLAM精度稳定性。在有限视野场景下(如180度激光雷达视野,或周围环境轮廓不良),可能会锁定不同关键帧(如站点前关键帧由于点云配准分数较低而未选用)而带来厘米级定位误差。此接口用于提高特定关键帧权重,以稳定锁定该关键帧,获得稳定的位姿。
2.1.7 启停回环功能
方法:GET 路径:/switchPosMatch 返回:JSON
举例:
// 启用(或停用)给定图层的回环功能。
// disable=false表示启用,true表示停用。
// name是图层名称(单线激光SLAM标签的Lidar点云图层)
GET http://127.0.0.1:4321/switchPosMatch?disabled=false&name=mainmap
{
"performed": true
}
说明:
- 停用给定图层的回环功能时,激光SLAM不再搜索该图层的关键帧。
- 本接口与暂停定位接口的差异在于,前者只是停用指定图层回环功能,激光里程计继续输出位姿;后者停止激光里程计和回环,输出位姿不可使用。
2.1.8 开启建图/锁定图层
- 方法:GET 路径:/call?cmd=ground.SwitchMode(1) 返回:{"result":"void"} 举例:说明:
// 开启或关闭建图 // 一般ground表示地纹图层名称,mainmap是激光图层名称 // 0是建图 1锁定图层 GET http:/call?cmd=ground.SwitchMode(1) return { "result":"void" }
- 注意图层名称,开启建图和锁定UI界面的状态并不会变化。
2.2 配置
2.2.1 加载地图
方法:GET 路径:/loadMap 返回:JSON
举例:
// 指定图层加载激光地图。
// name是图层名称,fn是激光地图文件名称。
GET http://127.0.0.1:4321/loadMap?name=mainmap&fn=mainmap.2dlm
{
"performed": true,
"success": false
}
说明:
- 可用于激光地图切换场景。比如移动机器人乘坐电梯到二楼时,把激光地图从一楼切换到二楼。
2.2.2 保存地图
方法:GET 路径:/saveMap 返回:JSON
举例:
GET http://127.0.0.1:4321/saveMap?name=mainmap&fn=mainmap.2dlm
{
"performed": true
}
说明:
- 图层的激光地图修改后,使用本接口将其存入激光地图文件。
2dlm地图格式可以参考该C#代码:2dlm地图文件格式 (lessokaji.com)
2.2.3 读取配置文件
方法:GET 路径:/getConf 返回:JSON
举例:
GET http://127.0.0.1:4321/getConf
{
"overrideLanguage": "/",
"license": "",
"initX": 15659.2,
"initY": 2436.9,
"initTh": 11.7,
"recordLastPos": true,
"layout": {
"chassis": {
"width": 1200.0,
"length": 2000.0,
"contour": [
-445.0,
330.0,
445.0,
330.0,
445.0,
-330.0,
-445.0,
-330.0
]
},
"components": [
]
},
"odometries": [
],
"positioning": [
],
"autoStart": true,
"debug": true,
"useGPU": true,
"TCtimeWndSz": 150,
"TCtimeWndLimit": 700,
"useTC": true,
"guru": {
"SpatialIndex2StageCache": 4194304,
"SpatialIndex1StageCache": 1048576,
"ICPFastIterFac": 0.8,
"ICPUseFastMode": false,
"ICP2DMaxIter": 16,
"RippleEnableEqualize": true,
"Lidar2dMapMaxIter": 50,
"phaseLockLvl": 3,
"rotMapProjectionLength": 500.0,
"gicp_p2pfac": 0.02,
"extractPlaneThresE": 700.0,
"lo3dlineWeightScale": 0.3,
"inputScale": 1.0,
"Lidar2DRippleDistDecay": 15000.0,
"Lidar2DRippleScale": 1.0,
"SI2DRectSmall": 130,
"SI2DRectBig": 600,
"TCVarMax": 1600.0,
"TCMaxBadEdges": 3,
"TCKalmanUseCurrentFac": 0.2,
"debugReg2D": true,
"ICP2ddebugSource": -1,
"ICP2dReflexWeightTranslateFac": 3.0,
"TCInterconnectType": 0,
"TCAutoCaliberation": false,
"dumpCriticalData": false,
"dumpLocation": false,
"logKeepDays": 7,
"GOAllowSO3": false,
"TCAllowSO3": true,
"MaxTCIters": 1000,
"GOStopMvmt": 1.0,
"TCDiscardFactor": 0.4,
"TCCouplingSigmaVXY": 0.2,
"TCCouplingSigmaVTh": 0.5
},
"recordPosInterval": 500,
"minimized": false
}
说明:
- 本接口返回Detour使用的配置文件内容,一般是detour.json。
- 可结合本接口和组件属性赋值接口实现激光雷达自动标定功能。首先读出配置,解析出要标定的激光雷达外参值(x, y, th),根据激光雷达外参标定方法实现移动机器人的标定行走功能,使用读取位姿、启停回环功能、组件属性赋值等接口计算并设置外参。
2.2.4 组件属性赋值
方法:GET 路径:/set 返回:JSON
举例:
// 可设置以下组件的属性值:
// - 车体部件。车体布局编辑器中列出的车体部件,一般是激光雷达,比如frontlidar。
// - 里程计。里程计标签中的里程计。
// - 地图。单线激光SLAM标签中的Lidar点云图层,比如mainmap。
// path是对象属性,本例是frontlidar.x,即激光雷达的x外参。
// val是值。
GET http://127.0.0.1:4321/set?path=frontlidar.x&val=500
{
"success": true
}
说明:
- Detour使用该接口配置DetourLite参数。由于组件属性赋值不支持创建组件,因此在Detour创建激光雷达时,该雷达不会同步给DetourLite,进而触发对该雷达属性赋值时报“DetourLite参数设置错误”提示。
2.2.5 上传资源
方法:POST 路径:/uploadRes 返回:JSON
举例:
// fn是资源文件名。
// POST Body是上传的资源文件内容。
POST http://127.0.0.1:4321/uploadRes?fn=foo
{
"performed": true
}
说明:
- 本接口可向Detour所在目录上传文件。比如激光地图文件。
2.2.6 下载资源
方法:GET 路径:/downloadRes 返回:字节流
举例:
GET http://127.0.0.1:4321/downloadRes?fn=foo
// 返回foo文件内容的字节流
2.2.7 保存导航配置
方法:Get路径:/set 返回:JSON
举例:
//
// 比如保存雷达名称,就可以保存所有配置信息到本地了
Get http://127.0.0.1:4321/set?path=frontlidar.name&val=frontlidar
{
"performed": true
}
2.2.8 外部加载二维码地图
方法:Get路径:/call?cmd=tagmap.load()返回:JSON
举例:
// load 里面输入二维码地图路径即可
Get 127.0.0.1:4321/call?cmd=tagmap.load(d:/src/detour/build/fuck.json)
re
{
"performed": true
}
2.3 状态
2.3.1 读取运行统计
方法:GET 路径:/getStat 返回:JSON
举例:
GET http://127.0.0.1:4321/getStat
{
"runningSeconds": 878.7448942,
"layoutStat": {
"frontlidar": {
"status": "等待帧",
"lidar_tick": 2542,
"interval": 77,
"validPoints": 196,
"preprocessTime": 0.0,
"timeBudget": 81.036527022839024,
"reflexN": 0.0,
"selfFitting": 0.0
},
"cart_odometry": {
"status": "初始化捕捉完毕",
"use": true,
"feedstate": "未开始捕获",
"time": 0,
"type": "/",
"counter": 0,
"pos": "/",
"selfFitting": 0.0
}
},
"odoStat": {
"odometry_0": {
"reg_ms": 6.0,
"loop_ms": 136.0,
"interval": 1,
"reg_mode": 0,
"kf_state": "10011/+1",
"SeqScore": 0.950587451,
"LOScore": 0.9299651,
"kfreason": ".",
"otherDebug": "",
"status": "waitframe",
"pause": false
}
},
"posStat": {},
"TCStat": {
"commitId": 1394,
"computeStat": "tcfrontlidar...tp",
"fitmethod": 1,
"goIters": 0,
"discarding": "",
"fitexplain": "frontlidar:5L/1.61",
"poseEstim": "/",
"TCPerf": "rigid:0.054,go:0.0622,post:0.0188",
"CouplingScores": "frontlidar(5):1.00/1.00",
"TCVar": 0.0,
"err": 0.0,
"historyLs": "frontlidar:N1/5",
"powers": "True:(,()"
},
"GOStat": {
"maxTension": 0.0,
"edgeN": 0,
"OPS": 8,
"Use": true
},
"licence": "DID:4D222EB2BEE27897",
"globalStat": {
"paused": false,
"IsSettingPosition": false
}
}
说明:
- 返回结果与Detour上相应对象的状态一致。
2.3.2 导出工作区
方法:GET 路径:/dumpWorkspace 返回:JSON
举例:
GET http://127.0.0.1:4321/dumpWorkspace
OK
说明:
- 在Detour的log/workspace目录下生成图像日志,包括一张PNG图片,内容为Detour主界面的地图;一个运行日志文件。
2.3.3 读取点云
方法:GET 路径:/getSensors 返回:字节流
举例:
GET http://127.0.0.1:4321/getSensors
// 返回字节流是点云数据,伪代码表述格式如下:
[
{ // 激光雷达
lidar.name : String; // 雷达名称,C# String类型
keyFrame.x : float; // 关键帧位姿
keyFrame.y : float;
keyFrame.th : float;
pointCloud.length : int; // 点云数组长度
[
point.x : float; // 测量点坐标
point.y : float;
]
}
]
说明:
- Detour使用此接口读取DetourLite点云数据。
- 调用该接口的频率应控制在2Hz以内,以免干扰Detour内核计算性能。
- 非必要不使用原则。如,在丢定位时(如l_step>15),在管控的维护功能界面显示点云,以帮助操作者识别移动机器人实际位姿,然后使用指定位置重定位接口找回定位。在这个场景中,只需在处理定位问题时读取点云,处理完毕后停止调用接口。
2.3.4 读取版本
方法:GET 路径:/getVersion 返回:JSON
举例:
GET http://127.0.0.1:4321/getVersion
shicong-liu@2024-06-26T13:25:22+08|master_b8dc
2.4 操作
2.4.1 调用方法
方法:GET 路径:/call 返回:JSON
举例:
// 调用对象方法。
// cmd是对象方法。本例是调用cart_odometry.capture()方法,即
// 触发外部定位源cart_odometry(轮里程计)的捕获方法。
GET http://127.0.0.1:4321/call?cmd=cart_odometry.capture()
// 返回该方法的返回值
{
"result": "void"
}
说明:
- 本接口相当于RPC(Remote Procedure Call)调用。应根据代码调用。
2.4.2 设置激光雷达蒙板
方法:POST 路径:/setLidar2DOdometryMask 返回:JSON
举例:
// odometry是里程计标签中的里程计名称。本例的odometry_0是默认激光里程计名称。
// POST Body是蒙板顶点数组,用于构造出封闭多边形,落在多边形内的点云都会被过滤。
POST http://127.0.0.1:4321/setLidar2DOdometryMask?odometry=odometry_0
[
{
"X": 123,
"Y": 456
},
{
"X": 123,
"Y": 456
},
{
"X": 123,
"Y": 456
}
]
{
"success": true
}
说明:
- 本接口只影响内存中的配置,不会存入配置文件。
- 坐标参考车体编辑器,直角坐标系的原点在底盘几何中心。
2.4 定位
2.4.1 外部定位源
输入外部定位源前,首先要在车体编辑器里增加对应的“外部定位源”部件
方法:POST 路径:/postExternPosition 返回:JSON
举例:
// name是外部定位源。本例的cart_odometry是IMU轮里程计。
// POST Body是外部定位源的航迹。
POST http://127.0.0.1:4321/postExternPosition?name=cart_odometry
{
"name": "cart_odometry", // 轮里程计+IMU对应在Detour中的部件名
"counter": 0, // 单调+1
"hasTranslation": true, // 可移动,(x, y)
"hasRotation": true, // 可旋转,(th)
"is3D": false, // 在三维平面运动,输出(x, y, z, th)
"is2D": true, // 在二维平面运动,输出(x, y, th)
"integrated": true, // 是否通过积分得到的位姿(轮里程计通过积分获得,gps是绝对位置)
"startingTick": 0, // 时间戳,不变则表示这是一条航迹。程序启动时可用系统Ticks为初始值
"x": 0.0, // 当前位姿
"y": 0.0,
"z": 0.0, // 二维平面的z总是0
"th": 0.0,
}
{
"performed": true
}
说明:
- 向Detour推送外部定位源的位姿。外部定位源一般是IMU轮里程计、GNSS RTK。Detour紧耦合功能融合多个里程计,择优输出一个位姿。
- IMU轮里程计的位姿发布频率建议20Hz(经测试获得的经验值)。
- 外部定位源的inputType="web",默认是"internal"(表示从Medulla发布)。设置错误将导致接口调用失败。
- 集成外部定位源时,应测试其发布频率,以免过快或过慢频率干扰紧耦合错误选用里程计。
- 以下是外部定位源表:
| hasTranslation | hasRotation | is3D | is2D | integrated | toRemap | |
|---|---|---|---|---|---|---|
| GNSS定位 | true | true
如果有的话 |
false | true | false | true
经纬度-地图位置需要标定:使用手册 |
| 轮编里程计(须自行融合IMU) | true | true | false | true | true
须自行积分,直接从0开始积分即可 |
2.4.2 外部二维码输入
方法:Get路径:/call?cmd=lesstag.inputextern(id,x,y,th) 返回:JSON
举例:
// id,x,y,th分别表示二维码的tag,xyth数值。
Get http://127.0.0.1:4321/call?cmd=lesstag.inputextern(id,x,y,th)
{
"result": true
}
说明:
- 配置此项功能需要把D参数中二维码配置useExtern改成true才可以生效