Today, in this project we will learn how to interface a Thermal Printer with Raspberry Pi using a hardware serial communication, to print a test receipt that contains various elements like a Logo, a QR Code, or barcode along with various other text and graphical characters. As we all know, Raspberry Pi is a portable development board and we have already built many raspberry pi based projects previously. In this project, we will be Interfacing a Thermal Printer with Raspberry Pi, then by using Serial communication and the python-escpos library we will control the thermal printer from raspberry pi and print text and graphical images. You should check out our previous articles, where we already interfaced thermal printer with Arduino Uno and PIC16F877A.
Before going further let us have a look at these steps that will be involved,
- Enable the Hardware Serial through raspi-config
- Connections for Thermal printer and Pi 3
- Figure out how the ESC-POS commands work.
- Install the library from GitHub.
- We will do some basic coding to print text, image, barcode, QR Code, etc.
- We will try Print a sample Receipt
- Conclusion
Components for Interfacing the Thermal Printer with Raspberry Pi
Component Name | Qty |
---|---|
Thermal Printer MAXIM PNP-500 | 1 |
Raspberry Pi 3 or Raspberry Pi 0 | 1 |
Jumper Wires Male to Female | As required |
9V 1 Amp Adaptor | 1 |
The above table is showing the list of components I am using as of now, you can have a different set of thermal printers and Raspberry Pi versions. Also, my printer requires at least 6 Volts to operate. (Please check the user manual while selecting the power source).
What is a Thermal Printer?
A thermal printer is a printer that uses heating head-on thermal papers to produce images. Its quality of print, ease of installation, minimum use of external components, and low power consumption, makes it more popular among token or ticket counters, grocery stores, tiffin centers, entertainment centers, healthcare, corporate industries, etc. It's both eco-friendly as well as a cost-effective solution for small-scale use as no ink Cartridge or ribbon is used.
It provides a noise-free operation along with faster monochromatic printing. Make sure to use the printer with an optimized temperature of print head as it may get damaged on operating with high temperature.
In our case, we are using a thermal printer that can be interfaced using RS232 mode or Serial TTL. I am using a 9V adaptor to power it up. By default, the baud rate of most of the printers is 9600. We will use the TTL mode of communication in this case. For more technical details of the printer please download Brochure.
Print Method |
Thermal Direct Line Printing |
Paper loading method |
Easy paper loading |
Paper width |
57 mm |
Print width |
48 mm |
Print speed |
250 mm/sec |
Resolution ratio |
8 dots/mm (384 dots/line) |
Life of printing head |
50 km |
Printing speed |
50 mm/sec |
Max. printing speed |
80 mm/sec |
Character size |
9 x 17 • 12 x 24 |
Chinese character fonts |
GB18030 |
Chinese character size |
12 x 24 dots • 24 x 24 dots |
Outline dimension |
76.8 x 77.4 x 47.6 (WxDxH mm) |
Installation |
72.8 x 73.4 (WxD mm) |
Embedded depth |
34.65 mm |
Paper roll specification |
Width : 58 mm, max. diameter: 40 mm |
Interface |
Serial (RS232C,TTL) / USB |
Input power |
DC5-9V • 12V |
Operating temperature |
0°C~55°C |
Storage temperature |
25°C~70°C |
Operating humidity |
10°C~80°C |
Storage humidity |
10°C~90°C |
Most of the printers work on ESC Point of service commands for interfacing with computers which was designed by EPSON. It was mostly used in some inkjet printers, dot matrix printers and is still widely used in many receipts thermal printers for controlling them. As of 2014, few modern non-Epson printers use ESC/P instead and most are driven through a standardized page description language, usually, PCL or PostScript, or they use proprietary protocols such as Hardware Code Pages.
This thermal printer works on ESC/POS command for which we will be using the dedicated library.
Enabling Serial Port of our Raspberry Pi
In the terminal, write the following command and then press enter.
sudo raspi-config
You will see the configuration page, then navigate to ‘interfacing option’ through the arrow keys. After pressing enter, go to the ‘serial port enable/disable’ option. Press ‘no’ for enabling the serial login shell and then press ‘yes’ for enabling the ‘Hardware Serial port’. Click ‘ok’ and then click on the ‘finish button’ to reboot your pi.
Now by doing so, you have enabled your Hardware Serial i.e. ‘/dev/serial0’ which is dedicated for ‘ttyAMA0’. This can be determined by entering the following command on Pi-3.
ls -l /dev
You'll see the following screenshot. Serial 1 is being used by the onboard Bluetooth of the Raspberry Pi 3. So, we will only be using the Serial 0 for the Thermal printer that is to be connected to GPIO 14 and GPIO 15 as TX-D0 and RX-D0.
Now we will connect the Printer with our Raspberry Pi and provide 9V Supply to the Printer.
Connection Diagram for Interfacing Thermal Printer and Raspberry Pi 3
Here you can see that RXD of the Printer is connected to the TXD of the Raspberry Pi and the TXD of the Thermal printer is connected to the RXD of the Raspberry Pi 3.
Also, one can note that TDR and GND are set to GND as of now. My printer was not printing until I put TDR to the ground.
Code for Interfacing Thermal Printer and Raspberry Pi
As we have discussed earlier, the thermal printer can be controlled by passing appropriate ESC POS Command. But for now, we are using a library to interface it as this library will send the data by using the same commands and your desired print would become easy. It is quite complex to understand the basic nature of the printers based on ESC Command but once you learn the basics, it would become a piece of cake for you.
Now for installation of the library write the following command in the terminal.
sudo pip install python-escpos
By doing so, you will be able to use the library. We will be using the serial UART protocol for interfacing.
Printing Text on Thermal Printer
Here we will be testing our first code on the printer that will print the text “Hello World” followed by a QR code.
from escpos.printer import Serial """ 9600 Baud, 8N1, Flow Control Enabled """ p = Serial(devfile='/dev/serial0, baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.00, dsrdtr=True) p.text("Hello World\n")
Now you can have a look at the detailed documentation for learning and exploring the functions and methods of this amazing library.
Setting up the Text Properties on Thermal Printer
The ‘set()’ function will be used to set the text properties like font style (‘a’ or ‘b’), alignment, or font size.
p.set( underline=1, align="left", font="a", width=2, height=2, density=3, invert=0, smooth=False, flip=False, ) p.textln(“Hello World”)
The text can also be bold or normal, inverted to black and white, or flip like upside or downside.
Printing the Barcodes
The barcode(data, code_type, pos) where the arguments will be as follows,
data= “any data to convert into Barcode” code_type=”type of barcode for eg. CODE39, CODE128, UPC-1, etc. “ POS=”position of the barcode data for eg. ‘BELOW’, ABOVE, BOTH, OFF“
For further details about this method please refer to the documentation page. It can be noted that the size of the barcode can also be adjusted by passing the respective arguments.
p.barcode('123456', 'CODE39')
This will print the barcode that will store ‘123456’. Also, this will be of CODE39 type. Moreover, for the alignment of the barcode, you can use the set() function as we discussed earlier.
Printing the QR Code
Now you will be amazed to know that the ESCPOS Library has the facility to convert your data into a QR Code directly by passing the desired string. For printing a QR Code of your desired information, you can use the following Function.
p.qr("Circuit Digest",native=True,size=12)
Here you can pass the “String data in quotes”, size of the QR code, and native as TRUE or FALSE.
Printing Image using Thermal Printer
Now it’s time for the image printing, here you can locate the image and pass the location as the argument of the image() function.
p.image("/home/pi/Raspberry_Pi_logp.png",impl="bitImageColumn")
Here “the path of the image should place here”, followed by the impl as “imageRaster” or “bitImageColumn” etc. You can have a look at the documentation part for more details. Just keep in mind that the pixels of width should not be more than 360 as the page size has a limited width.
Print Sample Receipt using Thermal Printer
So, now it's time to print our first Receipt using Thermal Printer but before going further please note that we are hard coding the output for now and will try to make it dynamic next time.
The code for printing the receipt is as follows:
from escpos.printer import Serial from time import * from datetime import date from datetime import datetime now = datetime.now() dt_string = now.strftime("%b/%d/%Y %H:%M:%S") print("Today's date:", dt_string) """ 9600 Baud, 8N1, Flow Control Enabled ""' p = Serial(devfile='/dev/serial0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.00, dsrdtr=True ) p.set( underline=0, align="left", font="a", width=2, height=2, density=3, invert=0, smooth=False, flip=False, ) p.text("\n") p.set( underline=0, align="center", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) #Printing the image # here location can be your image path in “ ” p.image("/home/pi/proj on pi0/CD_new_Logo_black.png",impl="bitImageColumn") #printing the initial data p.set( underline=0, align="left", ) p.textln("CIRCUIT DIGEST\n") p.text("AIRPORT ROAD\n") p.text("LOCATION : JAIPUR\n") p.text("TEL : 0141222585\n") p.text("GSTIN : \n") p.text("Bill No. : \n\n") p.set( underline=0, align="left", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) # print the date and time of printing every time p.text("DATE : ") p.text(dt_string) p.textln("\n") p.textln("CASHIER : ") p.textln(" ===========================") p.textln(" ITEM QTY PRICE GB") p.textln(" --------------------------") p.textln("IR SENSOR 2 30 60") p.textln("ULTRASONIC 2 80 160") p.textln("RASPBERRY 1 3300 3300") p.textln("ADOPTOR 2 120 240") p.textln(" --------------------------") p.textln(" SUBTOTAL: 3760") p.textln(" DISCOUNT: 0.8") p.textln(" VAT @ 18%: 676.8") p.textln(" ===========================") p.textln(" BILL TOTAL: 4436.8") p.textln(" TENDERD: 0.8") p.textln(" BALANCE: 676.8") p.textln(" --------------------------") p.textln(" THANK YOU") p.textln(" ===========================") p.set( underline=0, align="center", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) p.qr("Circuit Digest",native=True,size=12) p.textln("") p.barcode('123456', 'CODE39') #if your printer has paper cuting facility then you can use this function p.cut() print("done")
Conclusion
We can have multiple ideas of printing text in different fonts, and various sizes on the thermal printer. In this article, we have learned some basic functionalities of the thermal printer and what commands does it support, i.e. ESCPOS in our case. Also, we come to know that thermal printers are the handiest in daily usage, have a long life, and have less maintenance. It can print up to 50Kms of fully dense written paper roles. We will try to print some more tables and aligned text next time, till then stay connected.
from escpos.printer import Serial from time import * from datetime import date from datetime import datetime now = datetime.now() dt_string = now.strftime("%b/%d/%Y %H:%M:%S") print("Today's date:", dt_string) """ 9600 Baud, 8N1, Flow Control Enabled """ p = Serial(devfile='/dev/serial0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=1.00, dsrdtr=True ) p.set( underline=0, align="left", font="a", width=2, height=2, density=3, invert=0, smooth=False, flip=False, ) p.text("\n") p.set( underline=0, align="center", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) #Printing the image p.image("/home/pi/ proj on pi0/CD_new_Logo_black.png",impl="bitImageColumn") #printing the initial data p.set( underline=0, align="left", ) p.textln("CIRCUIT DIGEST\n") p.text("AIRPORT ROAD\n") p.text("LOCATION : JAIPUR\n") p.text("TEL : 0141222585\n") p.text("GSTIN : \n") p.text("Bill No. : \n\n") p.set( underline=0, align="left", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) p.text("DATE : ") p.text(dt_string) p.textln("\n") p.textln("CASHIER : ") p.textln(" ===========================") p.textln(" ITEM QTY PRICE GB") p.textln(" --------------------------") p.textln("IR SENSOR 2 30 60") p.textln("ULTRASONIC 2 80 160") p.textln("RASPBERRY 1 3300 3300") p.textln("ADOPTOR 2 120 240") p.textln(" --------------------------") p.textln(" SUBTOTAL: 3760") p.textln(" DISCOUNT: 0.8") p.textln(" VAT @ 18%: 676.8") p.textln(" ===========================") p.textln(" BILL TOTAL: 4436.8") p.textln(" TENDERD: 0.8") p.textln(" BALANCE: 676.8") p.textln(" --------------------------") p.textln(" THANK YOU") p.textln(" ===========================") p.set( underline=0, align="center", font="a", width=2, height=2, density=2, invert=0, smooth=False, flip=False, ) p.qr("Circuit Digest",native=True,size=12) p.textln("") p.barcode('123456', 'CODE39') #if your printer has paper cuting facility then you can use this function p.cut() print("done")