Week 14
Networking and Communications
- Send a message between two projects
Networking and Communications
For this week's group assignment, we are sending a message between two projects.
Introduction
We chose to use the UART communication protocol for this week's assignment between Victor Montano's control circuit, which serves as the brain for a neopixel strip, and Emilio Cruz's glove circuit, which features flex sensors on his fingers. The idea is that when the flex sensors change, the color of the neopixels changes.
UART communication is a communication protocol that permits the exchange of data between two MCUs. It uses at least two communication pins (RX and TX), which means reception and transmission and the reference GND pin. This implies that it operates in full-duplex mode, enabling simultaneous sending and receiving. It can also have a clock signal, making synchronous communication possible. Since we are operating autonomously, the speed and format of our messages will remain consistent. This ensures that there are no issues with misdirected messages.
Process
To start this process, you need wiring. In Emilio's case, we are simply using a couple of fingers, which correspond to the wiring in the following image.
Next, we perform Victor's wiring, which consists of a neopixel strip, as depicted in the accompanying image.
Ultimately, we must conduct wiring between the two MCUs, as depicted in the image below, while considering the crossing of TX and RX. This is important because when one transmits, the other must receive. As emilio didnt have a pin header on his UART pins, we soldered a couple of jumper wires fro this connection.
With the wiring planned, let's focus on the programming. The plan is the following: We will send a command from the glove circuit in the following format: "P# R# M# T#/n", where "P" represents the pinkie, ring, middle, and thumb fingers, and the # represents the reading from the flex sensor.
Here is the full code that sends the command every second:
#define ANALOG_PIN_P A0
#define ANALOG_PIN_R D1
#define ANALOG_PIN_M D2
#define ANALOG_PIN_T D3
void setup() {
Serial.begin(115200);
}
void loop() {
// Read analog values
int analogValueP = analogRead(ANALOG_PIN_P);
int analogValueR = analogRead(ANALOG_PIN_R);
int analogValueM = analogRead(ANALOG_PIN_M);
int analogValueT = analogRead(ANALOG_PIN_T);
// Convert the analog values to a command string
String command = "P" + String(analogValueP) + " R" + String(analogValueR) + " M" + String(analogValueM) + " T" + String(analogValueT) + "\n";
// Send the command over Serial
sendCommand(command);
// Wait before sending the next command
delay(1000);
}
void sendCommand(String command) {
int len = command.length();
char charArray[len + 1];
command.toCharArray(charArray, len + 1);
Serial.write(charArray, len);
}
On Victor's board, we must receive the command and separate the data into something usable. First, we need to detect when our command finishes. So we will use the command "Serial.readStringUntil('\n');" which will read all the characters sent by UART. This is because UART communication sends 1 byte of information at a time, so it doesn't send all characters at the same time; it only sends one character at a time. Using the command, we will read each character and add it to a string until it encounters a newline character.
After that, we work with the string. Ultimately, the string transforms into an array. We retrieve the index position of each finger letter, segment it up to the space character in the string, and then extract each value and check if it's a valid numerical value. Next, we'll convert it into a color and send it to the neopixel strip.
The code can be seen here:
#include Adafruit_NeoPixel.h
/********Definiciones*********/
#define LED_PIN 9
#define LED_NUMBER 4
/********Variables*********/
/*Used for commands*/
String cmd_python = "";
/*Used in string partition*/
int indexP = -1;
int indexR = -1;
int indexM = -1;
int indexT = -1;
enum error_type {
INCOMPLETE,
UNKNOWN,
INVALID
};
/********Funciones*********/
void ERROR(error_type error);
bool isValidNumber(String str);
void setLedColor(int ledIndex, int colorValue);
/**************************/
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_NUMBER, LED_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(115200);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
if (Serial.available()>0) {
cmd_python = Serial.readStringUntil('\n');
Serial.println(cmd_python);
indexP = cmd_python.indexOf('P'); // PINKY
indexR = cmd_python.indexOf('R'); // RING
indexM = cmd_python.indexOf('M'); // MIDDLE
indexT = cmd_python.indexOf('T'); // THUMB
if (indexP != -1) {
int endP = cmd_python.indexOf(' ', indexP);
if (endP == -1) endP = cmd_python.length();
String numberP = cmd_python.substring(indexP + 1, endP);
if (isValidNumber(numberP)) {
int colorValueP = numberP.toInt();
setLedColor(0, colorValueP);
} else {
ERROR(INVALID);
return;
}
}
if (indexR != -1) {
int endR = cmd_python.indexOf(' ', indexR);
if (endR == -1) endR = cmd_python.length();
String numberR = cmd_python.substring(indexR + 1, endR);
if (isValidNumber(numberR)) {
int colorValueR = numberR.toInt();
setLedColor(1, colorValueR);
} else {
ERROR(INVALID);
return;
}
}
if (indexM != -1) {
int endM = cmd_python.indexOf(' ', indexM);
if (endM == -1) endM = cmd_python.length();
String numberM = cmd_python.substring(indexM + 1, endM);
if (isValidNumber(numberM)) {
int colorValueM = numberM.toInt();
setLedColor(2, colorValueM);
} else {
ERROR(INVALID);
return;
}
}
if (indexT != -1) {
int endT = cmd_python.indexOf(' ', indexT);
if (endT == -1) endT = cmd_python.length();
String numberT = cmd_python.substring(indexT + 1, endT);
if (isValidNumber(numberT)) {
int colorValueT = numberT.toInt();
setLedColor(3, colorValueT);
} else {
ERROR(INVALID);
return;
}
}
strip.show(); // Update the LED strip to show new colors
}
}
bool isValidNumber(String str) {
for (int i = 0; i < str.length(); i++) {
if (!isDigit(str[i])) {
return false;
}
}
return true;
}
void setLedColor(int ledIndex, int colorValue) {
// Convert the value from 0-1023 to 0-255 for RGB components
int red = (colorValue >> 2) & 0xFF; // Scale down to 8 bits
int green = ((colorValue >> 1) & 0xFF) - 128; // Scale down and shift
int blue = colorValue & 0xFF; // Lowest 8 bits
strip.setPixelColor(ledIndex, strip.Color(red, green, blue));
}
void ERROR(error_type error) {
switch (error) {
case INCOMPLETE:
Serial.println("Your Command is incomplete");
break;
case UNKNOWN:
Serial.println("Unknown Command");
break;
case INVALID:
Serial.println("Invalid Value at Command");
break;
}
}