Continuous Inkjet Printing

Learning about continuous inkjet printing and sharing my experience with the community.

Similar projects worth following
Here is another inkjet project and this time it is about continuous inkjet printing. In this project I want to set up and work with a CIJ Printer to find out how it works down to the smallest detail to possibly build a CIJ printer by my own.

In my last inkjet project I built a piezo inkjet printer from scratch made of cheap electronics, pneumatic and 3D printed parts. I could get it to work, but I had a few problems with the reliability. The drop size was quite large, keeping the ink supply pressure steady was quite difficult and sometimes there formed drops on the nozzle or air got sucked into the printhead what both prevented the printhead from working. There also was a problem with clogging of the nozzle when not in use.

So I looked for a more reliable printing method and choosed Continuous Inkjet Printing.

CIJ printing is (as far as I know) only used in industrial or production applications and therefore super reliable. CIJ printers are working for years 24/7 with only minor maintenance. 

Even though CIJ printers have much more parts than piezo or thermal inkjet printers, all parts have a decent size - no sub millimeter dimension like piezo and thermal inkjet nozzles, so working on them, fixing problems and maybe also manufacturing them will be a lot easier.

How CIJ Printing works:

Here I will describe you in my own words based on my experience with my printer model how CIJ Printing works. The printer I have is an older model that uses pressurized air and vacuum instead of a special ink pump, what I think is really cool because it keeps everything simple and you can use any air and vacuum supply that you want.

Animation from Wikipedia

CIJ printers need two different fluids to work - Ink and Make Up Fluid. 

Both fluids get mixed by the printer to reach the right viscosity. The make up fluid is essentially a solvent to dilute the ink.

My printer has an ink mixing assembly in which the ink get mixed and also the not used ink returns to. The chamber of it is set under vacuum and the adding of ink and make up fluid is controlled by two pneumatic driven rubber valves.

From the ink mixing chamber the ink gets transfered to a viscosity measuring cylinder by a pneumatic rubber pump. The ink cylinder is pressurized and connected to the nozzle which has a valve that stays closed until it reaches a certain pressure to prevent the ink from dripping from the nozzle when not under the right pressure. The pneumatic driven rubber pump is driven with 1 bar above set ink pressure to be able to pump the ink into the cylinder through an ink filter. The pump also has check valves at the in and outlet.

The cylinder has a floating magnet in it and multiple reed switches to detect the ink level. For measuring the viscosity the printer measures the time that it takes to empty the cylinder and according to the set flow time the printer adds ink or make up to the ink chamber - or nothing if everything fits and the ink level in the ink mixing chamber is high enough (it also has a floating magnet and reed switches). The viscosity is measured to get the same print quality at all times during operation.

The next step in the cycle is the printhead.

The "low pressure limit valve" at the printhead is connected to the nozzle which contains a piezo crystal that is driven with a frequency that breaks the ink stream up into dropplets using the Plateau–Rayleigh Instability. 

After the nozzle there follows a tunnel that is driven by a high voltage to charge the dropplet and after this there follows a high voltage deflection plate to kick dropplets out of the stream to form pattern on the printed surface.

The unused ink streams right into an ink return block which is connected to a sensor that prooves whether the charging has worked and from there it get sucked back into the ink mixing chamber by vacuum to close the cycle.

I think the pneumatics, hydraulics and their control circuits are quite simple and would not be very complicated to build for an open source system.

The electrical control of the printhead at the other hand, like the nozzle piezo drive, charging, deflection and sensing signal are more complicated, so that I will likely...

Read more »

  • Milestone reached: Working CIJ Nozzle

    Dominik Meffert09/23/2021 at 01:54 3 comments

    The piezo nozzle is one of the most expensive parts of a CIJ printer. It is usually made of a piezo ring stack with an inner channel leading to a small nozzle orifice. By driving the piezo with a high frequency signal, the ink stream exiting the nozzle can be broken up into separate droplets, which then can be charged and deflected for printing.

    Because of the high price I thought they would be extremely hard to build and would need exact tuning to work at all. Nevertheless, I tried building one out of an ultrasonic transducer from an ultrasonic bath and could get it to work with some trial and error.

    First, I had to build a driver for it.

    It took me a while to find a driver design which was simple and promising and I finally found it in The Thought Emporium's great video about sonoluminescense.

    The piezo is driven by a cheap audio amplifier which gets its signal from a signal generator. The piezo nozzle which is essentially a capacitor has to form a series LC circuit with an inductor in order to work.

    The ultrasonic transducer that I used has a capacitance of 3.8nF. For the first test I used a selfmade air core inductor with a metal rod for variable inductance and set it to 1.5mH, because I calculated the LC circuit values for a frequency of about 66kHz, which is the frequency of a commercial piezo nozzle that I have. It later turned out that a frequency of about 40kHz worked a lot better for my selfmade piezo nozzle - maybe this frequency was closer to the resonant frequency of my nozzle, which I had not figured out, yet. For a second test I replaced the large inductor with a smaller ferrite core inductor with about 2mH for testing and it worked as good as or even better than before. Maybe I will do more testing with proper tuning in the future, but even with suboptimal values it did work not that bad.

    Another important thing is to backlight the ink/water stream with a LED which is driven by the same frequency as the piezo to make the forming of separate droplets visible.

    Here is a video of the experiment:

    And here are some pictures:

    Signal generator: 

    CH1 for the piezo and CH2 for the LED

    Signal generator and power supply

    Audio amplifier

    Piezo nozzle with inductor and LED

    Water is supplied by connecting it to the shower in my bathroom


    Picture of seperate droplets

    Another picture of seperate droplets

    Another picture of seperate droplets


    Ultrasonic transducer nozzle

    So, with a working piezo nozzle that can break up the ink stream, I can now start with the design of a printhead and the charge and deflect circuit.

  • CIJ Nozzle Prototype

    Dominik Meffert09/10/2021 at 14:48 0 comments

    Here is a prototype of the nozzle for my CIJ Printer Project. The nozzle is made of an ultrasonic transducer from an ultrasonic bath with a hole drilled through the screw in the middle. For the 3D printer nozzle I drilled a M6 thread into the screw head and the M10*1 or 1/8" thread for the push in fitting was already at the other end of the transducer. I also placed an O - ring at the bottom of the push in fitting thread to prevent ink from leaking through the thread of the screw to the piezo. At the moment I have no driver for the piezos but I'm currently researching how to build one. There will also be a strobe LED needed to see the seperation of ink dropplets from the ink stream, which runs at the same frequency as the piezo.

    So, next up will be building a test stand for the nozzle with strobe LED, a driver for driving the piezo and writing a script for automating the cycle.

  • Electronics wired and some Improvements

    Dominik Meffert05/27/2021 at 23:58 0 comments

    Over the last days I tested out the cycle to find out design flaws and improve everything to get it working reliably.

    I also wired everything, so that I can now control everything from the Raspberry PI by setting the pin states and also read all the sensors. 

    I wired 5 relays, a vacuum switch, a pressure switch, the upper and lower switch of the reservoir and the upper and lower switch of the viscosity counter to the Raspberry Pi.

    Decided to remove the float switches from the ink and makeup bottle, because I think it will be more practical to check their level by just looking on them - Like you check your filament spool before starting a print.

    It's also no problem to refill them while the cycle is running, because they are not pressurized and only used every few seconds if ink/makeup is needed.

    The bottles could also be replaced by larger bottles or canisters if the printer's use case would need a lot of ink/makeup.

    Added one more vacuum connection to the reservoir to have 2*2mm inner tube diameter for a higher vacuum throughput.

    This was needed to be able to draw ink/makeup from the bottles while the return line is feeding the ink back to the reservoir.

    Changed the stainless steel tube and the two other tubes to PTFE tubes, because the stainless steel tubes inner surface was very rough, so that the magnetic float got stuck on it. It's also better because it is translucent, so you can see the float moving.

    Also added a vacuum gauge to the vacuum overflow tube.

    Changed some parts of the pneumatics assembly.

    An important change was separating the pump solenoid from the ink/makeup solenoid block.

    Before, the pump solenoid let the displaced air from the pump's piston flow into the vacuum lines, what caused serveral problems. By separating the solenoid that's no longer a problem.

    An interim printhead to complete the cycle.

    The ink (water) is streaming from the viscosity counter to a syringe needle into an 1mm 3d printer nozzle back to the reservoir.

    The check valve before the syringe is to provide some resistance, so that the needle stops dripping if the pressure is turned off.

    The check valve after the 1mm nozzle is also to provide some resistance, but this time to prevent the vacuum level from dropping too much through the return line.

    Added a filter to keep the ink clean.

    Now I only have to write a CIJ Cycle Controller python script to get the cycle to work. 

    Doing this will just take some time, but I have no doubt that I will get it to work by using try and error and reading StackOverflow sites :)

    The more critical part on which I want to work first will be building a nozzle that can split the ink stream into droplets.

    To do this I will research ultrasonic vibration and pizo ceramics + their drivers.

    I want to start by building some mist makers and their drivers.

  • Quick Update

    Dominik Meffert05/10/2021 at 17:40 0 comments

    Over the last days I was building a CIJ printer hydraulics and pneumatics system from commonly available parts (got all my parts from Amazon, Ebay and my local hardware and pneumatics/hydraulics store).

    Until now I successfully tested out every component on its own and all components together by operating the solenoid valves by hand. The electronics and control software are still missing at the moment.

    Stainless steel reservoir tube - no more rust :)

    Stainless steel viscosity counter with reed switches.

    Connected the solenoid valves to a relay module and added a Raspberry Pi 4 as controller for the CIJ Cycle.

  • Printing Text Blocks

    Dominik Meffert04/18/2021 at 20:15 0 comments

    I spent the last week collecting Python code examples all over the web and put them together in a way that meets my goal of processing text to gcode for stepper motors and the CIJ printer.

    I came up with this:

    #Import tkinter and Scrolledtext
    import tkinter as tk
    from tkinter import scrolledtext
    from tkinter import filedialog
    import textwrap
    import os.path
    import pickle
    gcode_output = ""
    #Open Text File
    def openFile():
        oF = filedialog.askopenfilename(title="Open Textfile", filetypes=(("Text Files", "*.txt"),))
        with open(oF, "r", encoding="utf-8", errors="ignore") as infile:
            indata =
            text_area0.delete("1.0", "end")
            text_area0.insert(1.0, indata)
    #Main Function
    def showPreview():    
        global gcode_output
        #Show Wrapped Text and Text Size
        getText = text_area0.get("1.0", "end")
        wrapper = textwrap.TextWrapper(width=int(EntryLabel1.get()), replace_whitespace=False)           
        string = wrapper.fill(text=getText)                     
        textlines = string.splitlines()
        printmatrix = EntryLabel0.get().split(", ")                                                      
        pm_float = [float(item) for item in printmatrix]
        Xmatrix = pm_float[0]
        Ymatrix = pm_float[1]
        most_chars = float(len(max(textlines, key=len)))                                                 
        Textsize = [(Xmatrix * most_chars), (Ymatrix * len(textlines))]
        Label4.config(text = str(Textsize))
        #Create i2c Commands
        text_lists_of_chars = [list(c) for c in textlines]
        lists_of_values = [[ord(item) for item in group] for group in text_lists_of_chars]
        lists_of_strings = [[str(x) for x in l] for l in lists_of_values]
        carriage_return = [item + ["13"] for item in lists_of_strings]
        byte_command = [["M260 B" + item + "\n" for item in group] for group in carriage_return]
        adress_command = [["M260 A9\n"] + item for item in byte_command]
        send_command = [item + ["M260 S1\n"] for item in adress_command]
        i2c_commands = ["".join(item) for item in send_command]
        #Calculate Print-Start Coordinates
        Y_coordinates = [x * Ymatrix for x in range(0, len(textlines))]
        Y_coordinates_floatlists = [[c] for c in Y_coordinates]
        Y_coordinates_stringlists = [[str(x) for x in l] for l in Y_coordinates_floatlists]
        Ystart_add_text = [["Y" + item + " F" + EntryLabel9.get() + "\nM106 P1 S255\n" for item in group] for group in Y_coordinates_stringlists]
        XYstart_lists = [["G1 X0.0 "] + item for item in Ystart_add_text]
        XYstart_strings = ["".join(item) for item in XYstart_lists]
        #Calculate Print-End Coordinates
        Xend_coordinates = [(len(item) * Xmatrix + float(EntryLabel2.get())) for item in textlines]
        Xend_coordinates_floatlists = [[c] for c in Xend_coordinates]
        Xend_coordinates_stringlists = [[str(x) for x in l] for l in Xend_coordinates_floatlists]
        Xend_add_text = [["G1 X" + item +  " " for item in group] for group in Xend_coordinates_stringlists]
        Yend_add_text = [["Y" + item + " F" + EntryLabel9.get() + "\nM106 P1 S0\n" for item in group] for group in Y_coordinates_stringlists]
        Xend_strings = ["".join(item) for item in Xend_add_text]
        Yend_strings = ["".join(item) for item in Yend_add_text]
        XYend_zip = zip(Xend_strings, Yend_strings)
        XYend_list = list(XYend_zip)
        XYend_strings = ["".join(item) for item in XYend_list]
        #Create GCODE
        gcode_zip = zip(i2c_commands, XYstart_strings, XYend_strings)
        gcode_list = list(gcode_zip)
        gcode_string_list = ["".join(item) for item in gcode_list]
        gcode_string = "".join(gcode_string_list)
        gcode_output = text_area1.get(1.0, "end") + gcode_string + text_area2.get(1.0, "end")
        #Show Preview
        text_area0.delete("1.0", "end")
        text_area0.insert(1.0, str(string))
    #Change Label back to -  
    def restoreLabel():
    #Save Settings to File
    def saveSettings(event):
        SettingValues = {"Print Matrix X, Y": EntryLabel0.get(), "Line Charakter Limit": EntryLabel1.get(),
                         "Runout": EntryLabel2.get(), "Speed F": EntryLabel9.get(), "Startcode": text_area1.get(1.0,
                         "end"), "Endcode": text_area2.get(1.0, "end")}
        pickle.dump( SettingValues, open( "Settings.p", "wb" ) )
        win.after(1000, restoreLabel)
    #Convert Text...
    Read more »

  • Everything in GCODE

    Dominik Meffert04/09/2021 at 12:39 0 comments

    I just figured out how to send messages to the CIJ printer from the 3D printer controller, so that it can be completely controlled by GCODE. 

    For doing so I used the i2c feature of the Marlin firmware to send the messages to an Arduino NANO which then sends the messages via serial to the MAX3232 and so to the CIJ printer.

    On the Arduino NANO I used the code from the Arduino i2c slave receiver example:

    #include <Wire.h>
    void setup()
    void loop()
    void receiveEvent(int howMany)
      while (Wire.available())

    Here is the gcode that I used:

    (with a small change to print only 3 lines)

    M260 A9
    M260 B84     ;T
    M260 B104    ;h
    M260 B105    ;i
    M260 B115    ;s
    M260 B32     ;Space
    M260 B77     ;M
    M260 B101    ;e
    M260 B115    ;s
    M260 B115    ;s
    M260 B97     ;a
    M260 B103    ;g
    M260 B101    ;e
    M260 B13     ;CR
    M260 S1        
    G1 X30.000 Y200.000 F2000
    M106 P1 S255        
    G1 X80.000 Y200.000 F2000
    M106 P1 S0
    M260 A9
    M260 B119    ;w
    M260 B97     ;a
    M260 B115    ;s
    M260 B32     ;Space
    M260 B115    ;s
    M260 B101    ;e
    M260 B110    ;n
    M260 B116    ;t
    M260 B13     ;CR
    M260 S1
    G1 X30.000 Y185.000 F2000
    M106 P1 S255
    G1 X80.000 Y185.000 F2000
    M106 P1 S0
    M260 A9
    M260 B119    ;w
    M260 B105    ;i
    M260 B116    ;t
    M260 B104    ;h
    M260 B32     ;Space
    M260 B71     ;G
    M260 B67     ;C
    M260 B79     ;O
    M260 B68     ;D
    M260 B69     ;E
    M260 B13     ;CR
    M260 S1
    G1 X30.000 Y170.000 F2000
    M106 P1 S255
    G1 X80.000 Y170.000 F2000
    M106 P1 S0
    G1 X150.000 Y170.000 F2000

    So, now that this works the next thing would be writing a python script to create the GCODE for longer messages.

  • Testing with GCODE

    Dominik Meffert04/06/2021 at 10:47 0 comments

    I set up the printer controller and stepper motor connections, wrote some gcode to a file and let it run to test it out.

    The next thing would be sending my own messages to the printer. 

  • Testing per Hand

    Dominik Meffert04/05/2021 at 00:23 2 comments

    To test the printer for the first time without GCODE and software I 3D printed two parts (A printhead mounting bracket and an encoder mounting bracket) for mounting the printhead and encoder to a cheap 3D printer.

    To test it I entered HACKADAY.IO on the CIJ printer display and powered the printer controller what also powered the MOSFET board and triggered the product detect.

    Then I moved the printhead by hand to print the message and that's it. The first printed message.

    I also tried printing on my hand :)

    The ink that I used is (as far as I know) acetone based and could be cleaned off by soap with some effort or immediately with the make up fluid.

  • Controlling the Printer

    Dominik Meffert04/04/2021 at 23:09 0 comments

    To control the printer there are 3 signals needed:

    - Droduct Detect

    - Encoder

    - RS232

    Product Detect:

    Everytime the Product Detect signal is triggered the printer starts printing a message.


    If an encoder is connected to the printer the printer is able to detect the exact position of the printhead, so that no matter how fast the printhead moves the message gets printed as it should be.


    To send messages for printing to the printer RS232 is used and the messages are send in HEX numbers.

    The upper connection at the right is the product detect and the lower is the encoder.

    Here you can see the DB25 RS232 connector which is also able to use hardware serial.

    Because I used software serial only 3 lines and some bridges are needed.

    The other end of the cable is connected to a DB9 connector.

    Which is connected to a MAX3232 board.

    I also placed a Ramps 1.6+ & Arduino Mega 2650 with two TMC2130 and a power supply in there to control two stepper motors. A mosfet board is used to trigger the product detect.

    At the moment I have not connected anything to the printer controller because I still have to configure the firmware for it.

  • Working at Night

    Dominik Meffert04/04/2021 at 20:22 0 comments

    I prefer working at night, but running an air compressor and a vacuum pump at night when you have roommates or neighbors is not the best idea and so I had to find a solution for this problem.

    Starting with the vacuum pump:

    Because I was concerned about acetone vapor buildup in the vacuum tank and therefore risk of fire or explosion I had to remove the vacuum tank.

    Without a tank the pump has to be able to run the entire time without overheating.

    To keep the pump as cool as possible I mounted it on an old LED heatsink and also reduced the voltage from 12V to 6V what also reduced the noise level.

    To prevent the pump from stalling at such a low voltage caused by too much load/too high vacuum level I added a regulatable muffler to let air in.

    To further reduce the noise I put a fitting with cap on the outlet and placed the pump in a plastic box.

    This worked very well and was also really quiet.

    Now I had a solution for vacuum, but still needed something to create pressurized air without being noisy.

    So I bought an old fridge at ebay Kleinanzeigen to get the compressor from it.

    After cleaning it I drilled 3 holes in it to let the old oil out and for modifying the case. After the old oil was gone I cut threads in the holes to attach fittings and a transparent tube to it for showing the oil level and to close the hole in the top with a screw.

    Then I filled in some new oil and attached the new compressor motor to the compressor tank.

    This setup worked very well and was really quiet, too. The most noisy part of the system is the check valve after some oil got to it. The noise is not really loud, more like a quiet oscillation that sometimes dissapears completely. Because of the oil I used a water seperator unit what should also prevent the oil from entering the printer.

    With the vacuum pump and fridge compressor the setup should be ready for the night.

View all 13 project logs

Enjoy this project?



Paulo Campos wrote 01/17/2022 at 00:29 point

I have worked with CIJ printers at least 18 years with projects and fluids. i'm impressed with your audacity and progress. Certainly the nozzle is not a big challenge, you can buy in Swiss (ruby) and assembly in a laser cutted plate, the diameter of the jet is governed by the size of droplet we want, 75 microns is most recommended. This give a wavelength of

  = 4.51x 75= 331 microns.

Also, the jet velocity at 40 Psi is 20~22 metres per second. If this is divided by the wavelength, it gives the optimum frequency.

  =22 m/s / 331microns= 64000.Hz

In practice, other frequency / nozzle sizes can be used that are not 'optimum', for example 60 micron/ 64kHz, but these still work, they are simply less efficient.

 I recomend you 75u  as we can get the best resonancy for drops in 64Khz with around 2800mBar/40psi, but till 100u we sill can get some workarounds. At past I worked in my 'hobby time' with some PCBs and HV PS for CIJs and I can say you there is no chance of success without phasing control and for do it you will need add one FPGA to your project. I have the PCB and HV Power project  ready without firmware, I can share you and share experience., I got success in many things .   Have a nice week! 

  Are you sure? yes | no

Paulo Campos wrote 01/16/2022 at 23:57 point

Awesome progress Dominik! Congratulations! 

  Are you sure? yes | no

srbin25 wrote 10/27/2021 at 19:56 point

how connect CIJ print head with Arduino if it is possible?

  Are you sure? yes | no

Dominik Meffert wrote 11/02/2021 at 15:38 point

My current plan is to control everything with a Raspberry Pi so that I can write a python script with GUI for all the settings and infos. I think it will also take more time until I can get the project to an usable stage because I'm currently working on another project which I want to use for creating the printhead parts.

  Are you sure? yes | no

Hexastorm wrote 06/10/2021 at 08:36 point

Great to see you are still up with inkjet printing. In the past, I did some research into this topic.
What I would recommend is the book (inkjet technology for digital fabrication). A pdf can be found online.
TNO, a research institute from the Dutch State, also build one setup see .  I was not involved but building it took a crazy amount of time. The CIJ head used air for droplet selection instead of electricity.
This gave it the ability to print high viscous non conductive fluids.
A problem encountered was the wavy-ness in the final result and low through put. You can see it in the image (3D graded product made of three high viscousmaterials) in the linked pdf.  Dr. René Jos Houben did most of the work and use this as a query term to find out more.  I think some of the patents, if any, got transferred to a company called Nordson.
What I would recommend;

 - do research in the field of laser induced forward transfer

   This is a very active area of research and from what I understand relatively easy.
   It requires a coated glass plate and a laser to heat and release a droplet.

 - think of applications

Crazy applications I heard of is injecting droplets in chicken meat.  This preserves the dead meat longer. Also, some people were active in the making of perfume. This required making well defined mixtures.  Some chemicals are extremely expensive so if you can deliver small dosages or make small mixes that could be nice.

- make images of droplet formation with a stroboscopic camera

Everyone in this field does this. It's real easy and allows you to understand the process much better. Ideally you use global shutter camera with LED

Anyhow, good to see you are making so much progress :-)..

Also, the TNO project was not a commercial success.  Which must have been frustrating for those involved.

  Are you sure? yes | no

Paulo Campos wrote 01/17/2022 at 00:36 point

Dear Hexastorm, TNO project is really interesting! Thanks. Increase the ink viscosity is a good way to printing over difficult adhesion substrates, like polyolefins. CIJs printers has this limitation.

  Are you sure? yes | no

heinz wrote 05/28/2021 at 06:21 point

Wow 😍 This already looks too professional to be built by me for some precision dispensing.

Very cool, thanks for sharing.

  Are you sure? yes | no

Dominik Meffert wrote 05/28/2021 at 15:54 point

Thank you very much :)

If I can find out how to build the CIJ nozzle there will be more progress, soon.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates