Controller Area Network (CAN) is a robust, reliable, and real-time communication protocol widely used in industrial automation and embedded systems. CAN enables multiple nodes to communicate over a single two-wire bus without requiring any central host. A CAN node can be any independent sensor or actuator unit. CAN networks are extensively used in process automation, industrial machinery, and robotic systems. It has very high noise immunity and requires only two wires for communication.
My project involves a CAN network where there will be an ESP32-based CAN node and a CAN gateway based on Arduino UNO Q and MAX33041E CAN transceiver shield from Analog Devices. The ESP32-based node collects sensor data and transmits it over the CAN bus to the central CAN gateway.
The ESP32 has a built-in CAN bus-compatible controller as TWAI which stands for Two-Wire Automotive Interface, it doesn’t have a built-in CAN transceiver, so we must use an external one to connect to a CAN network. So, in my project, I am using the MCP2551 CAN transceiver module to make a CAN node using an ESP32 microcontroller. The MCP2551 transceiver converts the CAN controller's digital TX/RX signals into the differential CANH/CANL bus signals.
I connected the VCC pin of the MCP2551 module to the VIN of the ESP32. Then, connect the GND pin to the ground. Next, connect the TX to GPIO5 and the RX to GPIO4 on the ESP32.
The next step is to connect the CAN Bus High and CAN Bus Low signals to the bus. I connected the CANH and CANL signals directly to the screw terminal on the MAX33041 Shield Evaluation Kit.
For programming the ESP32 module for CAN communication, I installed the following library:

For sending the test message on the CAN bus, I used the following test code.
#include <CAN.h>
#define TX_GPIO_NUM 5
#define RX_GPIO_NUM 4
void setup() {
Serial.begin (115200);
while (!Serial);
delay (1000);
Serial.println ("CAN Sender");
// Set the pins
CAN.setPins (RX_GPIO_NUM, TX_GPIO_NUM);
// start the CAN bus at 500 kbps
if (!CAN.begin(500E3)) {
Serial.println("Starting CAN failed!");
while (1);
}
}
void loop() {
// send packet: id is 11 bits, packet can contain up to 8 bytes of data
Serial.print("Sending packet ... ");
CAN.beginPacket(0x12);
CAN.write('h');
CAN.write('e');
CAN.write('l');
CAN.write('l');
CAN.write('o');
CAN.endPacket();
Serial.println("done");
delay(1000);
// send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
Serial.print("Sending extended packet ... ");
CAN.beginExtendedPacket(0xabcdef);
CAN.write('w');
CAN.write('o');
CAN.write('r');
CAN.write('l');
CAN.write('d');
CAN.endPacket();
Serial.println("done");
delay(1000);
}