Lab 5 - Communications

Overview

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.

Tools Required

References

  1. REF03 STM32 Nucleo-64 boards User Manual

  2. REF01 STM32F401RE Datasheet

  3. REF02 STM32F401RE Reference Manual

  4. Lab Report Submission Guidelines

  5. ME319 Prelab 5

Project Creation & Submission

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

Questions

  1. 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:

  1. 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.

  2. 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();
 
    }
}