概要
SLAM技术
SLAM(Simultaneous Localization and Mapping),同步定位与地图构建,最早在机器人领域提出,它指的是:机器人从未知
环境的未知地点出发,在运动过程中通过重复观测到的环境特征定位自身位置和姿态,再根据自身位置构建周围环境的增量式
地图,从而达到同时定位和地图构建的目的。
空间识别技术
空间识别技术是包含回环检测和地图优化的SLAM模式,建议在要求高精度定位的使用场景中使用空间识别技术模式
建图步骤
要建立一个好的地图,你必须首先考虑如何使用地图。地图必须包含应用程序所需的视点。如果最终应用程序在另一个房间,则没有理由在当前房间中记录地图。类似地,如果最终应用程序将显示地面上的一些虚拟对象,则没有理由将地图记录到使用摄像头向上看的房间中。应用程序要移动的路径应该是记录地图的最终路径。
为了保证一个好的循环闭合,在同一条路径上走两次:例如,从一个起点开始,走开,回到起点,然后再次在同一条路径上走开,然后回到起点结束。在记录过程中,在同一
条路径上行走两次,可以保证在循环闭合检测的不同记录视点之间有很好的重叠。在做这个地图记录时,重要的是避免快速移动或面对没有特征的区域。
开发教程
场景识别Demo CslamDemo.unity
操作界面功能:
保存地图:调用MR眼镜接口生成slam地图
/// <summary>
/// 保存地图接口
/// </summary>
/// <param name="mapStream"></param> 保存地图到本地设备的存储地址
/// <param name="cslamSavedCallback"></param> 保存地图成功后的回调函数
/// <param name="cslamLocalizedCallBack"></param> 获取地图匹配度的回调函数
/// <returns></returns>
cslamName = "map.bin";
API.xslam_save_map_and_switch_to_cslam(Application.persistentDataPath + "/" + cslamName, OnCslamSaved, OnSaveLocalized);
//函数回调 OnCslamSaved
/// <summary>
/// 保存地图的回调实现
/// </summary>
/// <param name="status_of_saved_map">是否成功保存地图</param>
/// <param name="map_quality">地图品质</param>
[MonoPInvokeCallback(typeof(API.detectCslamSaved_callback))]
static void OnCslamSaved(int status_of_saved_map, int map_quality)
{
status_of_saved_mapq = status_of_saved_map;
save_map_qualityq = map_quality;
}
//函数回调 OnSaveLocalized
/// <summary>
/// 保存地图匹配度的回调实现
/// </summary>
/// <param name="percentc">实时返回的地图识别匹配度</param>
[MonoPInvokeCallback(typeof(API.detectLocalized_callback))]
static void OnSaveLocalized(float percentc)
{
percentcD = percentc;
}
保存位置
//调用函数保存文件
WriteText(Application.persistentDataPath,"cube.txt", getMapAllCubeInfo())
/// <summary>
/// 文件写入保存到box上
/// </summary>
/// <param name="file_path">文件路径</param>
/// <param name="file_name">文件名</param>
/// <param name="str_info">内容</param>
public void WriteText(string file_path, string file_name, string str_info)
{
Debug.LogError(file_path + "//" + file_name);
StreamWriter sw;
FileInfo file_info = new FileInfo(file_path + "//" + file_name);
if (!file_info.Exists)
{
sw = file_info.CreateText();
}
else
{
sw = file_info.CreateText();
}
sw.Write(str_info);
sw.Close();
sw.Dispose();
}
加载地图
cslamName = "map.bin";
/// <summary>
/// 加载地图接口
/// </summary>
/// <param name="mapStream"></param> 加载地图的路径地址
/// <param name="cslamSwitchedCallback"></param> 加载地图的地图地址路径
/// <param name="cslamLocalizedCallBack"></param> 获取地图匹配度的回调函数
API.xslam_load_map_and_switch_to_cslam(Application.persistentDataPath + "/" + cslamName, OnCslamSwitched, OnLoadLocalized);
/// <summary>
/// 加载地图的回调函数实现
/// </summary>
/// <param name="map_quality"></param>
[MonoPInvokeCallback(typeof(API.detectSwitched_callback))]
static void OnCslamSwitched(int map_quality)
{
switch_map_quality = map_quality;
}
/// <summary>
/// 保存地图匹配度的回调实现
/// </summary>
/// <param name="percentc"></param>
[MonoPInvokeCallback(typeof(API.detectLocalized_callback))]
static void OnSaveLocalized(float percentc)
{
percentcD = percentc;
}
加载位置
/// 加载位置
showSaveGroup();
/// <summary>
/// 加载位置
/// </summary>
private void showSaveGroup()
{
string data = GetText(Application.persistentDataPath, "cube.txt");
infoTxt.text = data;
if (data != "")
{
JsonData jd = JsonMapper.ToObject(data);
List<MapContentVO> mapContentList = new List<MapContentVO>();
for (int i = 0; i < jd.Count; i++)
{
Vector3 v_t = new Vector3(float.Parse(jd[i]["t_x"].ToString()), float.Parse(jd[i]["t_y"].ToString()), float.Parse(jd[i]["t_z"].ToString()));
Vector3 v_r = new Vector3(float.Parse(jd[i]["r_x"].ToString()), float.Parse(jd[i]["r_y"].ToString()), float.Parse(jd[i]["r_z"].ToString()));
addCube(jd[i]["o_name"].ToString(), v_t, v_r);
}
}
}
保存的地图文件和位置文件位置可以在如下路径找到
操作视频
第一次打开APP做建图和位置保存操作
20240913_103646
第二次打开APP做加载地图和位置加载操作
20240913_103812