Upload Files From Ev3 Brick to Pc Using Bluetooth
This post was authored by Eric Schmidt, Content Developer 2, Xbox Programmer Content
Microsoft recently sponsored a team to complete in the "Build for Good" LEGO® MINDSTORMS® Robo Competition, a team that represented the Xboxbrand. I had the distinct honor of working on this team of developers, testers, and one business manager to create a pretty awesome exhibit.
Team Xbox, wearing distinctive Zoo Tycoon themed hats.
The Squad Xbox exhibit ambitiously connected 3 LEGO MINDSTORMS EV3 robots, 5 Windows Phones, and a Surface Pro tablet into an integrated arrangement. The exhibit created a real-life version of the Zoo Tycoonvideo game from Microsoft Studios that used LEGO bricks and robots instead of people. Using a Windows Runtime app (that is, an app that runs on the Windows Runtime APIs, like a Windows Store app) on the Surface, a "player" built a zoo, exhibit-by-exhibit, by making selections in the app. When the player added a new animal showroom to the zoo – a polar bear, for example – the app sent a simple Bluetooth message to one robot that delivered an showroom (fabricated of LEGO bricks). That robot then sent a unproblematic message back to the app that the exhibit was delivered. The app adjacent sent another message to a second robot to deliver (by airlift!) an animal to the exhibit. Finally, afterward the exhibit and fauna were securely in identify, the app alerted a third robot to feed the brute.
Each of the robots executed code written using the LEGO® MINDSTORMS® EV3 Software. The code listened for messages from the app and then reacted in a specific mode.
From the app's perspective, it connected three separate and distinct Bluetooth-enabled devices to which it sent diverse messages. The difficulty lay in establishing the Bluetooth connection with each robot and and so sending and receiving messages. To accomplish this, the app used several of the Windows Runtime APIs designed for interacting with devices – including the Windows.Devices.Bluetooth.Rfcommnamespace introduced in Windows viii.1 and Windows Phone 8.1.
In this web log post, I'll provide step-by-stride instructions for how you tin can talk to a MINDSTORMS robot from a Windows Runtime app. I'll bear witness you how to build a very simple app that sends and receives messages from an EV3 robot. I'll focus on the specific Windows Runtime APIs we used to connect to the robots, and so I'll be glossing over a lot of the basics well-nigh building a Windows Runtime app using HTML, CSS, and JavaScript. If you need to learn more about the fundamentals, see Create your first Windows Store app using JavaScript on MSDN.
On the other mitt, go along in mind that this blog post provides more than explicit instructions effectually managing project files in a Visual Studio solution than we normally provide in our posts. I know that many of the loyal readers of our blog are professional developers who are deeply familiar with the nuts of Visual Studio. For you, I encourage you to skip ahead to some of the details virtually connecting to Bluetooth devices from a Windows Runtime app.
Get the hardware and software
Before I get whatever farther, I assume that you've already got the required devices and software for this process. I'm using Visual Studio Limited 2013 for Windows, running on Windows 8.1, to write my lawmaking. I'k connecting to a MINDSTORMS EV3 Intelligent Brick (the 'brain' of the robot) that has been updated with the 1.03H firmware version of the EV3 operating organisation. (It'due south easiest to update the firmware from the MINDSTORMS EV3 Software.)
Important: Your EV3 Intelligent Brick needs to be paired and connected at least one time to your Windows PC before they volition exist able to receive and send letters to each other. This can exist a tricky process:
- On the settings folio for the EV3 Intelligent Brick, make sure that Bluetooth is turned on. When yous select the Bluetooth option from the screen, ensure that Visibility and Bluetooth are selected. Likewise, make sure that iPhone/iPad/iPod are non selected.
- Pair the EV3 Intelligent Brick and your Windows PC.
- From the Starting time screen, type Devices and Printers, and then select Devices and Printers. In the Command Console, on the Devices and Printers folio, click Add a device. In the list, notice the name of your EV3 Intelligent Brick (if you haven't changed it in the EV3 Software, the name will be 'EV3') and and then follow the on-screen instructions.
- t this indicate, you'll be prompted on the EV3 Intelligent Brick to acknowledge the connectedness with your PC and to take a passcode. On the PC, you'll be asked to supply this passcode.
- Make sure y'all remember your brick's name!This becomes important later on on when y'all endeavor to connect to the brick.
- At present yous can connect to the brick from your PC. You lot can do this with a unmarried click from the EV3 Software.
- Open Devices and Printers again. If your brick and PC are paired, the brick will show up in the "Unspecified" category under its own proper name. (You may see it twice if you connected to the brick previously by USB. Select the entry that has the details 'Bluetooth Peripheral Device'.) Right-click the device and select Properties. In the device Properties window, become to the Services tab and ensure that Serial Port (SPP) 'Series Port' is selected. Apply any changes and close the settings dialog box.
- Make sure that the EV3 Software is not connected to your brick by Bluetooth when you attempt to connect to the brick from your app. This can block the Window Runtime app from connecting to the EV3 brick.
For more than info about how to troubleshoot Bluetooth connectivity problems, download the EV3 Bluetooth guide.
Write the EV3 listening and receiving code
To demonstrate sending and receiving messages, the brick runs a simple listening program written using the MINDSTORMS EV3 Software. A picture of the program running on the robot is shown below.
Here's a brief description of how the program on the EV3 robot works:
- The plan waits until it receives a message from the app titled "AppSays" (using a Wait block). The value of the message sent by the app is interpreted as a floating bespeak number. The screen on the brick briefly displays an acknowledgement that information technology received a bulletin.
- Adjacent is a simple switch-case statement (a Switch block). If the robot receives a 1 or 2 from the app, it creates a variable called "Response" that says "Robot got [number]." If the robot receives any other number – or cannot decipher the message that it receives – information technology updates the "Response" variable to say "Could non decipher."
- The robot then sends a message dorsum to the app titled "RobotSays" with the value provided by the "Response" variable (a Messaging block).
Afterward I create and download this program to my EV3 brick, I tin can close the MINDSTORMS EV3 Software and start to build the Windows Runtime app.
Create the user interface for the Windows Runtime app
Before I start writing more code, I'll accept a quick inventory of the features I demand to build for this uncomplicated Windows Runtime app. The app has to be able to do a few things programmatically:
- It needs to establish a connectedness to the brick. (For Squad Xbox, the code needed to be extensible and so that the app could connect to three bricks.)
- It needs to convert a user-generated message into the message protocol that the EV3 brick tin can understand.
- Information technology needs to listen for and decode incoming messages from the brick.
In this web log post, I'll pattern an app so that the code for each feature can be individually tested. Because the Team Xbox app was largely written using JavaScript, I'll write this simple app in JavaScript. Of course, the WinRT APIs that I use are too available to other languages, so you lot could recreate this app in C#, Visual Basic, or C++ (and use the same code in a Windows Phone app). (In fact, you might find that creating the message to send to the robot is easier in a more strongly-typed language. If you feel bold, I encourage you to abstract the messaging part of the solution into a Windows Runtime component.)
After opening Visual Studio 2013 Express for Windows, I click File, New Project. In the New Projection dialog box, I expand Installed, Templates, JavaScript, Store Apps. In the list of templates, select Navigation App. (This may be titled Navigation App (Windows) if you've downloaded Visual Studio 2013 Update ii.) Now I accept a clean Windows Runtime app with a single page called "home" as shown in the project structure below:
Because this app needs access to the PC's proximity features, nosotros need to declare this adequacy in the app'due south manifest. We also need to declare access to the specific Bluetooth device. In Solution Explorer, right-click the file titled 'package.appxmanifest' and select View Code. In the code for the app manifest, find the Capabilities chemical element and add the following XML:
< DeviceCapability Name ="proximity" />
< m2:DeviceCapability Proper name ="bluetooth.rfcomm" >
< m2:Device Id ="any" >
< m2:Function Type ="proper name:serialPort" />
</ m2:Device >
</ m2:DeviceCapability >
Next, I'm going to create a simple user interface for the app. In Solution Explorer, open up /pages/dwelling/home.html. In the department with the part 'primary', supersede the content with the following HTML markup:
<!–Send letters to the robot.
This section remains disabled until a connection has been fabricated. –>
<!-- Ship Messages to the robot. This department remains disabled until a connexion has been made-->
< div >
< h2 >Send message</ h2 >< br />< br />
< div >
< div >< input type ="number" class ="number-input" placeholder ="Type a
number" /></ div >
< div >< button class ="transport-bulletin" disabled ="disabled" >Send
bulletin</ push button ></ div >
< div form ="output" ></ div >
</ div >
</ div >< br />< br /><! --Connect to the robot and register messages that are received.
<div >
< h2 >Connectedness info</ h2 >< br />< br />
< div >< button class ="connect-robot" >Connect to
robot</ push button ></ div >< br />
< div >
Bulletin history
< div grade ="messages" ></ div >
</ div >
</ div >
This HTML creates a two buttons (Connect to robot and Send message) and a number input box. The Send message push starts out disabled – once the app has connected to the robot, the button becomes enabled over again. Under the Connect to robot button is a container div for displaying the messages received from the robot.
Next, I'll open the /pages/abode/home.js and add code to react to events raised by the HTML page, especially the buttons. Supercede the template code in abode.js with the following code:
(role () {
"use strict";
var myRobot;WinJS.UI.Pages.ascertain("/pages/home/home.html", {
ready: function (element, options) {// A uncomplicated utility function to write output to the HTML page.
function logOutput(championship, bulletin) {
var output = element.querySelector('.letters');
output.innerHTML += new Date().toLocaleTimeString() + " " +
title + ": " + message + "</br/>";
}// Add an event handler to the push that connects to the robot.
element.querySelector('.connect-robot').addEventListener("click",
function (evt) {
evt.target.setAttribute("disabled", "disabled");// The phone call to connectToRobot is asynchronous,
// so we continue our work in the done method of
// returned promise.
Robot.connectToRobotAsync().done(function (rbt) {
myRobot = rbt;
logOutput("Connection", "Connected to robot.")element.querySelector('.send-message').removeAttribute('disabled');
// Add together an effect handler to the robot's reportReceived upshot.
myRobot.reportReceived = function (written report) {
logOutput(study.title, report.value);
}
});
});// Add result handler to the button that sends a bulletin to the robot.
chemical element.querySelector('.ship-bulletin').addEventListener("click",
role () {
var number = chemical element.querySelector('.number-input').value;if (!isNaN(number)) {
myRobot.sendMessage("AppSays", number);
element.querySelector('.output').innerHTML = "Message sent.<br/>";
}
else {
element.querySelector('.output').innerHTML =
"Brand sure that you lot entered a number.<br/>";
}
});
}
});
})();
In this code, I create a new Robot object, store a reference to that object and so transport messages to robot when the user clicks the Ship message button. When messages are received from the robot, in that location is a simple utility role (logOutput) that displays the bulletin in the UI of the app.
Write the code to interact with the robot
Now I tin begin to write the JavaScript code that talks to the EV3 robot. I'll kickoff past calculation a new JavaScript file called "Robot.js" to the solution. (In Solution Explorer, right click the 'js' binder, cull Add, New JavaScript File. In the Add together New Item dialog box, proper name the file "Robot.js" and click Add together.) Before I go on, I'll add a reference to the new JavaScript file to my default.html file.
< script src ="/js/Robot.js" ></ script >
Robot.js is initially empty, so I'll add the post-obit code to the file to give information technology some shape.
(part () {
"use strict";var robotName = "EV3"; // Replace with your device's proper name.
// Create aliases for the Windows Runtime namespaces that we need.
var bluetooth = Windows.Devices.Bluetooth;
var devices = Windows.Devices.Enumeration;
var sockets = Windows.Networking.Sockets;
var streams = Windows.Storage.Streams;
var crypto = Windows.Security.Cryptography;// Gets a connection to a specifically named EV3 brick. This code can be
// customized to connect to multiple EV3 bricks.
office connectToRobotAsync() {
// Implementation details …
}WinJS.Namespace.define("Robot", {
connectToRobotAsync: connectToRobotAsync
});
})();
I've used WinJS.Namespace.defineto expose the connectToRobotAsync role. You notice that I've declared a robotName variable in this module that identifies the robot I'll connect to. I could have instead passed the name to the connectToRobotAsync part, which would exist necessary if I wanted to connect to more than than one robot.
I need to employ several Windows Runtime APIs to connect to the robot and send information to it. Rather than use the fully-qualified names for each namespace, y'all see that I've given them curt aliases that are referenced by variables inside the scope of the bearding function. This is a mutual practice in JavaScript to avoid typing out the full identifiers for APIs each time.
Here now is the implementation of the connectToRobotAsync function:
// Gets a connection to a specifically named EV3 brick. This code tin can
// be customized to connect to multiple EV3 bricks.
function connectToRobotAsync() {
var selector =
bluetooth.Rfcomm.RfcommDeviceService.getDeviceSelector(
bluetooth.Rfcomm.RfcommServiceId.serialPort);
selector += " AND Organisation.ItemNameDisplay:="" + robotName + """;return devices.DeviceInformation.findAllAsync(selector, zip).
then(function (devices) {var device = devices[0];
return bluetooth.Rfcomm.RfcommDeviceService.fromIdAsync(device.id);
}).
then(function (result) {var service = event;
var socket = new sockets.StreamSocket();
var promises = [];if (service.connectionHostName && service.connectionServiceName) {
promises.push(socket.connectAsync(
service.connectionHostName,
service.connectionServiceName));
promises.push(WinJS.Promise.as(socket));return WinJS.Promise.join(promises);
}
}).
done(function (effect) {if (!Array.isArray(outcome)) {
return result;
}return WinJS.Hope.as(new Robot(robotName, result[1]));
});
}
There's a lot to unpack in this lawmaking block, so I'll take information technology step past pace. Observe kickoff that the code is set upwards as a series of asynchronous calls, each one returning a Promise object. Each code block – contained in the calls to then and done – returns a Hope object the represents the work performed by the asynchronous call. To perform the work in sequence, I add my code to the so method of the Promise object returned by the previous cake of code.
Before I go along, I need an like shooting fish in a barrel way to select my connected Bluetooth device (in this case, my robot) out of all the devices connected to my motorcar. To practise this, I call the Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService.getDeviceSelector method. This returns an Advanced Query Syntax (AQS) cord that defines the parameters for a query that volition select my robot. The AQS selector cord will expect something like the following:
System.Devices.InterfaceClassGuid:="{B142FC3E-FA4E-460B-8ABC-072B628B3C70}" AND
System.DeviceInterface.Bluetooth.ServiceGuid:="{00001101-0000-1000-8000-00805F9B34FB}"
AND System.Devices.InterfaceEnabled:=Organization.StructuredQueryType.Boolean#Truthful AND
System.ItemNameDisplay:="EV3"
Next, look at the first asynchronous call, the telephone call to Windows.Devices.Enumeration.DeviceInformation.findAllAsync. This returns all the devices (as a DeviceInformationCollection object) that satisfy the query defined by the selector string. In this case, it should return a collection with only a single DeviceInformationobject – my robot.
Note: You need to laissez passer in a 2d argument to the phone call to DeviceInformation.findAllAsync. Otherwise, you'll get a collection of ALL the devices that connect to the PC using a serial port. Of course, y'all tin can modify the AQS selector string to render divergence sized collections of devices. If, for instance, you wanted to get all the Bluetooth devices continued to the machine, you could utilize the aforementioned query string as shown higher up (only leave out the final AND clause).
Side by side, I call the Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService.fromIdAsync method for the DeviceInformation object that represents my robot. This will return the Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService that represents the connection to my robot. I can retrieve the RfcommDeviceService from the result argument passed into my call to then.
With the RfcommDeviceService in manus, at present I create a new StreamSocket object and connect to my robot using the Windows.Networking.Sockets.StreamSocket.connectAsync method. The StreamSocket object represents an open up 'channel' between my PC and the robot: I tin can send messages to and receive messages from the robot over the StreamSocket. When I send messages to my robot, I'll write to the output stream exposed by the StreamSocket. To receive messages from the robot, I heed to changes from the data received from the input stream of the StreamSocket.
When the StreamSocket.connectAsync returns successfully, I now accept an open channel to talk to the robot. The Promise object returned by the StreamSocket.connectAsync method is empty, so I need to go along a reference to that StreamSocket outside of that code block. Rather than storing the StreamSocket in a variable in a higher lexical scope, I wrap it in a hope and use WinJS.Promise.join to combine it with the promises returned from the call to StreamSocket.connectAsync. Once the joined promises return, the StreamSocket will be independent in i of the results.
Considering I need this StreamSocket to communicate with my robot, I laissez passer it into the constructor for my custom Robot form. The last code block, the call to done, returns a new Robot object to the code that calls Robot.connectToRobotAsync.
The following code shows the definition of the Robot class:
// A grade that contains information near a robot.
part Robot(name, socket) {
this.name = name;this._connection = socket;
this._reader = new streams.DataReader(socket.inputStream)
this._reader.byteOrder = streams.ByteOrder.littleEndian;this.sendMessage = office (title, value) {
if (this._connection) {
var message = new Message(title, value);
var messageBuffer = message.messageBuffer;this._connection.outputStream.writeAsync(messageBuffer);
}
else {
throw new WinJS.ErrorFromName("Connexion",
"No connection to brick; tin can't write a message.")
}
}this.reportReceived = null;
// Outset listening loop.
pollResults();var that = this;
function pollResults() {
that._reader.loadAsync(ii).so(function () {
var size = that._reader.readInt16();that._reader.loadAsync(size).then(function (data) {
var dataArray = new Uint8Array(data);
that._reader.readBytes(dataArray);
var message = Message.parseMessage(dataArray);if (that.reportReceived) {
that.reportReceived(message);
}
setTimeout(pollResults, 500);
});
});
}
}
Once again there's a lot I could discuss here, simply I'll focus just on a couple of items. Commencement, notation that the Robot class takes the robot's proper noun and the StreamSocket that connects my PC to the robot every bit parameters for the constructor method. When I create a new Robot object, I store a reference to the StreamSocket in the object, in addition to its name. Yous'll as well note that I create a new Windows.Storage.Streams.DataReader object when the object is initialized – I'll need this to read the messages the robot sends back to me. The streams emitted by the robot use the Little Endiansystem for organizing individual bytes within a multiple-byte datum of information.
The Robot class exposes one public method, sendMessage, and i public event, reportReceived. The sendMessage method has two parameters, championship and value, which it uses to create a new Message object. (I'll examine the Message course in a moment.) After creating a new Message object, the sendMessage method writes the message equally a buffer to the output stream of the StreamSocket, using the Windows.Storage.Streams.IOutputStream.writeAsyncmethod.
The reportReceived event allows external code to add an result listener to answer when the robot sends a message back to the PC. One time I've created a new Robot object, I can assign a function to this event (property) and it will exist called when the PC receives the message.
The pollResults method waits to load data from the input stream from the StreamSocket connection (via the DataReader object). The constructor part for the Robot course both defines the pollResults role and invokes it, which starts the process of waiting for letters from the robot. When invoked, the pollResults function attempts to read ii bytes of data from the input stream provided by the StreamSocket, using the DataReader.loadAsync method. While the input stream is empty (no data has been sent from the robot), the method waits, returning command to other lawmaking. Once some data has been sent, it is loaded into the DataReader and so read as bytes into a typed array. The resulting array is passed as an argument to the Message.parseMessage function, which returns a Message object. After the message from the robot has been decoded, the reportReceived event handler is called, passing in the new Message object every bit an argument.
This brings me to the Message class, which is shown in the following lawmaking.
// A class that tin encode / decode messages to the robot.
part Message(championship, val, assortment) {
this.title = title;
this.value = val;
this.messageArray = assortment || encodeMessage(title, val);
this.messageBuffer = crypto.CryptographicBuffer.createFromByteArray(new Uint8Array(this.messageArray));// Encodes a message as a byte array.
role encodeMessage(title, val) {
function encodeString(str) {
var byteArray = [];
for (var i = 0; i < str.length; i++) {
if (str.charCodeAt(i) <= 0x7F) {
byteArray.push(str.charCodeAt(i));
}
}
render byteArray;
};var floatsAsBytes = {
"1": [four, 0, 0, 0, 128, 63],
"2": [4, 0, 0, 0, 0, 64]
};var header = [1, 0, 129, 158];
var titleFieldRaw = encodeString(title);
titleFieldRaw.button(0);
var titleSizeField = Number(titleFieldRaw.length);
var valueField = floatsAsBytes[val.toString()];var payload = header.concat(titleSizeField, titleFieldRaw, valueField);
var rawMessageArray = [Number(payload.length), 0].concat(payload);return rawMessageArray;
}
}
The Message grade needs to support two separate scenarios:
- Information technology needs to convert championship/message pairs to a byte array that'southward sent to the robot.
- It needs to contain title/message pairs decoded from data received from the robot.
To address both of these scenarios, the constructor function for the Bulletin form takes three parameters: title, val, and an optional parameter, array. The championship and val parameters are pretty straightforward – they are the title and bulletin of the message that I'1000 going to send to or have received from the robot. The arrayparameter supports the second scenario – when I receive a message from the robot, the data volition already be processed every bit an array through the decoding process. So, I don't need to create a new array from the championship and value when the Message object is instantiated – I tin just pass in the array that I already have and store it in the Message object. I'll discuss the procedure of decoding a message later, when I talk about the Message.parseMessage part.
You run across that the Message object exposes four members: title, value, messageArray, and messageBuffer. The championship and value backdrop store the title and val parameters passed into the constructor and permit me to convert the messages into a specifically-ordered byte array. The messageArray property stores that byte array, which can exist created using the internal encodeMessage office. (As mentioned earlier, for received messages the messageArray property stores the decoded assortment.) The messageBuffer property stores a Windows.Storage.Streams.IBuffer object, which is what really gets written to the output stream sent to the robot. I use the Windows.Security.Cryptography.CrytographicBuffer.createFromByteArray method to create the Buffer object from the byte array.
So y'all're probably wondering: how does the message from my PC get encoded so that the robot can sympathize it? Well, there'southward a very specific protocol that the EV3 brick expects from messages it receives. If you ship a bulletin to the EV3 without post-obit the protocol (or with a poorly formed bulletin), the EV3 will receive the bulletin just won't register information technology as a message in a Look block of Messaging block. Each message needs to incorporate a title (Message championship in the EV3 Software) and a bulletin (Message in the Ev3 Software). The title provided in the bulletin must match the Mailbox title field of the Wait block in the EV3 program running on the brick – if they don't match, the robot ignores the message.
The protocol for a message sent to and received from the EV3 brick follows. I'll provide the values both as hex values and (where possible) UTF-8 graphic symbol codes or values. (Here I demand to acknowledge the tremendous debt I owe to the EV3Messenger sample on CodePlex and Hans Odenthal's blog post, Sending messages from a PC application in C# to the Lego EV3.)
- The number of bytes in the message, followed by a 0 (0x0) terminator.
- A "header" of sorts that e'er contains the aforementioned data:
- The number of messages being sent. This will ever exist i (0x1).
- A 0 (0x0) terminator.
- The type of bulletin, which is always 124 (0x81).
- A system command, which is e'er 159 (0x9E).
- The size of the bulletin title, in bytes.
- The message championship, with each letter of the alphabet in the title represented every bit a UTF-8 encoded value, followed by a 0 (0x0) terminator.
- The message size, as a single byte, followed by a 0 (0x0) terminator.
- The message as a series of bytes. The message can be text (a varying number of bytes), a floating point number (16-chip or four bytes), or a simple Boolean (1 byte).
Taking my instance of a message that has the title "AppSays" and a bulletin with a Unmarried floating indicate number (1) to the robot, the byte array looks like the post-obit nautical chart. (Think that the Wait block in the EV3 program is listening for a message titled "AppSays".)
| Index in the array | Value | Section | Description |
| 0 | 0x13 (xix) | Bytes in the message | The size of the message does non take into account the beginning two bytes. |
| 1 | 0x0 (0) | A zero terminator. | |
| 2 | 0x1 (1) | Header | The number of messages being sent. |
| 3 | 0x0 (0) | Header | A nix terminator. |
| iv | 0x81 (124) | Header | The type of bulletin – always 124 (0x81). |
| 5 | 0x9E (159) | Header | System control – always 159 (0x9E). |
| 6 | 0x8 (viii) | Title size | The number of bytes in the message title, including the cypher terminator. |
| 7 | 0x41 (65) | Title | The first letter of the championship in UTF-8 encoding, an upper-example 'A'. |
| 8 | 0x70 (112) | 'p' | |
| ix | 0x70 (112) | 'p' | |
| 10 | 0x53 (83) | 'South' | |
| 11 | 0x61 (97) | 'a' | |
| 12 | 0x79 (121) | 'y' | |
| 13 | 0x73 (115) | 's' | |
| 14 | 0x0 (0) | A zero terminator | |
| 15 | 0x4 (iv) | Message size | The size of the message, in bytes. I'm sending a 16-chip floating betoken number (a Single), so the bulletin is 4 bytes. |
| 16 | 0x0 (0) | A zero terminator | |
| 17 | 0x0 (0) | Message | The start of the bulletin. In this case, the floating point number '1.0' expressed as iv byte values. |
| 18 | 0x0 (0) | Message header bytes ii for floating signal value ane.0 | |
| nineteen | 0x80 (128) | Bulletin header bytes 3 for floating indicate value 1.0 | |
| twenty | 0x3F (63) | Bulletin header bytes 4 for floating betoken value ane.0 |
TIP: If you're sending a numerical value to your robot but the robot can't decipher information technology, make certain you lot're sending a floating point number and not an integer. The Message and Wait blocks in the EV3 Software only accept numerical values that are floating-betoken numbers.
The messages that the EV3 sends dorsum to the PC follow the same protocol. So, decoding them is just a thing of using the protocol to catechumen the received message back into text (and other things). The part Message.parseMessage, which does the decoding, is shown below.
// Decode a bulletin sent from the robot into a Message object.
Message.parseMessage = role (message) {
function decodeMessage(message) {
var str = '';
for (var i = 0; i < message.length; i++) {
var currentCharHex = message[i];
str += String.fromCharCode(currentCharHex);
}
return str;
}var titleSize = bulletin[four];
var titleByteArray = message.subarray(5, 4 + titleSize);
var title = decodeMessage(titleByteArray);var valueStartNum = iv + titleSize + 1;
var valueSize = message[valueStartNum];
var valueByteArray = Uint8Array(message.subarray(valueStartNum + two, valueStartNum + valueSize + 1));
var value = decodeMessage(valueByteArray);return new Bulletin(title, value, message);
}
This function takes a information array and converts it to a Message object. I only need to know where the characters for the championship and the bulletin brainstorm in the information assortment – from there I use the length to get out the total strings. The first affair I do in this office is get the size of the title string, which will always be at the 6th index in the assortment. (In my lawmaking above I access the 4thindex in the array because the pollResult function in the Robot object reads and discards the first ii bytes of data sent by the robot.)
Once I have the size of the title, it becomes a relatively trivial mathematical process of selecting sub-arrays in the information and converting them into strings. In JavaScript, I use the Cord.fromCharCodefunction to decode individual characters. Once the title and value have been converted to strings, I create a new Message object that is so returned to the calling code.
(As some of you will probably notice, this function only handles the decoding of strings – Booleans and numeric letters from the robot won't be deciphered correctly using this code.)
Now that I've covered the lawmaking for sending and receiving letters betwixt a PC and an EV3 robot, let's test the code out.
Test the app
Before running and testing the Windows Runtime app, you lot'll want to outset the program on the EV3 brick. I highly recommend that you download the code to the brick, shut all instances of the EV3 Software on your PC, and so run the programme directly on the brick.
With the EV3 program running, run the Windows Store app code from Visual Studio Express (press F5). The user interface for the app should look similar to this:
TIP: When you showtime exam connecting to the brick from your app, yous'll exist prompted as to whether you want to let the app to access your brick. Click Allow to continue.
To ensure that the code is working correctly, try the following steps:
- Click Connect to Robot to initiate the connectedness between the app and the robot.
A message will appear nether Bulletin history after the app has connected and the Send bulletinpush button will go enabled. - Enter a number, 1 or 2, into the text box provided and and then click Ship message.
Yous should see a new message appear under Message history that includes the time, the championship "RobotSays" and a bulletin indicating what value the robot received. If you want to perform an extended test, I suggest that y'all convert the EV3 programme provided in a higher place into a MyBlock and then place a copy of that MyBlock within a Loop cake. That way you lot tin can try out multiple dissimilar values.
Other resources
You might be wondering if at that place's an easier way to reach all this. Well, the good news is that there are a couple of CodePlex projects designed to aid y'all communicate with the LEGO MINDSTORMS EV3 brick over Bluetooth:
- LEGO MINDSTORMS EV3 API. This project includes a Windows Runtime component (.winmd file) that can be added to a Windows Runtime project (Windows, Windows Telephone, and universal Windows apps), a library for Windows Phone apps built with Silverlight, and a library that can be used in a Win32 application. This library is very powerful and provides a significant range of functionality. You can use it to read sensor values, run motors, even play sounds or read files on the EV3 brick. However, it won't allow you to connect to multiple EV3 bricks from a Windows Runtime app.
- EV3Messenger. This Win32 project (a unproblematic Windows Forms awarding) allows you to connect directly to a specific EV3 brick by specifying the serial port assigned to the brick. If you have more than one brick connected to your PC, you need simply specify different series ports to connect to each / all of them. I of the best parts of this project is that the message protocol for the EV3 brick is broken down into a very readable table. As well, the project contains some C# code that can be reused to encode and decode messages from a Windows Runtime app (with some slight modifications). The only drawback is that the connection code for this app uses the System.IO.Ports namespace, which you can't apply in a Windows Runtime app or in a Windows Runtime component.
Unfortunately, neither of these libraries supply both of ii key features that Team Xbox needed. We wanted to have the form factor of a Windows Runtime app, but nosotros needed to send messages to and receive messages from multiple (in our case, three) EV3 bricks. We produced some lawmaking that was heavily influenced by the two CodePlex projects mentioned earlier, but tailored for our needs. The "secret sauce" lies in the Robot.connectToRobotAsync role. Equally I mentioned previously, it tin can exist easily modified to accept a unique name for an EV3 brick and the same role tin exist called repeatedly at runtime (allowing the states to connect to more one block during one app session).
All in all, Team Xbox had a blast edifice Lego robots and writing the code to talk to them. Our goal was to inspire more people – especially immature adults – to engage and explore the world of science, engineering science, applied science, and mathematics. I retrieve nosotros achieved our goal; furthermore, I hope that this blog postal service will help you build a Windows Runtime app that talks to an EV3 robot … or whatever other Bluetooth-enabled device y'all're working with.
Thank yous for reading and proceed on developing apps!
reeddreasockinly80.blogspot.com
Source: https://blogs.windows.com/windowsdeveloper/2014/05/07/talking-to-robots-or-other-devices-using-bluetooth-from-a-windows-runtime-app/
Post a Comment for "Upload Files From Ev3 Brick to Pc Using Bluetooth"