This is part 3 of a 3 part series on controlling a LEGO Mindstorms EV3 using an Amazon Echo. Part 1 is available here.
In earlier blog posts, I presented the overall architecture for controlling a Lego EV3 with an Amazon Echo (Alexa) device, and I detailed the Amazon and Alexa components in the project. In this post I'll cover more of the local application side of the architecture.
Referring again to the broad layout of the application, once a command has been received by the Echo, processed, and ultimately stored in an Amazon SQS messaging queue, pretty much all of the remaining functionality resides in a C#/.NET console application. The role of the console application is to simply poll the SQS queue for new messages, read the next one in queue and extract it's commands, then send those commands wirelessly via bluetooth to the EV3 robot.
The code for the console application can be found on github, here:
It's a pretty simple and straightforward application, so I won't go through it line-by-line. I will however point out the two central libraries powering the app:
The Amazon API (specifically Amazon.SQS and Amazon.SQS.Model NuGet packages)
and Brian Peek's legoev3 EV3 library for .NET.
For the most part, the Console application runs in a loop, where it constantly executes a cycle of
PollForQueueMessage() and then
ProcessCommand(Ev3Command command). When polling for a queue message, we simply execute the following, with a bit of fluff in the middle:
ReceiveMessageRequest request = new ReceiveMessageRequest(); request.QueueUrl = _awsSqsAddress; var responseTask = _sqsClient.ReceiveMessageAsync(request); Message nextMessage = response.Messages.First(); DeleteMessageRequest deleteRequest = new DeleteMessageRequest(); deleteRequest.QueueUrl = _awsSqsAddress; deleteRequest.ReceiptHandle = nextMessage.ReceiptHandle; var deleteTask = _sqsClient.DeleteMessageAsync(deleteRequest);
All we're doing here is requesting a message off the AWS SQS queue, grabbing the message contents (a JSON object), then deleting that message off of the queue. We then parse out the contents of the message into a command object, which we ultimately use to build up our EV3 actions.
Sending commands to the EV3 is crazy easy using the legoev3 library. Simply set up a new
Brick object, specifying a
BluetoothCommunication configuration, connect asynchronously, and you're ready to issue commands. Typical commands look something like this:
_brick.BatchCommand.Initialize(CommandType.DirectNoReply); _brick.BatchCommand.SetMotorPolarity(OutputPort.B, Polarity.Forward); _brick.BatchCommand.SetMotorPolarity(OutputPort.C, Polarity.Forward); _brick.BatchCommand.StepMotorAtSpeed(OutputPort.B, 100, distance, false); _brick.BatchCommand.StepMotorAtSpeed(OutputPort.C, 100, distance, false); await _brick.BatchCommand.SendCommandAsync();
This just tells both of the track motors to move forward, and step forward 100 units. By adding all of the commands to a
BatchCommand, you can send the entire batch at once and have the EV3 execute the steps concurrently. This way you're not moving one motor, then another.
Connecting your EV3 via bluetooth
Connecting to an EV3 via bluetooth was actually harder than I'd expected. Fundamentally the process is very easy - but the stars need to be aligned just right for it to all work perfectly.
The bluetooth protocol used is the common bluetooth-as-a-serial connection paradigm. Once you've got the EV3 properly paired with your machine (the hard part), then the EV3 is exposed to your applications as a typical serial port. In the Windows world, this means you'll communicate over COM1/2/3, or whatever. In the Linux and OSX worlds, you'll find the EV3 exposed as a /dev/tty.YourDevice device. Setting this up for the console app is a breeze. Just edit the App.config file and set the Ev3Port to be whatever serial port your machine assigned:
<add key="Ev3Port" value="COM1" /> <!-- or for Linux/OSX, "/dev/tty.YourPortName" -->
The difficult part, however, is getting the EV3 to pair with your machine.
Have a read over LEGO's documentation for the best instructions I was able to find:
Bluetooth Troubleshooting for EV3 - LEGO
Some tips I learned:
Seriously read the above PDF. There will be steps that sound strange, but you really need to follow it to the letter. Don't skip anything, and don't think you know better than the authors of that document.
I had lots of issues with when things got plugged or unplugged. You may have to try plugging things in at different times.
I had to completely shut down the Mindstorms software in order for my application to actually be able to talk to the EV3. If the Mindstorms app was still open, the connection would always be blocked.
Hopefully this 3-part series has been helpful. Please let me know if you need more information on any of the parts, I'd be happy to point you in the right direction. Otherwise, have a look at all the code on github and tinker away.