Cornell University: ECE 4960

Return to main page

Lab 2, Bluetooth

Objective

The Artemis board and a computer are capable of low-latency, moderate-throughput wireless communication via Bluetooth LE. In this lab, you will expand a basic application for wireless communication over a Generic Attribute (GATT) framework on top of robust BLE stacks.

Distribution Code

Please download the distribution code.

Files included

  • ECE_4960_Robot/*: contains the Arduino sketch to upload.
  • main.py: A Linux, macOS, and Windows compatible python Bluetooth example. Searches for the robot board (if not saved in Settings.py), connects, and performs tasks in myRobotTasks. Handles messages from the board with a simple handler that you will expand.
  • constants.py: A collection of useful constants. ..* Commands must match your commands on the robot. ..* Bluetooth UUIDs are preset and correct.
  • settings.py: Settings dictionary.
  • Other c files: functions that use the Ambiq suite SDK to control the radio and establish a GATT serial port protocol. The true protocol (Ambiq Micro Data Transfer Protocol) employs some additional handshaking, but our example just uses plain bytes.

Tasks

USB Passthrough Bluetooth

The USB BLE adapter in your kit of parts that should work with little extra configuration. If you can set up USB passthrough, that adaptor should work with the Ubuntu VM provided in Lab 1. The staff will be able to provide better support for that setup. As a fallback, BLE exists on many computers made after 2012 and running recent operating systems. The bluetooth example should be compatible with backends on Linux (bluez), Windows 10 (Windows BLE), and macOS (CoreBluetooth).

You’ll also need an installation of bleak on python3. The easiest way is to install python3, pip, and run python3 -m pip install bleak or py -m pip install bleak. The Ubuntu VM should already have python3 and bleak installed. However, running the install command should not break anything. As a result, once you get USB passthrough working, you should be able to download the distribution code and commence work immediately.

Connect to the Artemis Board

Upload the provided Arduino sketch to the Artemis board. Upon reset, the blue LED should blink rapidly for a short time and then extinguish itself. The Serial Monitor should also show:

Revision = Rev 1.0  ECE 4960 Robot Compiled: Aug 28 2020   14:38:19
############## setting up WatchDogTimer WDT ########################
Interrupt Count = 93 ticks
Reset Count = 93 ticks
Reset Status Register = 0x1

Run main.py to try to discover your robot. The bleak library might throw some errors (usually on macOS) when trying to discover the robot. Re-running the program gives bleak another chance to search for the robot. It may take many re-runs for bleak to connect, but once it connects, the connection should be fairly reliable. (Optional step: add your robot’s MAC address or UUID to Settings["cached"] in settings.py. This especially helps on macOS.)

If you come up with a better solution than re-running the program, please share it.

Robot command framework

The distribution code includes the framework for a basic, efficient command language. command.h includes a 99-byte structure (cmd_t) with the first byte as the command type, the second byte as some sort of length (you will decide how to use it!), and the rest as data. A 1-byte enum names a few commands (cmd_type_e) which must match the commands found in constants.py. We recommend that you expand this framework in a way that works well for your implementation of future labs. A few things to note:

  • Your programs might not have to handle all kinds of received commands. One-way commands may make debugging easier (i.e. SER_TX will travel only from your robot to the computer, while SER_RX only travels from the computer to your robot).
  • There are also some helper functions, such as printOverBluetooth() and theRobot.sendMessage(). They are slow compared to sending numbers themselves. You can use sprintf() on Arduino to build strings for printOverBluetooth().

Ping Your Robot

Right now, your robot doesn’t do anything when connected. Comment pass in myRobotTasks() and uncomment await theRobot.ping(). Observe the output and comment on the round-trip latency. What is it on average? How does the latency vary? How many bytes does the ping transfer? How does the round-trip data transfer rate compare to a wired, serial connection? Please include a useful plot (likely a histogram) related to the latency in your lab write-up.

Request a float

You can send commands using theRobot.sendCommand(cmd, length, data). If length and data are “don’t care” values, you may just send the command. For example, in main.py/myRobotTasks(), uncomment await theRobot.sendCommand(Commands.REQ_FLOAT) to request a float. In the Arduino sketch, your task is to put code in case REQ_FLOAT:. Put in a float that starts at (res_cmd->data). Review C data types and casting as necessary. (Update 19 Sep 2020: You may need to use memcpy(dstAddr, srcAddr, numBytes); depending on where exactly you end up putting your float. Misaligned memory accesses can cause hardfaults.) Replace TODO_VAL in the nearby amdtpsSendData((uint8_t *)res_cmd, TODO_VAL); with the number of bytes that you will send. If your code works, simpleHandler will unpack the float that you sent and print it. Does the float displayed to the screen match the float that you tried to send? What does this mean with regards to float comparision?

Test the Data Rate

You know (approximately) what the round-trip latency is. We also want you to get a feeling for the wireless data transfer rate is, and how reliable the connection is. You’ll get a decent sense of this by streaming bytes from the Artemis to your computer. In the main Arduino sketch, find the line if (bytestream_active). At the very least, send an example of a 32-bit integer and a 64-bit integer. A count and the result of micros() would be useful. On your setup, what is the (approximate) average time between packets sent? How often are packets dropped? Does the number of bytes sent make a difference? In your report, please include at least two useful figures (likely histograms) related to your data rate results. (Update 19 Sep 2020: See the note on memcpy(dstAddr, srcAddr, numBytes); It is idiomatic to pack structs with memcpy)

Optional for this lab: Reliable Data Transfer

Can you transfer a large (2KB or more) set of data to and from the Artemis board reliably over Bluetooth? Cite any outside sources and produce some reliability metric of your solution. Include summary graphics as necessary. How quickly can you transfer the data?

Best Practices

  • Keep individual calculations in loop() short. So long as everything fits in memory, the WSF OS should stay out of your way, for example, if you want to use the PDM. You could explore how to add tasks to WSF OS, but it isn’t necessary for this lab.
  • Devise efficient data structures.
  • For asyncio “concurrent” operation using asyncio.gather(), you should include await asyncio.sleep() calls in your tasks so that they can interleave. Otherwise, they won’t actually run concurrently.

Write-up

To demonstrate that you’ve successfully completed the lab, please upload a brief lab report (<800 words), with code snippets (not included in the word count), photos, and/or videos documenting that everything works and what you did to make it happen. Use the questions asked throughout this document to guide your report.