LinuxCNC on Raspberry Pi With GPIO Control
by audioartillery in Workshop > CNC
1194 Views, 14 Favorites, 0 Comments
LinuxCNC on Raspberry Pi With GPIO Control

This article is about using LinuxCNC on Raspberry Pi microcomputers for control of a CNC machine. It will specifically focus on direct control of CNC machine stepper motors with the Raspberry Pi I/O pins (as opposed to with an Ethernet based control board such as Mesa).
LinuxCNC is a free, open source, and industrial strength set of CNC software that can be used to control any CNC machine. It is available as Debian-based release images that contain a real-time Linux kernel and all the LinuxCNC software utilities.
Raspberry Pi's are ARM based boards capable of running Linux and are suitable for a variety of computing needs. They are cheap and easy to set up. And for the purposes of this article, they have a bank of GPIO pins suitable for controlling CNC machines.
Supplies

You will need:
- Raspberry Pi 5 (4 GB version is fine)
- Widely available.
- A Pi 4 will probably work, but I have not verified it can keep up with the CPU load.
- Small heat sink for the Pi (recommended)
- Example
- 40mm fan that plugs into the Pi (optional)
- Example
- Micro SD card
- Byte2Bot Parallel Hat
- Stepper motor breakout board such as either of these:
- A C10 6-axis breakout board (these are very common).
- This 5 axis breakout board. Byte2Bot has a 3d printable bracket to combine the hat and this breakout board, which is convenient.
- 25-pin parallel (printer) cable (optional)
- You can plug the hat and breakout board together, if you're happy with that configuration from a mechanical point of view.
- A CNC machine with stepper motors
System Overview

This is a brief overview of out a basic CNC machine is controlled. You can skip this if you know what you're doing.
- Each axis has a step signal and a direction signal. These control signals originate from software on the controlling computer (in our case, the LinuxCNC gcode interpreter running on the Pi).
- These 2 signals for each axis (6 total for a basic 3 axis machine) are output on GPIO pins on the Pi.
- These signals are routed to the parallel hat which performs two functions:
- Converting the Pi's 3.3VDC I/O signaling to 5V which is appropriate on a parallel port.
- Routing I/O pins to a DB25 connector which is used for parallel ports.
- The signals then (via parallel cable/connector) are further amplified and isolated in the breakout board.
- The signals are then routed to stepper motor drivers which are capable of driving high amounts of current suitable for driving a stepper motor.
- Finally, the signals are driven to the stepper motors themselves to cause them to move.
A couple notes:
First, the usage of a parallel port is due to historical tradition. In the old days every computer had a parallel port for communicating with printers and these massive DB25 cables were used to connect the printer to the cable. They were also adopted for CNC control because the parallel ports in computers were capable of outputting data on multiple pins coherently. This is important because you want your CNC machine's axes to work in conjunction with each other, not stepping sequentially. Thus breakout boards were invented to split the parallel cable's pins out so they could be wired to drivers.
Second, while I like the separation of the breakout board from the computer, there does exist Raspberry Pi hats that have breakout board functionality, essentially combining the parallel hat and the breakout board. This will work just as well.
Set Up Raspberry Pi
Get an image from LinuxCNC.org. I used this one for Raspberry Pi 5. Note that the downloads page will have newer images over time. Raspberry Pi has a Raspberry Pi Imager utility that you can use to flash this onto an SD card, but you can also just use dd to copy it directly to the SD card. There's lots of instructions about setting up Raspberry Pi's out there.
Once flashed, boot it up and:
- Log in. User and password are both "cnc".
- Run "sudo menu-config" in a terminal and configure wifi. I couldn't find a normal GUI way to configure this.
- Follow the instructions here to configure permissions/rules for GPIO usage.
In case you're wondering, LinuxCNC's image has XFCE4 configured as the window manager. This is a decent choice, but if you can't figure out how to configure it, XFCE4 is the thing to search for.
Determine Pin Usage and Mappings

Things are going to get a little confusing here. Refer to the system diagram in a previous step. At every point in this chain of components the X, Y, and Z step and direction signals exist. But they are referred to differently at each point.
- We will need to tell LinuxCNC which signals to map to which GPIO pins, and to do that:
- We need to know which GPIO pins to map to which DB25 connector pins, and to do that:
- We need to know which DB25 connector pins are connected to which stepper driver terminals.
This is a very simple thing to figure out, but it's worth getting organized and labelling things and/or writing down a table that describes the mapping. Below is an example table for my machine:
# +----------+----------+----------+----------------+
# | Function | Rpi GPIO | Rpi pin | DB25 connector |
# +----------+----------+----------+----------------+
# | E-stop | | | |
# | X step | GPIO17 | PIN11 | pin 8 |
# | X dir | GPIO23 | PIN16 | pin 9 |
# | Y step | GPIO6 | PIN31 | pin 6 |
# | Y dir | GPIO19 | PIN35 | pin 7 |
# | Z step | GPIO11 | PIN23 | pin 4 |
# | Z dir | GPIO5 | PIN29 | pin 5 |
# +----------+----------+----------+----------------+
Refer to the Byte2Bot parallel port documentation for a schematic of how the DB25 pins are routed to Raspberry Pi pins.
Create a LinuxCNC Configuration
You may find Byte2Bot's video helpful for this step. They make the parallel port hat used in this project and have a video explaining the configuration.
First, generate a configuration.
- Start LinuxCNC StepConf.
- Give it a name.
- You won't be able to directly configure Raspberry Pi GPIO pins directly. Instead, choose pins as if you're talking directly to a parallel port and mark down the DB25 connector pins you want to use.
- Enter all parameters for the machine that you able to. Don't worry, we're going to edit the resulting files anyways so you can fix things up. But key parameters are:
- The scale for each axis. This is steps per linear unit and is derived from the pitch of your drive screws.
- The range of each axis.
Next we will modify the configuration by editing the .hal file in /home/cnc/linuxcnc/configs/[your config name]/[your config name.hal]. Refer to the Byte2Bot parallel port documentation as it will have a reference HAL file which I used to piece together what needed to be done in my .hal file.
Next:
Add some load commands referenced in the Byte2Bot .hal file. But the GPIO's need to match the ones you're using.
Note that these output pins are the ones you determined in the previous step. That command enables them as outputs. The reset list is supposed to enable some pin options for the step pins but I didn't find that actually worked. Also note that it is possible to have conflicts depending on which pins you end up using.
Replace the "net" descriptions that referenced parallel port pins with hal_gpio pins:
One gotcha I struggled with is the actual naming of GPIO pins. I had referred to GPIO6 as GPIO06 (zero prefix) and that doesn't work and is difficult to diagnose.
Remove any other references to "parport". Any command in the .hal file that is mentioning the parallel port likely needs to be removed.
Plug Everything Together and Test

Reference the system diagram and wire everything up as you intended. Power everything up.
You should have a LinuxCNC shortcut for the configuration you created. Load it. The program loaded by default is AXIS and it has a great GUI as well as a direct gcode interface. In the upper left are two buttons. You will need to enable both of them to be able to move your motors.
Verify all axes move, move in the correct direction, and move the correct distance.
If an axis moves the wrong direction, change the scale value for the axis to be negative.
If an axis moves the wrong distance, correct the scale value for the axis.
If an axis does not move, verify the pin mapping is correct.
Note: AXIS will note any errors and not launch if there is something wrong. Don't worry, this absolutely will work in the end, but the configuration files are easy to get wrong. Go back to the Byte2Bot reference configuration. It won't necessarily just work but it's a good reference.
LinuxCNC also has a latency test utility which you can run to verify the system is keeping up.
Thermal Considerations

The parallel hat used for this project is well designed and works great... but it also blocks most of the airflow over the Raspberry Pi CPU. And you can't just stack a fan on it because the hat is in the way.
Absolutely do put a heat sink on the Pi CPU.
The optional fan is tricky to mount in this configuration but it will keep things cooler. I designed a printable case to help with this and it seems to work well. If I can get it cleaned up a bit I will link to it here.
The good news is LinuxCNC is not a demanding application. If all you're doing is cutting parts you'll be fine. If you want to watch videos or play games while the machine is running you may get thermal throttled.
Accuracy and Performance Considerations






You may have heard that a Raspberry Pi can't directly control stepper motors and you need an ethernet based controller (Mesa etc) or an MCU based controller (Arduino, etc).
As far as I can tell, this is not true. However it is worth digging into the details around performance. This thread has some brief discussion about this and the limits of of the GPIO subsystem in terms of update rate. The maximum update rate will limit how fast you can turn your stepper motors and thus the speed of the machine. It's said in this thread the maximum update rate is 5 kHz.
As a first step I collected some oscilloscope captures of the step pins at different linear rates. My shallow analysis is as follows.
First two photos were captures using g1 x5 y5 z5 f200 (200 ipm move on all axes). That yielded 5 kHz (200us period) pulses on the X axis but as you can see those pulses were in groups of 5 and the groups were delayed from each other by about 110us. This is bad. Also while I have not done the math, I don't think 5 kHz pulses will result in 200 ipm on my machine (TODO figure this out -- machine configuration is 2032 steps per inch). I think this capture confirms the Pi 5 cannot toggle GPIO faster than 5 kHz, and that LinuxCNC can't drive the GPIO at that rate for some unknown to me reason.
The 3rd photo is at 100 ipm which seems to be around 3.25 kHz. Some jitter is still apparent but you can't see that grouping of 5 pulses any longer.
The 4th photo shows relative jitter between X and Y axes at 100 ipm.
The 5th photo shows the jitter between X and Y axes at 60 ipm.
The 6th photo shows a 0.01" movement on the X axis at 100 ipm using 20 steps. This shows LinuxCNC enforcing acceleration limits (starting slow, speeding up, then slowing down at the end).
Well, what to make of all this? To be honest: I'm not sure. Obviously, the step patterns being output are not perfect. In the context of a physical machine with inertia and ~2000 steps to move one inch on my machine this is clearly in the noise at the linear speeds I normally cut parts with.
Open Issues
This is my TODO list for this project.
- Publish 3d printable case used in this project.