Since last year I have an Anet A8, a 3d printer received from China as a kit and that I use as you can expect to print 3d models and experiment with this technology.
In this post I want to describe a thing that is very simple but that is not (probably) well known: the board that manages the functionality of this device is (in the majority of the cases) an arduino-like system that receives commands via a serial port and acts accordingly enabling the various systems that compose the printer, like stepper motors, bed heater etc...
The commands understood by this sistem of boards is called
Gcode, is a text based
language used primarly for movements in a 3d spaces; you can find a list of these commands
in the page of the RepRap site. Not all the commands
are implemented in all the firmwares (some of them don't make sense in a 3d printer).
A little problem that someone using a Linux system is that the baudrate used with these systems
is a not standard one: 250000 and in some cases it's tricky to make the OS accepts this value.
set_special_baudate() function in the module below:
''' For more information about GCODE take a look at <http://reprap.org/wiki/G-code>. ''' from __future__ import absolute_import import array import ctypes import fcntl import logging import time import os import serial from cmd import Cmd logging.basicConfig() logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) class SerialCmd(Cmd): def __init__(self, printer): Cmd.__init__(self) self.printer = printer def _query(self, msg): self.printer.write('%s\r\n' % msg) # we need to wait a little bit in order # to receive the output while self.printer.in_waiting == 0: time.sleep(0.5) response = '' while self.printer.in_waiting > 0: response += self.printer.readline() #time.sleep(0.5) return response def do_query(self, args): print self._query(args) def do_firmware(self, args): '''Get firmware version and capabilities''' print self._query('M115') def do_origin(self, args): '''Move to origin the printer head''' self.printer.write('G28\n') response = self.printer.readline() print response def do_sdcard(self, args): print self._query('M20') def do_quit(self, args): '''quit the shell''' raise SystemExit # from /usr/lib/python2.7/site-packages/serial/serialposix.py # /usr/include/asm-generic/termbits.h for struct termios2 # c_cflag c_ispeed c_ospeed def set_special_baudrate(fd, baudrate): TCGETS2 = 0x802C542A TCSETS2 = 0x402C542B BOTHER = 0o010000 CBAUD = 0o010017 buf = array.array('i',  * 64) # is 44 really fcntl.ioctl(fd, TCGETS2, buf) buf &= ~CBAUD buf |= BOTHER buf = buf = baudrate assert(fcntl.ioctl(fd, TCSETS2, buf)==0) fcntl.ioctl(fd, TCGETS2, buf) if buf != baudrate or buf != baudrate: print("failed. speed is %d %d" % (buf,buf)) sys.exit(1) def open_serial(device_path='/dev/ttyACM0', baudrate=250000): logger.info('opening serial device \'%s\' with baudrate set to %d' % (device_path, baudrate)) fd = os.open(device_path, os.O_RDWR) set_special_baudrate(fd, baudrate) device = serial.Serial(device_path, baudrate) logger.info('please wait, the device will reset in a few seconds') # we need to wait a little bit to allow the port to be opened # and the device to be reset import time;time.sleep(5) banner = "\n" while device.in_waiting > 0: banner += device.readline() logger.info('BANNER: %s' % banner) return device if __name__ == '__main__': device = open_serial() shell = SerialCmd(device) shell.prompt = 'anet> ' shell.cmdloop('starting...') device.close()
With this script is possible to interact with the serial with some commands preconfigured; below an example: first of all launch the script and wait for the prompt.
$ python -m anet.serial INFO:__main__:opening serial device '/dev/ttyACM0' with baudrate set to 250000 INFO:__main__:please wait, the device will reset in a few seconds INFO:__main__:BANNER: start test1 echo:Marlin 0721 echo: Last Updated: Apr 12 2017 12:22:44 | Author: (none, default config) Compiled: Apr 12 2017 echo: Free Memory: 4534 PlannerBufferBytes: 1232 echo:SD card ok starting... anet>
You can find the commands available with the
anet> help Documented commands (type help <topic>): ======================================== firmware help origin quit Undocumented commands: ====================== query sdcard
At this point in time there are few commands:
anet> firmware FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:http://www.mendel-parts.com PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1 ok anet> sdcard Begin file list /TESTFILE/TESTMODE/2016~1.GCO /TESTFILE/TESTMODE/FZ-~1.GCO /TESTFILE/TESTMODE/MAN~1.GCO /TESTFILE/TESTMODE/PIGALL~1.GCO /TESTFILE/TESTMODE/TEST-P~1.GCO /TESTFILE/TESTMODE/TEST~1.GCO /TESTFILE/TESTMODE/YZ87B3~1.GCO /TESTFILE/TESTMODE/Z-LEFT~1.GCO /TESTFILE/TESTMODE/Z-RIGH~1.GCO echo:Cannot open subdir PI_LVD~1.GCO PI_GAP~1.GCO PI_LVD~2.GCO PIM_PO~1.GCO A_CAT~1.GCO End file list ok
A fundamental command is
query that allows to send directly raw text
to the printer: if you want to move of a vector-offset of
(100, 100, 100)
the head of the printer you have to type
anet> query X100 Y100 Z100 ok
(keep in mind that if you don't have endstop in one or more of those directions and the offset move the head off the limits of you printer damage can happen!).
Now it's possible to abuse the 3d printer and use it as a scanner or maybe a PCB milling machine or whatever you want ;)