这两年虚拟现实VR和增强现实AR简直火的不要不要的,众多巨头都在发力,Google也推出了自己的AR技术解决方案,因为目前介绍Tango的中文资料还比较少,所以本人结合官网文档和自己的理解写了本文,如有错漏请不吝赐教。
一、简介
1. Tango是什么,可以用来干什么?
Tango是Google的一个AR增强现实项目,配合其独特的移动设备和SDK可以方便的在应用中使用AR技术。
2. Tango室内定位为什么有很高的精确度?
众所周知,传统的定位技术(GPS\WIFI等)在室内定位上精度很低,那么Tango是怎么实现室内定位的呢?
Tango采用的是“参照定位”,即相对于“初始位置”的一种定位方式,不涉及到卫星定位。它根据硬件设备的传感器,比如重力传感器、IMU陀螺仪等,获取移动设备相对于初始位置的“位移”和“旋转角度”,自己构建了一个“参照坐标系”,因此有较高的准确度。
当然,还有其他一些软件技术手段,比如通过区域学习修正偏差等。
3. 几个重要的概念
Tango中如下3个概念,其实也算是3个功能模块。开发者通过设置TangoConfig对象的相应字段来选择开启哪些功能。
a. 移动追踪(motion tracking)
移动追踪指的是,Tango会记录追踪移动设备的在3D空间中的位置,位置数据包括地点和超像旋转角度等、实时报告给应用。
b. 区域学习(Area Leaning)
移动追踪只会反馈移动设备当前的坐标信息、对于设备“看”到的东西没有任何记忆,区域学习使移动设备能够看到和记住物理空间的关键视觉特征,比如边缘,角落等。
区域学习会把看到的保存起来,下次再次“看”到的时候会进行匹配,利用这些数据修正误差(漂移修正),使得轨迹追踪、定位更加准确。
c. 深度感知(Depth Perception)
深度感知给予设备“明白”物体之间的距离,这是通过独特的硬件设备技术实现的,比如“结构光”、“光速飞行时间TOF”和Stereo立体测量
4. Tango的简单使用方式
在Android中,Tango是一个后台Sevice,负责AR工作。我们使用Tango的方式就是启动这个Service,与其进行交互。
Tango主要有如下两个对象:
private Tango mTango; //Tnago对象
private TangoConfig mConfig; //配置
按照需求对TangoConfig类进行配置,下面代码配置了移动追踪和自动恢复
private TangoConfig setupTangoConfig(Tango tango) {
TangoConfig config = tango.getConfig(TangoConfig.CONFIG_TYPE_DEFAULT);
//开启移动追踪功能
config.putBoolean(TangoConfig.KEY_BOOLEAN_MOTIONTRACKING, true);
// 自动恢复
config.putBoolean(TangoConfig.KEY_BOOLEAN_AUTORECOVERY, true);
return config;
}
初始化Tango,调用它的connect()方法。
@Override
protected void onResume() {
super.onResume();
mTango = new Tango(HelloMotionTrackingActivity.this, new Runnable() {
@Override
public void run() {
synchronized (HelloMotionTrackingActivity.this) {
mConfig = setupTangoConfig(mTango);
mTango.connect(mConfig);
startupTango(); //处理数据
}
}
});
}
通过回调处理数据,上一步中处理数据的方法是startupTango(),其源码如下
private void startupTango() {
//设置坐标参照系
final ArrayList<TangoCoordinateFramePair> framePairs =
new ArrayList<TangoCoordinateFramePair>();
framePairs.add(new TangoCoordinateFramePair(
TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE,
TangoPoseData.COORDINATE_FRAME_DEVICE));
// 通过回调获取和处理坐标数据
mTango.connectListener(framePairs, new OnTangoUpdateListener() {
@Override
public void onPoseAvailable(final TangoPoseData pose) {
//在这里写处理移动追踪和区域学习数据的代码
}
@Override
public void onXyzIjAvailable(TangoXyzIjData xyzIj) {
// We are not using onXyzIjAvailable for this app.
}
@Override
public void onPointCloudAvailable(TangoPointCloudData pointCloud) {
// 如果开启深度感知,则在这里处理点阵信息
}
@Override
public void onTangoEvent(final TangoEvent event) {
//在这里处理各种事件,比如鱼眼摄像头出问题,pose数据失效事件等
}
@Override
public void onFrameAvailable(int cameraId) {
// We are not using onFrameAvailable for this application.
}
});
}
应用不在前台的时候,断开和Tango的连接(官网推荐的用法)
@Override
protected void onPause() {
super.onPause();
synchronized (this) {
mTango.disconnect();
}
}
二、开发者必备
1. 学习资料
- 官网:https://developers.google.com/tango/
- 开发者社区:https://plus.google.com/communities/114537896428695886568
- 官网的demo:https://github.com/googlesamples/tango-examples-java
- sdk源码:官方demo中有个jar包,名字是tango_java_lib.jar
- 官网API:https://developers.google.com/tango/apis/overview
2. 开发方式
开发方式 | 软件需求 | 设备 |
---|---|---|
Java Android | Android Studio、 TangoReleaseLibs(Tango SDK) | Tango Device |
Unity Android | Unity 5.2.1以上(配置好Android开发环境)、Tango Unity SDK | Tango Device |
注:Android API版本 只支持 API Level 17 及以上,Tango Device是必须的,没有其独特的感应设备,Tango没办法正常工作。
三、移动追踪(motion tracking)
1. Tango的坐标数据——pose
pose是Tango中的坐标表示,其具体的Java对象是TangoPoseData,其包含了两个信息:三维坐标、物体的朝向,其结构如下:
struct PoseData {
double orientation[4]; //朝向信息,四元数表示
double translation[3]; //三维坐标信息
}
三维坐标系可以用下图表示,当我们正常站立手持移动设备面向自己的脸部时,X轴的正方向是向右的。
朝向信息,也可以说成旋转信息,如下图理解,三个方向上的旋转,用四元数表示(这个我不太懂,三个旋转用四元数表示好像是为了方便计算,具体请百度)。
2. pose的生命周期
pose数据是有可能失效的,比如鱼眼摄像头发生了错误导致出错等。下图 是pose数据的状态转换图。
3. 应用获取和处理pose数据
private void startupTango() {
// 设置坐标参照系
final ArrayList<TangoCoordinateFramePair> framePairs =
new ArrayList<TangoCoordinateFramePair>();
framePairs.add(new TangoCoordinateFramePair(
TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE,
TangoPoseData.COORDINATE_FRAME_DEVICE));
// 在回调中获取坐标信息
mTango.connectListener(framePairs, new OnTangoUpdateListener() {
@Override
public void onPoseAvailable(final TangoPoseData pose) {
logPose(pose);
}
});
}
/**
* 打印坐标信息
*/
private void logPose(TangoPoseData pose) {
StringBuilder stringBuilder = new StringBuilder();
float translation[] = pose.getTranslationAsFloats();
stringBuilder.append("Position: " +
translation[0] + ", " + translation[1] + ", " + translation[2]);
float orientation[] = pose.getRotationAsFloats();
stringBuilder.append(". Orientation: " +
orientation[0] + ", " + orientation[1] + ", " +
orientation[2] + ", " + orientation[3]);
Log.i(TAG, stringBuilder.toString());
}
四、区域学习(Area Leaning)
1. ADF文件
区域学习将设备“看到的信息”保存成ADF(Area Description File)文件,采用UUID进行唯一标识。ADF文件算是一种持久化的数据,可以重复利用。
ADF文件实际上是一种键值对的文件形式,它其中保存了区域学习记录的信息,但是这些空间信息不需要也不允许开发者进行修改,其他官网公开的属性有如下几个:
键值 | 解释 |
---|---|
KEY_UUID | UUID唯一标识 |
KEY_NAME | 文件的name |
KEY_TRANSFORMATION | ADF到全局坐标的一个转换 (x, y, z, qx, qy, qz, qw) |
KEY_DATE_MS_SINCE_EPOCH | ADF文件保存的时间 |
此外,我们也可以加入一些自己定义的键值对信息。
2. 区域重定位(区域匹配)
如果载入使用以前的ADF文件,要实现正常的功能,必须进行一个重定位过程,用户要手持设备走到现实中与载入的ADF匹配的地域,tango会将环境信息和ADF文件信息做匹配,匹配成功了即意味着“重定位”成功。
区域匹配是有可能失败的,Tango的区域匹配成功率与环境的“多样性”有关,如果环境很空旷,或者各个房间都是一模一样的,那么区域学习和匹配陈功率较低。如果环境中有各式各样的物品,那么成功率较高。
3. 加载和使用ADF文件示例
开启区域学习
TangoConfig mConfig = mTango.getConfig(TangoConfig.CONFIG_TYPE_CURRENT);
mConfig.putBoolean(TangoConfig.KEY_BOOLEAN_LEARNINGMODE, true);
加载特定UUID标识的ADF文件
mConfig.putString(TangoConfig.KEY_STRING_AREADESCRIPTION, uuid);
获取最近所有的ADF文件
ArrayList<String> fullUUIDList = new ArrayList<String>();
fullUUIDList = mTango.listAreaDescriptions();
保存当前的ADF文件,这个可能很耗时,不要在UI线程做(官方提供了SaveAdfTask来做这件事)。
Tango.saveAreaDescription()
在回调中处理区域学习的位置数据,因为文章开头有讲述,其他步骤省略了。
@Override
public void onPoseAvailable(TangoPoseData pose) {
if (pose.baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION
&& pose.targetFrame == TangoPoseData.COORDINATE_FRAME_DEVICE) {
// 这个条件意味着移动设备到了一个新的位置
}
else if (pose.baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION
&& pose.targetFrame == TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE) {
// 这个条件告诉我们,设备回到了ADF文件区域的开始位置,也意味着重定位过程成功。
//开发者可以视其为重定位成功的信号
}
五、深度感知(Depth Perception)
深度感知目前为平衡对设备和处理器的要求,理想的扫描距离为0.5米到4米之间,近距离物品扫描和手势检测并不完美。对于采用红外光技术的深度感知设备,在如下两种情况有可能工作不正常:
- 环境中红外光在光源中占据较高比例,比如阳光和白炽灯照射的区域
- 不反射红外光的物品难以被正常扫描
深度感知的工作原理就是扫描摄像头照射的区域,对照射到的物品计算其空间位置,给出一大堆三维点阵的信息(point cloud)
深度感知仍旧在回调里面编写获取数据的方法,回调中不能做耗时操作,如果上次回调没有完成,因为你无法获取最新的数据。
@Override
public void onPointCloudAvailable(final TangoPointCloudData pointCloudData) {
//在这里处理点阵数据
}
六、 总结
1. Tango功能总结
功能 | 数据表示 | 对应的数据类 | 用途 |
---|---|---|---|
移动追踪 | 三维坐标信息和物体的朝向信息 | TangoPoseData | 检测移动设备的位置和朝向 |
区域学习 | ADF文件 | TangoAreaDescriptionMetaData | 提高移动追踪的准确度、记忆空间信息(做室内导航) |
深度学习 | 点阵信息(一大堆三维坐标集合) | TangoPointCloudData | 扫描建模 |