11. Embedded Networking and Communications¶
Weekly Assignment:¶
Group assignment:
- Send a message between two projects
- Document your work to the group work page and reflect on your individual page what you learned
Individual assignment:
- Design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output devices
XIAO ESP32C3 -- XIAO RP2040¶
For my individual assignment, I decided to combine my inputs and outputs weeks by having a XIAO ESP32C3 controlling a servo in communication with a XIAO RP2040 controlling the TTP223 touch sensor. The ultimate goal is for the servo to make a spin when the touch sensor senses my touch.
Coding¶
I first got each component to work seperately. Using Claude, I had it generate for me the suitable code for each part. Here is a public link to that conversation. This was the working code for the RP2040 (touch sensor):
```#define TOUCH_PIN D4 // GPIO4 for touch sensor
void setup() { Serial.begin(115200); Serial1.begin(9600); // RP2040 Serial1 uses pins 0 (TX) and 1 (RX) by default pinMode(TOUCH_PIN, INPUT);
delay(1000); // Give time for serial to initialize Serial.println("RP2040 Touch Sensor Ready"); }
void loop() { int touchValue = digitalRead(TOUCH_PIN); // Read sensor value Serial.println(touchValue); // Debug print
if (touchValue == HIGH) { Serial1.println("TOUCH"); // Send command to ESP32C3 Serial.println("Sent: TOUCH"); delay(500); // Debounce }
delay(100); // Small delay to reduce spam }
As commanded in the code, when the touch sensor senses touch, it should indicate that with the serial output of "TOUCH." When I uploaded it, that is what properly came up.
<video width="600" height="345" controls>
<source src="../../images/week12-networking/touchsensor.mp4" type="video/mp4">
</video>
This was the corresponding code for the ESP32C3 (servo):
``` #include <ESP32Servo.h>
#define SERVO_PIN D5 // GPIO6 for servo control
Servo myServo;
bool triggered = false;
unsigned long lastTriggerTime = 0;
void setup() {
Serial.begin(115200);
Serial1.begin(9600, SERIAL_8N1, 20, 21); // TX=21, RX=20 for ESP32C3
myServo.attach(SERVO_PIN);
myServo.write(0); // Initial position
delay(1000); // Give time for serial to initialize
Serial.println("ESP32C3 Servo Controller Ready");
}
void loop() {
if (Serial1.available()) {
String msg = Serial1.readStringUntil('\n');
msg.trim(); // Remove any trailing newline or whitespace
if (msg == "TOUCH") {
Serial.println("Touch received — spinning servo");
myServo.write(90); // Rotate servo
triggered = true;
lastTriggerTime = millis();
}
}
// Reset servo after 1 second
if (triggered && millis() - lastTriggerTime > 1000) {
myServo.write(0); // Return to start
triggered = false;
}
}
Breadboard and PCB¶
I then set up my breadboard. I planned on using UART (Universal Asynchronous Receiver-Transmitter) to communicate my two microcontrollers. That would be using the TX (transmit) and RX (receive) pins on the ESP32C3 and RP2040. The two important considerations when wiring were that 1) TX connects to RX 2) there must be shared grounds.
Once I uploaded the code for both microcontrollers, both serial monitors outputted the proper lines and the servo would spin when I touched the touch sensor.
With that, I started designing in KiCAD.
What I made a note of before was that is should be D6 to D6 (TX) and D7 to D7 (RX), which I got confused on for this board. In the ones above, its D6-D7 That's also why, spoiler alert, it didn't work.
Milled and soldered board.
However, when I uploaded the code, it would not work. It took a long time for me to realize that it was because of my UART connections.
So, I redesigned the board
to have the PROPER UART connections.
I milled and soldered that board.
And because the issues were not in the code I was using, it worked once I powered the two microcontrollers!
Group Assignment¶
The group assignment was to send a message between two projects. We chose to communicate between a touch sensor (my project) on a XIAO ESP32C3 and a servo motor (Amalia's project) on a XIAO ESP32S3. You can find our documentation here.
Individual Contribution¶
I worked on wiring the breadboard and coding the microcontrollers.
Breadboard¶
We first got the two microcontrollers connected on a breadboard.
Coding¶
We first used code to ensure the two microcontrollers could communicate with each other, checked with serial monitor.
For the C3:
void setup() {
Serial.begin(115200); // For debug
Serial1.begin(9600, SERIAL_8N1, 20, 21); // RX=20, TX=21
delay(1000);
}
void loop() {
Serial1.println("Hello from C3!");
Serial.println("Sent message to S3.");
delay(1000);
}
For the S3:
void setup() {
Serial.begin(115200); // For debug
Serial1.begin(9600, SERIAL_8N1, 44, 43); // RX=44, TX=43
}
void loop() {
if (Serial1.available()) {
String msg = Serial1.readStringUntil('\n');
Serial.print("Received: ");
Serial.println(msg);
}
}
This is a video of what it resulted in. In serial monitor, we were able to see the change in output when the sensor sensed touch, but the servo motor did not move. However, it was a step in the right direction.
Amalia suggested we use code that worked for the servo for our individual assignments and have Chat edit it be compatible with UART for networking. Here is a public link to the ChatGPT conversations for troubleshooting the coding.
This approach worked and this was the final code we used for the sender side, the touch sensor on the ESP32C3:
#define TOUCH_PIN D4 // GPIO5 for touch sensor
void setup() {
Serial.begin(115200);
Serial1.begin(9600, SERIAL_8N1, 20, 21); // TX=21, RX=20 — adjust as needed
pinMode(TOUCH_PIN, INPUT);
}
void loop() {
int touchValue = digitalRead(TOUCH_PIN); // Read sensor value
Serial.println(touchValue); // Debug print
if (touchValue == HIGH) {
Serial1.println("TOUCH"); // Send command to other ESP
Serial.println("Sent: TOUCH");
delay(500); // Debounce
}
delay(100); // Small delay to reduce spam
}
This was the final code we used for the receiver side, the servo motor on the ESP32S3:
#include <ESP32Servo.h>
#define SERVO_PIN D5 // Set this to your actual servo control pin
Servo myServo;
bool triggered = false;
unsigned long lastTriggerTime = 0;
void setup() {
Serial.begin(115200);
Serial1.begin(9600, SERIAL_8N1, 44, 43); // RX=44, TX=43
myServo.attach(SERVO_PIN);
myServo.write(0); // Initial position
}
void loop() {
if (Serial1.available()) {
String msg = Serial1.readStringUntil('\n');
msg.trim(); // Remove any trailing newline or whitespace
if (msg == "TOUCH") {
Serial.println("Touch received — spinning servo");
myServo.write(90); // Rotate servo
triggered = true;
lastTriggerTime = millis();
}
}
// Reset servo after 1 second
if (triggered && millis() - lastTriggerTime > 1000) {
myServo.write(0); // Return to start
triggered = false;
}
}
This is a video of these two pieces of code working to get the two microcontrollers in communication on the breadboard.
Overview¶
Overall this week was kind of a struggle because I have never done networking between microcontrollers before. But at least now I know how UART works, the TX and RX pin connections and shared ground. It was also kind of a puzzle figuring out how to design the PCB, given all the requirements to get networking to work. But in the process, I have definitely gotten more comfortable with electronics.
Files¶
Design:
Print: