In this assignment you will be practicing exchanging information between the PC and microcontroller.
Before attempting this assignment, make sure you go through the prelab 5 document first.
VSCode with PlatformIO Extension
MATLAB (Julia or Python also OK)
STM32 Nucleo F401RE Board
USB Type A to USB Mini-B Connector
Lab Report Submission Guidelines
For this assignment, it is suggested that you create a single project with multiple main*.cpp
files, inside the src folder, for each question below.
You only need to submit the (mainQ1.cpp
, mainQ2.cpp
, etc) files for this assignment. As well as the your PC client scripts (ScriptQ1.m
, ScriptQ2.m
)
To have one project with multiple source files, where you only compile one at a ime, you need to configure platformio.ini
to only compile the file you want. Replace the content of the platformio.ini
with this, then change mainQ1.cpp
to the file name you wish to compile. The last line (src_filter) basically tells the platformio configurator to remove all main*.cpp
from the compile list, then add only the specific mainQ1.cpp file. If we don't add this filter line, all the files inside the folder src will be compiled.
[env:nucleo_f401re]
platform = ststm32
board = nucleo_f401re
framework = arduino
src_filter = -<main*.cpp> +<mainQ1.cpp>
monitor_speed = 250000
lib_deps = bblanchon/ArduinoJson @ ^6.17.3
Parsing and Serializing Data between PC and MCU
You are given a MATLAB Script and a code template for the microcontroller. The MATLAB scripts emulates a GPS message and sends it to the microcontroller via the serial port in the following form:
$GPS,time,lat,lon,speed
%% Clear Open Ports - Might Crash Other Serial Devices
clear all
if ~isempty(instrfind)
fclose(instrfind);
delete(instrfind);
end
%%
% Motion Dynamics
dxdt = @(x)[x(3); x(4); 1*randn(1); 1*randn(1)];
dt = 0.1;
time = 0; x = zeros(4,1);
% Create Serial Object
mcuCom = serial('COM6','BaudRate',250000);
fopen(mcuCom);
counter = 0;
% Animated Line Plot
h1 = animatedline('LineWidth', 2, 'color', 'red', 'LineStyle', ':',...
'MaximumNumPoints',600);
hold on
% h2 = animatedline('LineWidth', 2, 'color', 'blue', 'LineStyle', ':',...
% 'MaximumNumPoints',600);
axis([0,400,-1,1]); grid on;
% xlabel('Time(s)')
setylabel = false;
% Flush First Line
flushinput(mcuCom)
while(1)
if(~ishghandle(h1))
delete(h2);
break;
end
% Simulate Motion and GPS Data
xdot = dxdt(x);
x = x + xdot * dt;
time = time + dt;
msg = "$GPS," + time + "," + x(1) + "," + x(2) + "," + norm(x(3:4));
% Forward GPS Message to MCU
fwrite(mcuCom, msg);
fprintf(mcuCom, ''); % For including a return line character
% Read Incoming Data and Print
if (get(mcuCom, 'BytesAvailable') > 0)
readline = fgetl(mcuCom);
dataJSON = jsondecode(readline);
addpoints(h1,dataJSON.latlon(1),dataJSON.latlon(2));
drawnow limitrate; % Faster animation
% Moving Axes [xmin xmax ymin ymax]
axis([dataJSON.latlon(1)-50 dataJSON.latlon(1)+50 ...
dataJSON.latlon(2)-50 dataJSON.latlon(2)+50])
if(~setylabel)
% ylabel(dataJSON.sensor);
setylabel = true;
end
end
pause(dt);
end
% We don't reach here...
fclose(mcuCom);
delete(mcuCom);
This is similar to the format of actual GPS sensor messages, but the units, length of message and additional info are different.
The job of the microcontroller is to parse the GPS message and save the parsed values into a local message struct. Then use JSON to serialize the message struct and send it back to the PC.
The MATLAB script will receive and decode the JSON messages from the microcontroller and then update an animated plot of a GPS position.
The MATLAB script is complete. Your task is to complete two parts in the microcontroller code:
Parse the GPS message received and save into the message struct.
The parsing is partially done for you, complete it. Look up the standard library functions strtok()
, and atof()
to understand how to parse a message.
Serialize the GPS message struct into a JSON object and send it back to the PC.
The prelab examples should be sufficient. Check the MATLAB script to confirm the order and format required for the message.
#include <Arduino.h>
#include <ArduinoJson.h>
struct gps_message_t {
String message_ID;
float time;
float lat;
float lon;
float speed;
}gps_message;
void setup() {
Serial.begin(250000); // opens serial port, sets data rate to 250kbps
}
void loop() {
StaticJsonDocument<200> doc;
if (Serial.available() > 0) {
// read the incoming number:
char buffer[200];
Serial.readBytesUntil('\n', buffer, 200);
/* TBC: Parse received message into gps_message struct */
char *pch;
pch = strtok(buffer,",");
gps_message.message_ID = (String) (pch+1);
pch = strtok(NULL,",");
gps_message.time = atof(pch);
/* - - - - - - - - */
/* TBC: Serialize gps_message into JSON */
/* - - - - - - - - */
serializeJson(doc, Serial);
/* At the end, we send a new line character to denote line termination */
Serial.println();
}
}