For this lab, using Terminal, I installed the latest releases of Python and pip. I also activated the virtual environment and installed the necessary Python packages using the command pip install numpy pyyaml colorama nest_asyncio bleak jupyterlab. Additionally, I started the Jupyter server. I then burned the ble_arduino.ino sketch onto the Artemis, after which the Artemis printed its MAC address to the serial monitor.
The codebase provided the necessary Python and Artemis code to establish a Bluetooth communication channel between my computer and the Artemis board. The MAC address of the Artemis and the BLEService UUID are declared in the file connection.yaml, allowing the computer to connect to the correct Artemis board. Command types are stored as enums in the file cmd_types.py and ble.py contains definitions for functions for handling BLE operations that allow data to be sent and received to and from the Artemis board.
I first updated the default MAC address of the Artemis with the address printed by my Artemis. Next, in both ble_arduino.ino and connections.yaml, I replaced the BLEService UUID with a new address generated by the command uuid4(). The screenshot below shows that the new MAC address was successfully used to establish a connection in demo.ipynb.
As seen in the screenshot below, I was able to run the given demo.ipynb file succesfully.
The Artemis was able to receive the two integers and print them to the serial monitor.
For this task, I create a case ECHO in the function handle_commands() in the ble_arduino.ino file, which when called from the Python end using the function send_command, appends the characters “:)” to the input and sends the augmented string as a response.
For this task, I create a case GET_TIME_MILLIS in the function handle_commands() in the ble_arduino.ino file, which when called from the Python end, appends sends the time in milliseconds, found using the function millis(), in the form “T:time” in response.
I set up a notification handler in Python to receive the string values the Artemis board sends in response to commands from the Python end. I defined a callback function callback(uuid,byte_array) that converts the received byte array of a characteristic string with a particular UUID into a string. To extract the time from the string, I sliced it to remove the first two characters. Then, to start notifications, I called the function start_notify with the UUID of the characteristic string and the callback function as parameters. Next, I sent the GET_TIME_MILLIS command from the Python end to the Artemis, and I was able to print the received string without calling the function receive_string, showing that the notification handler worked. Finally, I called the function stop_notify to cease notifications. No code was added on the Arduino end.
For this task, I create a case GET_TEMP_5s in the function handle_commands() in the ble_arduino.ino file, which when called from the Python end, sends a string with 5 timestamped internal die temperature readings (in Celsius), with the readings being taken once per second for five seconds. This string was created by appending a time reading, found using the function millis(), and a temperature reading, found using the function getTempDegC(), to the characteristic string five times using a loop, with each loop separated by a 1000 millisecond delay.
On the Python end, I added a notification handler the same way as in the section above. I used the same callback function to start notifications, sent the GET_TEMP_5s command, printed the string, and stopped notifications.
For this task, I create a case GET_TEMP_5s_RAPID in the function handle_commands() in the ble_arduino.ino file, which when called from the Python end, rapidly sends timestamped internal die temperature readings (in Celsius), all taken within 5 seconds. In the code for this case, a while loop is run for 5000 milliseconds, or 5 seconds, during which time as many timestamped temperature readings as possible are sent. There is also a 10 millisecond delay between samples to prevent duplicate samples from being sent.
On the Python end, I modified my existing callback function to append each received string to a list to create a list of timestamped temperature readings. I then used that callback function to start notifications, sent the GET_TEMP_5s_RAPID command, printed the string, printed the length of the list to verify that more than 50 samples were collected, and stopped notifications.
One second of a 16-bit values sent at 150 Hz would take 2400 bits of memory, or 0.3 kB. This means that 384 kB of RAM could store 384/0.3 = 1280 seconds, or 21 minutes and 20 seconds, of 16-bit values at 150 Hz. However, this is assuming that all of the space on the RAM is available, but in reality, the amount of data that can be stored is probably less than the calculated value.