Previously I posted an article on handling EV3g binary Mailbox messages under Python3. Since then I have carried on working on this class, along with adding a handler class.
Improved Mailbox Handling
One of the things I wasn’t so keen on with my implementation was the need to specify the type of Mailbox value, i.e. BOOL, NUMBER, or TEXT. Python’s variables have their own type, so the code has been adjusted to use the value’s own type to determine the binary payload format. It is still possible to coerce the type:
from ev3mailbox import EV3Mailbox
float_msg = EV3Mailbox("Pi", 3.1415)
# Coerce to a string
string_msg = EV3Mailbox("Pie", 3.1415, str)
These changes have made the use of this side of the code much cleaner.
Mailbox I/O Handler
Whilst working on my use case for the original code, I had been working on the principle that I’d be using it in a simple synchronous send/receive pattern. This worked well, until I started using threads at both sides of the ev3dev <-> EV3g link. Once threads were in the mix, there’s a risk that the bt_socket.recv(…) call could actually receive a message that wasn’t destined for that particular call, but for another area of the program.
The solution to the above problem was to implement a receiving thread that deals with all the socket.recv(…) calls. Each message is decoded, and then each Mailbox name has its own FIFO of message objects. It’s a deliberate choice to maintain the list of objects, rather than just their values, so that they can be forced to floats if it’s known they may be very small – see my previous post about that problem.
The new class implements a handler that will deal with all the Bluetooth and thread side of things. All that’s then required to do is call send(…), get(…), or stop() on the class instance:
from ev3messages import EV3Messages
handler = EV3Message(bt_mac_address)
msg = handler.get("ANOther")
value = msg.value
The calls to send(…) and get(…) should (!) be thread safe, so calls to get(…) wait on receiving a message of the requested name.
Recently, on the MINDSTORMS Facebook group, the question was posed about is it possible to receive Bluetooth mailbox messages in an AI2 app from an EV3. This is something I’ve been meaning to do for a while. I’d written AI2 code to send BT messages to an EV3, but hadn’t focused on receiving messages. This was the spur to actually get this code written.
It wasn’t too tricky. Receiving the message was simple, but parsing it was the harder part. The format of a message from the EV3, as covered in my update to BT messaging is:
This is received as a string of bytes, so has to be parsed as a list. Add in that there doesn’t appear to be a chr(x) type function in AI2 to convert from a number to its equivalent ASCII character, I have to do some array/list lookups. Thankfully I had that code in place for sending to the EV3.
I’ve got the code to a position that it can hopefully be used for other purposes. I’m releasing what I’ve done so far as a baseline for others to work from. To make the code, linked below, work do the following:
Run the EV3 code first.
Start the AI2 app.
Long-press the BT button. This will bring up a settings box.
Enter the App device’s Bluetooth name in the settings. This will be stored, and sent to the EV3. This is so that the EV3 knows where to send its messages to. This must be the same name as shown in the BT connections list on the EV3.
Press “Connect EV3”. This will give the list of BT devices known the the Android device. Choose the correct EV3.
Once the App is connected to the EV3, the EV3 will say “detected”.
Pressing the top, middle, or bottom buttons on the EV3 will send a BT message to the App.
The App will then display the message name in the top text box, and the message text contents in the bottom box.
The code only handles text message. I have no plans to develop code to handle numbers or booleans. The EV3 code will coerce those data types to strings if sent as a text message. AI2 will coerce strings to numbers if they look correct, so if the EV3 needs to send a number, simply send it as a string, and the AI2 App will still do the Right Thing™.
Okay, so I’ve been rather quiet on the blogging front for a few weeks – that’s because I’ve been working on getting my Plott3r to write out text:
Here’s a video of it taken a little while ago (prior to some of the improvements I’ve made):
This has been rather a journey of discovery. I’ve blogged previously about getting a bluetooth message to the EV3 and how I needed to work out a font.
The font itself didn’t prove to be that tricky to work out; it’s mainly been planned out on 5mm graph paper and simply converted into coordinates. I’ve tried to have it write the letters as a Left->Right writer would, so starting on the left side of each character and probably ending on the right. This way moving the the next letter doesn’t involve a lot of travelling.
One thing my Plott3r has, is an effort to manage backlash. Since the paper and pen change direction regularly I have a system that pre-moves the paper/pen a little prior to any change in direction. One thing I hadn’t realised before is that if I want to move a really small amount I could overshoot where I wanted to be just in my backlash correction. This would cause some oscillation around the correct location in some cases. For example, look at the centre of the spiral below:
The centre of the spiral is crooked due to the pen “seeking” around the correct location. My solution to this was to measure where I was before the backlash correction, and after. If I had overshot, then I did not move that particular axis. The results of this improvement on the spiral are below:
I wanted to be able to send a message from a spare Android phone to the EV3. Here’s where App Inventor 2 came in. I had to learn how it worked, along with learning its Scratch-like language, and implementing some fundamental routines, such as storing an IEE754 float. The current instance of the application looks like:
The user can simply choose between 3 text sizes, and then write their message and press “Print”. The BT button is used to set up the Bluetooth connection and the name of the sending device; this is needed so that the EV3 can acknowledge message it receives. I found that if I didn’t ACK the messages there was a race condition whereby I’d get duplicate values with the second “overwriting” what the first should have been. The core code of the messaging app is below:
At the start of the block you can see it send its name, and towards the end of the block it waiting for a bluetooth message. It doesn’t care about the contents of the message, simply that it got one. The EV3G side of the code is as below:
What’s not shown is the plotting code as that’s quite complex. It keeps a tally of the location of the last plotted character and works out if the next one will fit; performing <cr><nl> if needed. The font is variable width, and has a small amount of “kerning”, so that letters such as ‘j’ and ‘q’ can overlap the inter-character space.
I originally was only going to have one letter size, but this would allow for only around 11 characters per line, which isn’t a lot. Shrinking the letters will result in more artefacts, which I’ll come on to later, but I think it has a certain “hand writing” charm:
There are a few artefacts that I’ve tried and tried to remove. I now think I’m simply fighting with the simple fact that it’s made from LEGO bricks and I can only realistically get a certain level of accuracy in the way I’ve built it. The main artefact left is as below:
If you look at the top and bottom of the 0 (zero), G and Q, there are small overshoots on one side of the diagonal. I think this is down to using Tank Move and the Y axis motor overshooting the target before moving back a little – a result of the internal PID controller.
I’ll be showing this off again at Bricktastic this year, hence all this work. I’m pleased that, due to my desire to plot text, that the backlash control is better. I figured that I’d have the Plott3r do one more thing. It now “signs” its plots with the URL to this blog 🙂
I now need to put this to bed for a bit whilst I check that all the other models still work. Then I need to get back on with my Loom – I need to do a little bit of programming for that ready for it to be shown off too.
The code above may not look much, but I’m very pleased with it 🙂 I’ve been working with MIT’s App Inventor 2 in an effort to build an app that can send text (in some form) to the EV3 for further processing – that code has managed it!
I’d extended the EV3 tilt-to-drive tutorial from the AI2 site to add in an extra button, that when pressed runs that code. It’s fixed at the moment but it encapsulates (little endian) 0x0018, 0x0001, 0x81, 0x9e, 0x5, beep\0, 0x0006, Beep!\0. All this info has been derived from the LEGO® Communications Developer Kit docs.
To test this I had a simple program, as below, running on the brick:
Press the button on the app, and the EV3 beeps – superb!
It also shows an interesting behaviour which I may well exploit in an upcoming model – I had one program running on the EV3, solely to beep, but was still able to drive the bot from my phone. Being able to externally control an EV3 whilst it is running its own program has a lot of merit.