- PVSM.RU - https://www.pvsm.ru -

Продолжаем исследовать возможности Sphero [1] и его SDK [2].
На повестке дня управление роботом с помощью акселерометра планшета и распознавание столкновения с препятствием.
В прошлой статье [3] мы уже рассматривали кто такой Sphero [1] и как начать управлять им программно на Windows 8.1 используя Visual Studio 2013 [4].
Теперь мы займемся более сложными вещами. Научимся «рулить» роботом наклоняя планшет в разные стороны и определять столкновение с препятствием. Для этого мы будем использовать акселерометр моего планшета и датчик столкновения робота с внешним миром.
Операционная система Windows 8.1 и объектная модель WinRT поддерживают работу со следующими сенсорами, если, конечно, они есть у устройства:
Акселерометр – это модуль, измеряющий движение в трех направлениях. Этим модулем обустроены многие современные устройства. Чтобы получить доступ к данным акселерометра, необходимо обратиться к объекту Accelerometer [5], который предоставляет доступ к объекту AccelerometerReading [6] со следующими свойствами:
Мы подпишемся на событие изменения показаний акселерометра и будем передвигать робота, ускоряя, замедляя или разворачивая его в зависимости от показаний.

Подписаться на событие изменения показаний акселерометра можно так.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
…
Accelerometer _accelerometer = Accelerometer.GetDefault();
_accelerometer.ReadingChanged += new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged);
…
}
async private void ReadingChanged(object sender, AccelerometerReadingChangedEventArgs e)
{
…
}
Предположим, мы получили данные акселерометра с планшета. Теперь надо их использовать для перемещения Sphero в пространстве.
В Sphero SDK для Windows 8.1 есть метод Roll, котoрый занимается перемещением Sphero и принимает два параметра:

По умолчанию, Sphero начинает свою работу с показателей x = 0, y = 0, heading = 0, speed = 0.
Sphero поддерживает такую забавную вещь, как датчик столкновения (Collision Detection [7]). Он работает весьма примитивно [7], на разнице координат.
В Sphero SDK для Windows 8.1 уже есть готовое событие CollisionDetectedEvent, на которое вы можете подписаться и отлавливать столкновения с объектами реального мира.
private void OnRobotConnected(object sender, Robot robot)
{
…
robot.CollisionControl.StartDetectionForWallCollisions();
robot.CollisionControl.CollisionDetectedEvent += OnCollisionDetectedEvent;
…
}
Событие будет срабатывать, если вы предварительно не забудете включить датчик столкновений:
robot.CollisionControl.StartDetectionForWallCollisions();
Когда датчик вам перестанет быть нужен – выключите его:
robot.CollisionControl.StopDetection();
Для работы с роботом, нам так же понадобятся следующие методы Sphero SDK для Windows 8.1:
SetBackLED(intensity) – включить подсветку задней части робота, чтобы можно было понимать куда он поедет. Значения:
1.0f – включает на полную мощность.
0.0f — отключает.
SetHeading(heading) – повернуть робота. Принимает значения от 0 до 359.
SetRGBLED(red, green, blue) – установить цвет шара.
Roll(heading, speed) – задать направление движения и скорость движения:
heading – угол перемещения. Принимает значения в диапазоне от 0 до 359.
speed – скорость перемещения. 0 – не двигается. 255 – максимальная скорость.
Sleep() – усыпить робота.
Передвигать робота используя акселерометр. При столкновении с препятствием – красить робота красным.
1. Открываем Visual Studio 2013 и создаём проект File / New / Project / Blank App.

2. Подключаем сборку RobotKit.dll из Sphero SDK [2] для Windows 8.1

3. Добавляем поддержку Bluetooth RFCOMM для приложения. Открываем Package.appxmanifest в режиме правки кода и добавляем в секцию Capabilities следующий код.
<wb:DeviceCapability Name="bluetooth.rfcomm"> <wb:Device Id="any"> <wb:Function Type="serviceId:00001101-0000-1000-8000-00805F9B34FB" /> </wb:Device> </wb:DeviceCapability>
4. На основной экран приложения кладем:
Откроем файл MainPage.xaml и добавим туда всё это.
<Page
x:Class="SpheroRace.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SpheroRace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" >
<Grid Margin="100" >
<Grid.RowDefinitions >
<RowDefinition Height="60"/>
<RowDefinition Height="60"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="SpheroName" Grid.Row="0" Grid.Column="0" Text="No Sphero Connected" FontSize="24"/>
<ToggleSwitch x:Name="ConnectionToggle" Grid.Row="1" Grid.Column="0" Toggled="ConnectionToggle_Toggled" />
<Button Name="StartBtn" Click="StartBtn_Click" Grid.Row="2" Grid.Column="0" Content="Start" VerticalAlignment="Bottom" HorizontalAlignment="Left" Padding="100" ></Button>
<Button Name="StopBtn" Click="StopBtn_Click" Grid.Row="2" Grid.Column="1" Content="Stop" VerticalAlignment="Bottom" HorizontalAlignment="Right" Padding="100" IsEnabled="False" ></Button>
</Grid>
</Page>
5. Перейдем в MainPage.xaml.cs и опишем логику игры. Для общения со Sphero используем объектную модель, предоставленную SDK.
public sealed partial class MainPage : Page
{
private Sphero m_robot = null;
private long m_lastTimeMs;
private double m_currentX = 0;
private double m_currentY = 0;
private bool m_isStarted = false;
private const string c_noSpheroConnected = "No Sphero Connected";
private const string c_connectingToSphero = "Connecting to {0}";
private const string c_spheroConnected = "Connected to {0}";
public MainPage()
{
this.InitializeComponent();
}
//Начало работы. Переход на основной экран
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
SetupRobotConnection();
Application app = Application.Current;
app.Suspending += OnSuspending;
Accelerometer _accelerometer = Accelerometer.GetDefault();
_accelerometer.ReadingChanged += new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged);
}
//Завершение работы. Переход с основного экрана
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
ShutdownRobotConnection();
Application app = Application.Current;
app.Suspending -= OnSuspending;
Accelerometer _accelerometer = Accelerometer.GetDefault();
_accelerometer.ReadingChanged -= new TypedEventHandler<Accelerometer, AccelerometerReadingChangedEventArgs>(ReadingChanged);
}
//handle the application entering the background
private void OnSuspending(object sender, SuspendingEventArgs args)
{
ShutdownRobotConnection();
}
//Ищем робота и подключаемся к нему
private void SetupRobotConnection()
{
SpheroName.Text = c_noSpheroConnected;
RobotProvider provider = RobotProvider.GetSharedProvider();
provider.DiscoveredRobotEvent += OnRobotDiscovered;
provider.NoRobotsEvent += OnNoRobotsEvent;
provider.ConnectedRobotEvent += OnRobotConnected;
provider.FindRobots();
}
//Завершаем работу с роботом
private void ShutdownRobotConnection()
{
if (m_robot != null && m_robot.ConnectionState == ConnectionState.Connected)
{
m_robot.SensorControl.StopAll();
m_robot.CollisionControl.StopDetection();
m_robot.Sleep();
m_robot.Disconnect();
ConnectionToggle.OffContent = "Disconnected";
SpheroName.Text = c_noSpheroConnected;
SetRedColor();
RobotProvider provider = RobotProvider.GetSharedProvider();
provider.DiscoveredRobotEvent -= OnRobotDiscovered;
provider.NoRobotsEvent -= OnNoRobotsEvent;
provider.ConnectedRobotEvent -= OnRobotConnected;
}
}
//Робот найден!
private void OnRobotDiscovered(object sender, Robot robot)
{
if (m_robot == null)
{
RobotProvider provider = RobotProvider.GetSharedProvider();
provider.ConnectRobot(robot);
ConnectionToggle.OnContent = "Connecting...";
m_robot = (Sphero)robot;
SpheroName.Text = string.Format(c_connectingToSphero, robot.BluetoothName);
}
}
//Робот не найден :(
private void OnNoRobotsEvent(object sender, EventArgs e)
{
MessageDialog dialog = new MessageDialog(c_noSpheroConnected);
dialog.DefaultCommandIndex = 0;
dialog.CancelCommandIndex = 1;
dialog.ShowAsync();
}
//Робот готов исполнять команды
private void OnRobotConnected(object sender, Robot robot)
{
ConnectionToggle.IsOn = true;
ConnectionToggle.OnContent = "Connected";
SpheroName.Text = string.Format(c_spheroConnected, robot.BluetoothName);
if (m_robot != null && m_robot.ConnectionState == ConnectionState.Connected)
{
m_robot.CollisionControl.StartDetectionForWallCollisions();
m_robot.CollisionControl.CollisionDetectedEvent += OnCollisionDetectedEvent;
SetRedColor();
}
}
//Событие изменения показаний акселерометра
async private void ReadingChanged(object sender, AccelerometerReadingChangedEventArgs e)
{
if (!m_isStarted)
return;
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Windows.Devices.Sensors.AccelerometerReading reading = e.Reading;
SendRollCommand(reading.AccelerationX, reading.AccelerationY, reading.AccelerationZ);
});
}
//Событие столкновения с препятствием
private void OnCollisionDetectedEvent(object sender, RobotKit.CollisionData data)
{
SetRedColor();
m_robot.Roll(0, 0);
}
//Кнопка для отключения робота
private void ConnectionToggle_Toggled(object sender, RoutedEventArgs e)
{
ConnectionToggle.OnContent = "Connecting...";
if (ConnectionToggle.IsOn)
{
if (m_robot == null || m_robot.ConnectionState != ConnectionState.Connected)
{
SetupRobotConnection();
}
}
else
{
ShutdownRobotConnection();
}
}
//Запустить робота
private void StartBtn_Click(object sender, RoutedEventArgs e)
{
m_isStarted = true;
StartBtn.IsEnabled = false;
StopBtn.IsEnabled = true;
SetGreenColor();
m_robot.Roll(0, 0);
}
//Остановить робота
private void StopBtn_Click(object sender, RoutedEventArgs e)
{
m_isStarted = false;
StartBtn.IsEnabled = true;
StopBtn.IsEnabled = false;
SetRedColor();
m_robot.Roll(0, 0);
}
//Начальное состояние робота. Он зеленый и неподвижно стоит
private void SetGreenColor()
{
m_robot.SetHeading(0);
m_robot.SetBackLED(1.0f);
m_robot.SetRGBLED(0, 255, 0);
}
//Состояние остановки или столкновения в препятствием
private void SetRedColor()
{
m_robot.SetHeading(0);
m_robot.SetBackLED(1.0f);
m_robot.SetRGBLED(255, 0, 0);
}
//Логика движения робота при изменении показаний акселерометра
private async void SendRollCommand(double newX, double newY, double newZ)
{
float x = (float)newX;
float y = (float)newY;
float z = (float)newZ;
float speed = Math.Abs(z);
speed = (speed == 0) ? 0 : (float)Math.Sqrt(speed);
if (speed > 1f)
speed = 0.01f;
int heading = Convert.ToInt32(Math.PI / 2.0 - Math.Atan2((double)y - m_currentY, (double)x - m_currentX));
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
if ((milliseconds - m_lastTimeMs) > 1000)
{
SetGreenColor();
m_robot.Roll(heading, speed);
m_lastTimeMs = milliseconds;
m_currentX = x;
m_currentY = y;
}
}
}
6. Подключаемся к Sphero по Bluetooth

7. Запускаем приложение.

8. Нажимаем на кнопку Start и проверяем игру на деле.
У нас получилась простая игрушка. Её можно применять, устраивая многопользовательские гонки роботов, или для игры с домашним животным.
Результат работы можно посмотреть на видео.
Исходники доступны тут: github.com/MissUFO/SpheroRace [9]
Программируем роботов на Windows 8. Магический шар Sphero [10]
Официальный сайт Sphero [1]
Центр разработчика Sphero [11]
Sphero SDK для Windows 8.1 [2]
Пример использования Sphero SDK для Windows 8.1 [12]
Пример использования акселерометра в Windows 8.1 [13]
Канал разработчиков Sphero на youtube [14]
Скачать Visual Studio 2013 [4]
Подробнее о Visual Studio Online [15]
Зарегистрироваться на Visual Studio Online [16]
Автор: MissUFO
Источник [17]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/windows/56505
Ссылки в тексте:
[1] Sphero: http://www.gosphero.com/
[2] SDK: https://github.com/orbotix/Sphero-Win-SDK
[3] прошлой статье: http://habrahabr.ru/company/microsoft/blog/213797/
[4] Visual Studio 2013: http://www.visualstudio.com/downloads/download-visual-studio-vs
[5] Accelerometer: http://msdn.microsoft.com/ru-ru/library/windows/apps/windows.devices.sensors.accelerometer
[6] AccelerometerReading: http://msdn.microsoft.com/ru-ru/library/windows/apps/windows.devices.sensors.accelerometerreading.aspx
[7] Collision Detection: http://orbotixinc.github.io/Sphero-Docs/docs/collision-detection/index.html
[8] Visual Studio 2013: http://www.visualstudio.com/
[9] github.com/MissUFO/SpheroRace: https://github.com/MissUFO/SpheroRace
[10] Программируем роботов на Windows 8. Магический шар Sphero: http://habrahabr.ru/users/missufo/topics/
[11] Центр разработчика Sphero: https://developer.gosphero.com/
[12] Пример использования Sphero SDK для Windows 8.1: http://code.msdn.microsoft.com/windowsapps/Sphero-SDK-Sample-2b18913c
[13] Пример использования акселерометра в Windows 8.1: http://code.msdn.microsoft.com/windowsapps/Accelerometer-Sensor-Sample-22982671
[14] Канал разработчиков Sphero на youtube: http://www.youtube.com/playlist?list=PLECE4BD55445BDA51&feature=plcp
[15] Подробнее о Visual Studio Online: http://www.visualstudio.com/products/visual-studio-online-overview-vs
[16] Зарегистрироваться на Visual Studio Online: http://go.microsoft.com/fwlink/?LinkId=307137&clcid=0x419
[17] Источник: http://habrahabr.ru/post/214759/
Нажмите здесь для печати.