PicoMatic
A compact CNC plotter controlled by a Raspberry Pi Pico 2W, moving a pencil in 3 axes (X, Y, Z) using stepper motors and drivers.
Author: Aliwi Walid
GitHub Project Link: https://github.com/UPB-PMRust-Students/project-AliwiWalid
Descriptionβ
This project consists of building a CNC plotter machine that uses a pencil as its tool head. It is designed to move across three axes: X, Y, and Z, using stepper motors and motor drivers. The system is controlled by a Raspberry Pi Pico 2W microcontroller, which receives G-code commands via USB serial communication. The commands are parsed on the Pico and translated into precise movements of the motors, allowing the machine to draw complex shapes automatically on paper. An external power supply is used to power the motors, providing enough current without overloading the Pico.
Motivationβ
Initially I wanted to build a 3D printer, but due to the high cost, complexity and potential dangers with heating elements and mechanical failures, I decided to scale down the project to something safer and more achievable in the desired price range. The goal remained to build something which involves motion control and automation, where mechanical movement is precisely driven by software. And that is how I ended up choosing the CNC plotter as my project idea, as it shares a bunch of fundamental principles with a 3D printer, but clearly a lot cheaper and safer to build at home. This will help me continue my journey of learning about embedded programming and real time systems.
Architectureβ
Logβ
Week 5 β 11 Mayβ
Since I had a clear idea of my project well before Week 7 and had already received approval, I ordered all the necessary components from AliExpress. This week, I 3D printed the structure of the CNC plotter and assembled the mechanical frame. I also created the initial architecture schematic and began researching which Rust crates I would need for motor control, serial communication, and other core features. One obstacle I encountered was that the STL file source I used did not specify the required screw sizes, which delayed the mechanical assembly. Here's how the build looked at this stage:
Week 12 β 18 Mayβ
This week, I secured all the components to the CNC structure using the correct screws and mounted everything onto a wooden base to give it a solid foundation. I also decided to add an LCD screen to the project, which will display the current status while the CNC is running, such as when it's starting, drawing, or finished. I updated the system architecture and KiCad schematics to include this new addition.
On the software side, I wrote the initial code to allow the CNC to draw basic shapes like squares. It's a good starting point, but Iβll continue improving it so the machine can handle more complex drawings in the coming updates.
Week 19 - 25 Mayβ
This week, i completed the code. I wrote the logic for all the GCode commands that i might use for my CNC, tested it on more complex drawings to make sure it can now draw arcs and full circles also using bresenham's algorithm, as suggested by my professor. I also completed the code for the display interface. To make it look better, i added a cardboard that will cover the wiring where there will also be a cutout for the display.
Hardwareβ
3Γ 28BYJ-48 Stepper Motors Each stepper motor is used to drive movement along one of the three axesβX, Y, and Z. They are each controlled by a dedicated ULN2003 driver board, with signal lines connected to the Raspberry Pi Pico via GPIO as follows:
Stepper 1: GPIO 15, 14, 16, 17
Stepper 2: GPIO 18, 19, 13, 12
Stepper 3: GPIO 20, 21, 11, 10
1Γ 1.8 Inch LCD (ST7735, SPI) Used to display messages like βCNC starting to plotβ¦β, βCNC plottingβ¦β, and βCNC has finished plotting!β. Connected to the Raspberry Pi Pico via SPI0 as follows:
MOSI: GPIO 3
SCK: GPIO 2
DC (A0): GPIO 6
RESET: GPIO 7
CS: GPIO 5
VCC and GND connected to 3.3V and GND respectively.
CH340G USB-to-UART Converter This module establishes serial communication between the Raspberry Pi Pico and a host computer. It is used to send G-code commands from the host (via a Python script) to the Pico for real-time stepper control. The pin connections are:
CH340G TX β Pico GPIO 1 (UART0 RX)
CH340G RX β Pico GPIO 0 (UART0 TX)
External Power Supply A separate 5V external power source is used to power the stepper motors through the ULN2003 driver boards. This is necessary to avoid overloading the Raspberry Pi Pico, which cannot provide sufficient current for motor operation. Ground from the external power supply is tied to the system ground to ensure a common reference.
Here is what the hardware is looking like so far:
Schematicsβ
KiCad Schematic
Bill of Materialsβ
Device | Usage | Price |
---|---|---|
Raspberry Pi Pico 2W | The microcontroller | 39.66 RON |
Debug Probe | The debug probe | 66.17 RON |
CH340G | The USB to UART convertor | 2.52 RON |
28BYJ-48 + ULN2003 | Stepper motors + drivers | 27.1 RON for a set of 3 |
Male to male/female jumper wires | Wires | 0.1 * 23 = 2.3 RON |
Breadboard Power Supply + battery | External power for motors | 4.69 RON |
1.8 inch TFT LCD ST7735 | LCD Display | 4.42 RON |
Softwareβ
Library | Description | Usage |
---|---|---|
embassy-executor | Async/await executor optimized for embedded systems | Runs asynchronous tasks without an OS |
embassy-embedded-hal | Collection of utilities to use embedded-hal and embedded-storage traits with Embassy | Used for shared SPI communication |
embassy-time | Timekeeping, delays, and timeouts | Used for non-blocking delays and timeouts |
embassy-sync | no-std, no-alloc synchronization primitives with async support. | Used to create a mutex for sharing the SPI bus |
embassy-rp | Library for peripheral access | Interfaces with RP2350 peripherals (GPIO, UART, etc.) |
defmt | Lightweight and efficient logging framework for embedded systems | Provides low-overhead debug output |
defmt-rtt | RTT backend for defmt logging | Sends logs from device to host over RTT |
heapless | static -friendly data structures without heap allocation | Used for queues, buffers, and collections without alloc |
cortex-m-rt | Minimal runtime for Cortex-M microcontrollers | Sets up vector table, stack, and entry point |
embedded-graphics | 2D graphics library that is focused on memory constrained embedded devices | Used to display the messages on the LCD |
libm | A Rust implementations of the C math library | Used to calculate the coordinates of points along the circle's circumference |
beresenham | Iterator-based integer-only implementation of Bresenham's line algorithm | Used to calculate points along arcs and circles |
mipidsi | MIPI Display Command Set compatible generic driver | Crate used to initalize the ST7735 display |
display-interface-spi | SPI implementation for display interfaces | Used for implementing the interface of the ST7735 |
Pythonβ
Library | Description | Usage |
---|---|---|
time | This module provides various functions to manipulate time values. | Used to pause the program for 4 seconds between sending each G-code command. |
serial | Allows communication with devices over a serial port (e.g., USB, UART) | Used to open a connection to the CNC machine via a specified serial port. |