# How to directly send G-code to printer from a Linux terminal?

Should it be possible to directly send G-code to the printer serial connection using pipes under Linux?

Example:

echo M106 > /dev/ttyUSB0


My controller runs at 250000 baud, I have tried setting the TTY baud rate to 250 kBd with:

stty -F /dev/ttyUSB0 250000


But, unfortunately, this particular baud rate appears to be unsupported under Ubuntu, giving the error:

stty: invalid argument ‘250000’


For direct low-level printer control from a terminal, without specific software, I found the following solution with full credit thanks to user: http://stackexchange.com/users/6463673/meuh

Sharing here as may be of use to other users in the 3d Printing community, and I was unable to source a "complete" solution to this elsewhere.

Step 1) Create a custom python script that allows you to set arbitrary baud rates (make executable with chmod u+x).

#!/usr/bin/python
# set nonstandard baudrate. Original Question: http://unix.stackexchange.com/a/327366/119298
import sys,array,fcntl

# from /usr/lib/python2.7/site-packages/serial/serialposix.py
# /usr/include/asm-generic/termbits.h for struct termios2
#  [2]c_cflag [9]c_ispeed [10]c_ospeed
def set_special_baudrate(fd, baudrate):
TCGETS2 = 0x802C542A
TCSETS2 = 0x402C542B
BOTHER = 0o010000
CBAUD = 0o010017
buf = array.array('i', [0] * 64) # is 44 really
fcntl.ioctl(fd, TCGETS2, buf)
buf[2] &= ~CBAUD
buf[2] |= BOTHER
buf[9] = buf[10] = baudrate
assert(fcntl.ioctl(fd, TCSETS2, buf)==0)
fcntl.ioctl(fd, TCGETS2, buf)
if buf[9]!=baudrate or buf[10]!=baudrate:
print("failed. speed is %d %d" % (buf[9],buf[10]))
sys.exit(1)

set_special_baudrate(0, int(sys.argv[1]))


Step 2) Run the script to set your baud rate.
./set_custom_baud_rate.py <> /dev/ttyUSB0 250000

Step 3) You can now monitor your printer output in a terminal window simply with:
tail -f /dev/ttyUSB0

Step 4) And finally, open up a new terminal window, and you can directly send M or Gcode to your printer; example:
echo "M115" >> /dev/ttyUSB0

• Can I ask you how is possible that this script works? I don't understand why you use <>, at first I thought was a typo, but modifying the script and opening the serial directly doesn't modify its baudrate. – gipi Jul 13 '17 at 13:15
• <> on unix opens a file read+write mode, without truncation, and creates the file if it doesn't already exist. i.e system call: open(filename, O_RDWR|O_CREAT) – Mtl Dev Jul 13 '17 at 13:56
• For example, cat < foo.txt it will print the contents of foo.txt, or fail if foo.txt doesn't exist. Whereas cat <> foo.txt,will also print the contents if it exists, but will create the file if it doesn't already exist. – Mtl Dev Jul 13 '17 at 13:59
• I know what <> does, but I don't understand why this works for the baudrate: you are setting the baudrate of the file descriptor 0, i.e. stdin not for the serial port. – gipi Jul 13 '17 at 15:42
• My understanding is the baudrate is simply the first argument to the script, (i.e sys.argv[1]). If you were to modify the script and hardcode a baudrate, and/or open device using the python equiv. of open(filename, O_RDWR|O_CREAT), then I, too, would be surprised if that didn't work. – Mtl Dev Jul 13 '17 at 18:25

you can use screen for that. Open a terminal window and type screen /dev/ttyUSB0 115200 The general form is screen serialdevice baudrate You will then see everything that the printer sends. Everything you type will be send to the printer.

• Thanks! Though does that work with non standard baud rates e.g 250k? I suspect not (at least with Ubuntu/Mint), but that it would be possible to combine the above script, with screen command as per your suggestion. – Mtl Dev Jul 13 '17 at 14:02

This forum page strongly suggests you should be using setserial for a port, not stty , which is for terminals. I'd give the code snippets there a try. Alternatively, stackoverflow has a similar discussion, with somewhat more complicated modifications.

Are you sure you can't talk with your printer at a lower baud rate than the maximum capability of the printer-end?

• You can't lower Marlin's baudrate without recompiling the firmware, I believe. – Tom van der Zanden Dec 1 '16 at 15:23
• @TomvanderZanden bummer :-( – Carl Witthoft Dec 1 '16 at 15:24

I spent a number of hours trying to work out why my Creality Ender Pro was ignoring me when I sent it serial data over USB from a Python app. Google searches trying to find a solution that were not talking about encode() and decode() all seemed to lead me to this thread.

I installed Minicom as per the video link, and all worked as it should, but I still failed to receive a reply in my Python implementation, I could connect and read the serial sent from the printer but nothing append when sending back to it.

After a few hours scratching my head I realised that the printer reacted to input as it received each new line \n character that I was failing to add to the end of each command sent so the printer was just sitting waiting for me to finish transmitting my line end that never came.

self.serialPort = serial.Serial('/dev/ttyUSB0', 115200, exclusive = True)
line = line + "\n"
self.serialPort.write(line.encode())


Hopefully no one else is as stupid but to save anyone else like me time, I would like to point this out here.

• This is sort of "me too" answer reacting on some other answer. Which link are you referring to? This answer could be better posted as a comment to that answer. – 0scar Sep 5 '20 at 13:29
• i tried to move it but it said "you must have 50 rep to comment" – Jay Dee Sep 9 '20 at 11:10
• Please shorten the answer and indicate to which answer you'd like to respond in a comment, moderators can move it for you. – 0scar Sep 9 '20 at 11:16

The accepted answer didn't work for me. Everything received on the serial port was repeated back to the serial port, sending the printer into a confusing loop. There is more information about that in this answer: https://unix.stackexchange.com/questions/42964/unexpected-results-testing-serial-loopback-using-echo-and-cat

The key is to use a command like this to prevent certain line termination characters from repeating themselves: stty 115200 -F /dev/ttyUSB0 -echo -onlcr , where 115200 is your baud rate.

Here is what I did:

# 1. plug in printer
sudo chmod +777 /dev/ttyUSB0 # 2. allow access to printer USB permissions, add user to dialout or tty is better
stty 115200 -F /dev/ttyUSB0 -echo -onlcr # 3. set serial port baud rate, might be 250000 for you
cat -v < /dev/ttyUSB0 # 4. get printer output



Then in a new terminal:

   echo "M119" >> /dev/ttyUSB0



This will give you a real console.

• Can you please share what flavour & version on linux you are using that this failed on? (It worked on mainstream distributions - Ubuntu & Mint - at time of publishing. Perhaps we can isolate why it wasn't successful for you. I note your solution is for baud rate 115200, are you able to verify this works for baud rate 250000? – Mtl Dev Nov 9 '20 at 3:39
• But the accepted answer also doesn't work for me on 250000 either – K Mmmm Nov 9 '20 at 16:22
• The accepted answer works when using cat -v < /dev/ttyUSB0 instead of tail -f /dev/ttyUSB on 250000 though – K Mmmm Nov 9 '20 at 16:23
• Can confirm the previous answer works on Ubuntu 18.04, and IIRC Mint before that (version unknown, formatted). Not sure why it's failing on 16.04. Thankyou kindly for posting another answer that works for you and other people - always great to have multiple working answers to help as many people as possible, cheers! – Mtl Dev Nov 9 '20 at 20:14
• 250000 is a non standard baud rate. In my case, 115200 works find with standard linux tools - but in order for 250000 to work, I needed that script posted in my answer. On my machines, 250000 works with that script. – Mtl Dev Nov 10 '20 at 23:26

That's work solution:

you need 2 terminal, one for in and another for out flows