📜 ⬆️ ⬇️

We program robots on Windows 8. We control Sphero from a tablet using an accelerometer and a collision sensor

image

We continue to explore the possibilities of Sphero and its SDK .
On the agenda is controlling the robot using a tablet accelerometer and recognizing a collision with an obstacle.

Some theory


In the last article, we already discussed who Sphero is and how to start managing it programmatically on Windows 8.1 using Visual Studio 2013 .
Now we will deal with more complex things. We will learn to “steer” the robot by tilting the tablet in different directions and determine the collision with an obstacle. To do this, we will use the accelerometer of my tablet and the robot's collision sensor with the outside world.

Accelerometer

The Windows 8.1 operating system and the WinRT object model support working with the following sensors, if, of course, the device has them:

An accelerometer is a module that measures movement in three directions. This module is equipped with many modern devices. To access the accelerometer data, you must access the Accelerometer object, which provides access to the AccelerometerReading object with the following properties:

We will subscribe to the event of changing the accelerometer readings and move the robot, speeding up, slowing down or turning it around depending on the readings.
')
image

You can subscribe to the event of changing the accelerometer readings.

Accelerometer event subscription
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) { … } 


Move

Suppose we obtained accelerometer data from a tablet. Now you need to use them to move Sphero in space.
In the Sphero SDK for Windows 8.1, there is a Roll method, which handles the movement of Sphero and takes two parameters:

By default, Sphero starts with x = 0, y = 0, heading = 0, speed = 0.

Collision detector

Sphero supports such a funny thing as a collision detector ( Collision Detection ). It works very primitively , on the difference of coordinates.

The Sphero SDK for Windows 8.1 already has a ready-made CollisionDetectedEvent event for which you can subscribe and catch collisions with real-world objects.

Event Description
 private void OnRobotConnected(object sender, Robot robot) { … robot.CollisionControl.StartDetectionForWallCollisions(); robot.CollisionControl.CollisionDetectedEvent += OnCollisionDetectedEvent; … } 

The event will be triggered if you do not forget to turn on the collision sensor:
 robot.CollisionControl.StartDetectionForWallCollisions(); 

When you no longer need a sensor, turn it off:
 robot.CollisionControl.StopDetection(); 


Some useful features of Sphero SDK

To work with the robot, we also need the following methods of the Sphero SDK for Windows 8.1:

SetBackLED (intensity) - turn on the backlight of the back of the robot so that you can understand where it will go. Values:
1.0f - includes full power.
0.0f disables.

SetHeading (heading) - rotate the robot. Accepts values ​​from 0 to 359.

SetRGBLED (red, green, blue) - set the color of the ball.

Roll (heading, speed) - set the direction of movement and speed of movement:
heading - the angle of movement. Accepts values ​​from 0 to 359.
speed - the speed of movement. 0 - does not move. 255 - the maximum speed.

Sleep () - put the robot to sleep.

Development


Task

Move the robot using the accelerometer. When faced with an obstacle - paint the robot red.

Instruments


Process

1. Open Visual Studio 2013 and create a project File / New / Project / Blank App .

image

2. Connecting the RobotKit.dll assembly from Sphero SDK for Windows 8.1

image

3. Add Bluetooth RFCOMM support for the application. Open Package.appxmanifest in the code editing mode and add the following code to the Capabilities section.

Bluetooth RFCOMM support for the application
 <wb:DeviceCapability Name="bluetooth.rfcomm"> <wb:Device Id="any"> <wb:Function Type="serviceId:00001101-0000-1000-8000-00805F9B34FB" /> </wb:Device> </wb:DeviceCapability> 


4. Put on the main screen of the application:

Open the MainPage.xaml file and add it all there.

The main screen of the application
 <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. Go to MainPage.xaml.cs and describe the logic of the game. To communicate with Sphero, we use the object model provided by the SDK.

Game logic
 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. Connect to Sphero via Bluetooth

image

7. Run the application.

image

8. Click on the Start button and check the game in practice.

image

Result

We got a simple toy. It can be used by arranging multiplayer robot races, or to play with a pet.

The result of the work can be viewed on video.


Sources are available here: github.com/MissUFO/SpheroRace

useful links


We program robots on Windows 8. Sphero magic ball
Sphero official website
Sphero Developer Center
Sphero SDK for Windows 8.1
Sphero SDK for Windows 8.1 Example
Accelerometer usage example in Windows 8.1
Sphero developer channel on youtube
Download Visual Studio 2013
Read more about Visual Studio Online
Sign up for Visual Studio Online

Source: https://habr.com/ru/post/214759/


All Articles