×
Namespaces

Variants
Actions

Lumia Sensor Core SDK

From Nokia Developer Wiki
Jump to: navigation, search
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Compatibility
Platform(s):
Windows Phone 8
Article
Created: ()
Last edited: Xinx Gong (27 Jun 2014)

Contents

Lumia Sensor Core SDK是什么

SensorCore SDK是一组API,它可以访问手机上的多种传感器数据(加速度传感器/数字罗盘/陀螺仪)和位置信息。这些信息可以用来追踪用户的身体和运动状态。一般情况下,传感器以较低的功耗在后台运行,并保存最近10天内的数据。用户总是可以禁用SensorCore SDK传感器和清除任何收集的数据。

Lumia SensorCore SDK beta

Step Counter API 统计用户步行和跑步的步数

Step Counter API提供的数据包括步数和用户持续步行或跑步的时间。API不仅提供当前步数,同时以每5分钟间隔提供了10天的历史记录。

在Step Counter开始计数前会有6到7秒的延时。在初始化延时过后,Step Counter数值几乎是实时更新的。引入延时是为了避免误报,7秒是出于对应用程序 UI响应的考虑。要指出的是,一旦计数开始,Step Counter不会遗漏初始化前的步数。即如果用户在Step Counter初始化完成前已经走了10步,在API开始提供数据时这10步也会被计入总步数,但是如果在6-7秒的阈值之前就停止计步,那这几步将不会被记录。

Step Counter的准确性的一些变化是来自于用户,设备是怎么被握住以及设备放在什么地方。在一些场景下是出现错误的计步,例如用户在骑车时把设备放在裤兜里,或者用户正在乘坐一辆强烈颠簸的汽车。

Activity Monitor 确定用户和手机的运动类型

Activity Monitor API提供的信息是关于用户在身体活动时的变化。例如:当用户开始或停止步行,或是保持静止。为了保证准确性,在检测Activity的变化时通常有几秒的延时。延时长短是根据Delta(时间和传感器数据)活动时的变化来定的。延时一般大概是5到10秒。Activity信息最精确时是当用户把设备放在口袋或者包里,此时的设备能紧密的遵循着用户的活动行为。另外也有一些对于Activity Monitor非常有难度用例,比如用户乘坐一辆强烈颠簸的车或者是用户用手拿着设备在摇晃。 Activities被分为下面几类:

o Idle (设备平放着) 
o Stationary (用户拿着手机但是用户没有动) 
o Moving
    • Pedestrian and bicycle
         • Walking
         • Running 

为了观察Activities变化,应用程序可以指定一组感兴趣的Activities。当Activity发生改变时,应用程序会接收到与指定Activity最为匹配和接近的Activity的一个通知。例如,如果一个程序对idle和moving Activity感兴趣,此时不论是在walking还是running,都只会收到moving的认知通知。

Place monitor 识别用户的家、工作和去过的地点

Place monitor API提供了用户停留超过一定时间段的地理位置信息,它运行在后台,为了使得功耗尽量低,主要利用手机基站和WiFi接入点信息来定位。因此,它不会主动激活GPS进行地理位置追踪,除非其他应用已经在使用GPS(如导航类应用)。由于该类API是被动工作的,因此它提供的地理位置信息并非是实时的。除了提供相关的地理位置信息以外,它还会尝试推断用户的家和工作单位的地理位置。 用户携带设备在某一个地点停留10分钟以上,该地点才会被认为是一个Known Places,同时加入到Known Places列表。一般来讲,单个Known Place的半径范围是200米。两个Known Place之间的距离一般要求500米以上,因此,即使500米范围内有两个不同的地理位置,该API会将这些位置融合为一个Known Place,这一点也是开发者需要考虑的。

Place monitor 为尝试分类place为“home”和“work”。判断“home”和“work”的规则如下:

• 设备在一定时间间隔内处于一个给定的Known Place内。
• 设备的移动范围和用户的活跃度
• 设备被使用的活跃度 
• 设备如何连接到充电器

根据用户行为,分类通常需要2-3天。应用应该注意,只能为这两个place提供逻辑分类标签,它们可能会也可能不会反应这些place的真实意义。例如,如果对学校的访问符合判断“work”的规则,place monitor 很可能会把学校检测为“work”。分类是非常好的尝试,在所有的设备使用场景里应该不会完全准确。“home”和“work”随着时间推移是会变化的。例如,如果设备持有者搬家了或是换工作了,place monitor 会重新检测,但是这个时间可能需要超过10天。

Place monitor 随着时间推移会调整Known Place列表。如果一个Known Place不再被访问,那么这个Known Place最终会从Known Place列表里消失。

Place的排序也会根据用户行为来调整。经常去的Known Place会在列表的上面,不经常去的Known Place则会在列表的下面。所有的新Known Place都会加在列表的顶部。这些调整的频度是由用户行为来决定的。

所有Place都有下面的属性:

ID:给出的位置的唯一ID
• Kind: frequent, home or work
• Position:place的地理位置。Position的准确性取决于环境和用户的使用因素。
• Radius:place的圆形区域的半径,单位是米。Radius的准确性取决于环境和用户的使用因素。


需要注意的是,places的检测取决于消费者如何使用设备以及环境因素,如基站的使用人数和Wi-Fi热点。在一些有大量基站和Wi-Fi热点的区域,如市中心,places的识别会更加准确。如果用户在用一些需要使用GPS的应用,例如导航应用,place monitor会在这种情况下利用从GPS过来的数据。在这些情况下,places数据会有更高的精准度。

Route Tracker 记录用户路线的位置点

Route tracker API 提供了用户的运动信息。它与place monitor很接近,但是它跟踪的是路线点(geo-location with heading)而不是像home或work那样的place。和place monitor一样, route tracker 也是被动的使用基站和Wi-Fi热点指出设备位置来工作。GPS信息只在有其他应用用着GPS时才被使用。另外,应用需要了解的是应用提供的线路点可能不完全准确。它更多的应该被看作是city tracker(可以提供city blocks级别的位置),而不是fitness tracker(可以提供几米级别的位置)。

跟踪点的注册最多间隔5分钟(API实现每隔5分钟记录路线点),并且距离上一个记录的路线点最少500米。例如,如果用户在一个给定的500米的区域内停留了很长时间,route tracker只会在这个区域记录一个路线点。当用户在高速公路上开车时,后续的跟踪点根据车速和基站的频率可以与其他点间隔数公里。

跟踪点的准确度取决于位置数据的频率和质量,也就是基站和Wi-Fi热点的存有数。例如,在公园里慢跑,在没有活跃的GPS会话并且手机始终只连接到同一个信号塔时就可能只记录到一个点。

API提供了下面参数:

Heading:用户在旅游时线路点被记录时的方向。这只在使用GPS时可用。这意味着这个参数在大部分情况下不可用。 
• LenghtOfStay:设备在这个点待的时间 。
• Position:线路点的地理位置。
• Radius:环绕位置的圆形区域的半径,反映的是地区的不精准性。不精准性取决于各种因素,如设备是怎么被使用的,以及如基站使用人数和Wi-Fi热点等环境因素。 
• Timestamp:进入地点的时间点。以5分钟为精度。

目前支持Sensor Core的设备

Lumia 1520, Lumia Icon, Lumia 930, Lumia 630 and 635

Windows Phone 8.1 with Cyan firmware

Cyan.png

如何启用设备的SensorCore 功能

为了使用SensorCore提供的API,我们需要在手机的功能中做一些设置,具体来说,是将定位运动数据功能打开。 Sensor Core Location.pngSensor Core Motion Data.png

Start Coding

开发环境

利用SensorCore进行应用开发,需要的开发环境为:Visual Studio 2013 Update 2 with Windows Phone SDK。SensorCore SDK 支持模拟器调试,但是支持的功能很有限。所以,如果实际开发应用的话,建议在支持Sensor Core并且解锁的开发设备上进行调试。

新建项目

首先,在Visual Studio中新建项目,选择 Installed > Templates > Visual C# > Store Apps > Windows Phone Apps > Blank App (Windows Phone) ,同时,将项目名称命名为HelloSensorCore

在项目中添加SensorCore SDK

选择Tools > NuGet Package Manager > Manage NuGet Packages for Solution,在nuget.org下搜索关键字Sensor Core,找到Lumia SensorCore SDK以及Lumia SensorCore SDK Testing Tools,然后点击安装。

Sensor Core Nuget.png

自动添加的引用 和 清单文件(Package.appxmanifest)自动添加的能力

安装完SDK后,工程会自动添加Lumia.Sense, Lumia.Sense.TestingMicrosoft Visual C++ 2013 Runtime Package for Windows Phone 这三个引用。同时也会在Package.appxmanifest文件中添加下面的能力:

 <DeviceCapability Name="location" /> 
<m2:DeviceCapability Name="humaninterfacedevice">
<m2:Device Id="vidpid:0421 0716">
<m2:Function Type="usage:ffaa 0001" />
<m2:Function Type="usage:ffee 0001" />
<m2:Function Type="usage:ffee 0002" />
<m2:Function Type="usage:ffee 0003" />
<m2:Function Type="usage:ffee 0004" />
</m2:Device>
</m2:DeviceCapability>

另外,为了使得程序能够正确的运行,我们需要对Configuration Manager中的目标平台进行配置。如果我们在实际设备中进行测试,那么必须选择ARM;如果在模拟器中进行测试,那么必须选择x86。

Sensor Core Remove Any CPU.png

在代码中使用SensorCore API

在MainPage.xaml的Grid元素中添加一个ListBox,用于显示SensorCore返回的数据。

<Grid> 
<ListBox x:Name="SensorcoreList"/>
</Grid>

在MainPage.xaml.cs中,加入命名空间的引用:

using Windows.UI.Popups; 
using Lumia.Sense;
using Lumia.Sense.Testing;
using System.Threading.Tasks;

在MainPage类中添加以下私有变量:

private PlaceMonitor _placeMonitor; 
private RouteTracker _routeTracker;
private ActivityMonitor _activityMonitor;
private StepCounter _stepCounter;

在MainPage的构造函数中添加Loaded事件处理代码,并根据应用的visibility来处理SensorCore的Activation和Deactivation:

this.Loaded += async (oo, ee) => 
{
await ShowStepCounter();
await ShowActivityMonitor();
await ShowRouteTracker();
await ShowPlacesMonitor();
};
 
Window.Current.VisibilityChanged += async (oo, ee) =>
{
if (!ee.Visible)
{
if (_placeMonitor != null) await CallSenseApiAsync(async () => await _placeMonitor.DeactivateAsync());
if (_routeTracker != null) await CallSenseApiAsync(async () => await _routeTracker.DeactivateAsync());
if (_activityMonitor != null) await CallSenseApiAsync(async () => await _activityMonitor.DeactivateAsync());
if (_stepCounter != null) await CallSenseApiAsync(async () => await _stepCounter.DeactivateAsync());
}
else
{
if (_placeMonitor != null) await CallSenseApiAsync(async () => await _placeMonitor.ActivateAsync());
if (_routeTracker != null) await CallSenseApiAsync(async () => await _routeTracker.ActivateAsync());
if (_activityMonitor != null) await CallSenseApiAsync(async () => await _activityMonitor.ActivateAsync());
if (_stepCounter != null) await CallSenseApiAsync(async () => await _stepCounter.ActivateAsync());
}
};

定义两个方法来检查设备是否支持SensorCore SDK,并且检查Location和motion data是否已经打开。通常来讲,用户默认会关闭这两个选项,所以我们需要为用户提供快速设置的方法。

private async Task<bool> CallSenseApiAsync(Func<Task> action) 
{
Exception failure = null;
try
{
await action();
}
catch (Exception e)
{
failure = e;
}
if (failure != null)
{
switch (SenseHelper.GetSenseError(failure.HResult))
{
case SenseError.LocationDisabled:
await CreateMessageDialog("Location has been disabled. Do you want to open Location settings now?", "Information", "Yes", async cmd => await SenseHelper.LaunchLocationSettingsAsync(), true);
return false;
case SenseError.SenseDisabled:
await CreateMessageDialog("Motion data has been disabled. Do you want to open Motion data settings now?", "Information", "Yes", async cmd => await SenseHelper.LaunchSenseSettingsAsync(), true);
return false;
default:
await CreateMessageDialog(SenseHelper.GetSenseError(failure.HResult).ToString(), "Failure", "OK", null, false);
return false;
}
}
return true;
}
 
private static async Task CreateMessageDialog(string message, string title, string label, UICommandInvokedHandler command, bool no)
{
var dialog = new MessageDialog(message, title);
dialog.Commands.Add(new UICommand(label,command));
if (no) dialog.Commands.Add(new UICommand("No"));
await dialog.ShowAsync();
}

开始使用StepCounter。 CallSenseApiAsync封装了安全访问SensorCore SDK的方法。在这个方法里面,我们先实例化一个StepCounter对象,并且调用StepCounter.IsSupportedAsync()来确认当前设备是否支持StepCounter。然后就可以获取当前StepCounter相关的数据,并且显示在主页面的Listbox中。

 private async Task ShowStepCounter()
{
await CallSenseApiAsync(async () =>
{
if (_stepCounter == null)
{
_stepCounter = await StepCounter.GetDefaultAsync();
}
if (await StepCounter.IsSupportedAsync())
{
var reading = await _stepCounter.GetCurrentReadingAsync();
SensorcoreList.Items.Add("Current step counter reading");
if (reading != null)
{
SensorcoreList.Items.Add(reading.Timestamp.ToString());
SensorcoreList.Items.Add("Walk steps = " + reading.WalkingStepCount);
SensorcoreList.Items.Add("Walk time = " + reading.WalkTime.ToString());
SensorcoreList.Items.Add("Run steps = " + reading.RunningStepCount);
SensorcoreList.Items.Add("Run time = " + reading.RunTime.ToString());
}
else
{
SensorcoreList.Items.Add("data not available");
}
}
});
}

使用ActivityMonitor

 private async Task ShowActivityMonitor()
{
await CallSenseApiAsync(async () =>
{
if (_activityMonitor == null)
{
_activityMonitor = await ActivityMonitor.GetDefaultAsync();
}
if (await ActivityMonitor.IsSupportedAsync())
{
var reading = await _activityMonitor.GetCurrentReadingAsync();
SensorcoreList.Items.Add("Current activity");
 
if (reading != null)
{
SensorcoreList.Items.Add(reading.Timestamp.ToString() + ", activity = " + reading.Mode);
}
else
{
SensorcoreList.Items.Add("not available");
}
}
});
}

使用PlacesMonitor

 private async Task ShowPlacesMonitor()
{
await CallSenseApiAsync(async () =>
{
if (_placeMonitor == null)
{
_placeMonitor = await PlaceMonitor.GetDefaultAsync();
}
 
if (await PlaceMonitor.IsSupportedAsync())
{
Place reading = await _placeMonitor.GetCurrentPlaceAsync();
SensorcoreList.Items.Add("Current place");
 
if (reading != null)
{
SensorcoreList.Items.Add(“place kind = " + reading.Kind);
}
else
{
SensorcoreList.Items.Add("
not available");
}
}
});
}

使用RouteTracker

 private async Task ShowRouteTracker()
{
await CallSenseApiAsync(async () =>
{
if (_routeTracker == null)
{
_routeTracker = await RouteTracker.GetDefaultAsync();
}
 
if (await RouteTracker.IsSupportedAsync())
{
IList<RoutePoint> reading = await _routeTracker.GetRouteAsync(
DateTime.Now.AddDays(-2), TimeSpan.FromDays(2));
SensorcoreList.Items.Add("Route history");
 
if (reading != null)
{
SensorcoreList.Items.Add("count = " + reading.Count);
 
foreach (RoutePoint route in reading)
{
SensorcoreList.Items.Add(
route.Position.Latitude + ", " +
route.Position.Longitude);
}
}
else
{
SensorcoreList.Items.Add("not available");
}
}
});
}

编译并部署应用

Sensor Core Deploy.png

记录和模拟传感器

记录

 StepCounter stepCounter = await StepCounter.GetDefaultAsync();
SenseRecorder recorder = new SenseRecorder(stepCounter);
await recorder.StartAsync();
/// ... Record data ...
await recorder.StopAsync();
await recorder.GetRecording().SaveAsync();

模拟

 SenseRecording recording = await SenseRecording.LoadFromFileAsync("jsonData.txt");
StepCounterSimulator simulator = await StepCounterSimulator.GetDefaultAsync(recording);
 
StepCounterSimulator simulator = await StepCounterSimulator.GetDefaultAsync(
recording, DateTime.Now - TimeSpan.FromDays(2));

开发时的建议

• 用户可以很方便的启用/禁用定位服务和运动数据。
• 不是所有的设备都支持运动数据。
• 运动数据只有在启用系统设置的运动数据之后才开始收集。
• 运动数据可以被用户清空。
• 记住Place monitor 和 Route tracker是被动收集数据的。
• 注意数据收集的延迟。
• 注意Step Counter历史数据的间隔时间。
• 注意Step Counter数据是绝对的。
• 尽量减少后台线程的使用。
• 注意系统时钟的变化。
This page was last modified on 27 June 2014, at 10:57.
77 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×