Project Background

My final project is multiple elements of an installation to raise awareness and reduce harm from PFAS, also known as Forever Chemicals. Since I wanted to both improve my coding skills and practice the digital fabrication techniques I learned in class, I opted for an emphasis on coding the receipt printer and website along with a few other techniques for building the receipt container and organ.

Final Project

Slideshow of the exhibit




Video Overview







Process

I built upon the molding and casting week's project so I added to that process page. Reference back to week 8 for the organ component of the project with some additonal learnings!

Materials

Electronics and Software

  • ESP32-Mini-1
  • Arduino UNO
  • CSN-a2 micro panel printer x2
  • Breadboard x2
  • 5V charger x2
  • Electrical wires
  • Firebase
  • VS Code

Receipt Box

  • 1/4 inch white acrylic
  • Acrylic glue
  • Corner clamps x2
  • Trigger clamps x2
  • Laser cutter
  • Vinyl cuttter
  • Red vinyl 8x3 inch strip
  • Small magnet set x4

Configuring the printer

For this component of the installation, a printer creates a receipt based on a survey completed by each participant. The receipt prints the results of their survey. I selected the esp32-mini-1 because of the wifi capability and steered clear of the esp32-s2, which I used for previous projects, because it tended to be unreliable and less supported by community forums.

I followed this tutorial to test a sample print by pressing the printer button while I gave it power - check complete, the printer works.

Next, I wanted to test the connection between the printer and the esp32-mini-1, but the adafruit printer library was only working with an Arduino UNO so I changed to the Thermal Printer library and used the sample code for the esp-32 with some edits below. There was not much documentation on these changes, so it took quite a bit of testing to finally make it work.

The set up for the electronics were pretty simple so I won't spend much time. I used a 5V battery on each so that the receipt boxes could be completely free standing on the checkout counter.




               
                // made by BinaryWorlds
                // Not for commercial use, in other case by free to use it.
                // Just copy this text and link to oryginal repository: https://github.com/BinaryWorlds/ThermalPrinter

                // I am not responsible for errors in the library. I deliver it "as it is".
                // I will be grateful for all suggestions.

                // Tested on firmware 2.69 and JP-QR701
                // Some features may not work on the older firmware.

                #include 
                #include   // if error you can also use SoftwareSerial, check first_view_arduino

                #include "TPrinter.h"

                // You need to use max3485(for 3V3 logic lvl) or similar, if you have printer with rs232.
                // If you use esp32 or other MCU with 3v3 logic level you can try with logic level converter.

                // Check which pin pairs are responsible for communication on your board!
                const byte rxPin = 10;
                const byte txPin = 9;
                const int printerBaudrate = 19200;  // or 19200 usually

                const byte dtrPin = 4;  // if used

                HardwareSerial mySerial(1);
                Tprinter myPrinter(&mySerial, printerBaudrate);
                // you can assign here other stream like Serial1, Serial2, Serial3 etc

                void setup() {
                  micros();
                  Serial.begin(9600);                                         // monitor
                  mySerial.begin(printerBaudrate, SERIAL_8N1, rxPin, txPin);  // must be 8N1 mode
                  myPrinter.begin();                                          // you can edit what be happen in Tprinter.cpp, like delay time(2s)
                  myPrinter.enableDtr(dtrPin, LOW);                           // pinNR, busyState;
                  // my printer is busy when DTR is LOW,
                  // there is a high probability that you should change it to HIGH;
                  // if wrong - print will no start

                  // if you dont enable checking dtr, you should call this:
                  // myPrinter.autoCalculate();

                  // or you can set it manually using this:
                  // myPrinter.autoCalculate(0); // turn off
                  // myPrinter.setTimes(30000, 3000); // oneDotHeight_printTime, oneDotHeight_feedTime in micros
                  // last is worst option


                  myPrinter.println("charset:");
                  myPrinter.printCharset();

                  myPrinter.println("codepage:");
                  myPrinter.printCodepage();

                  myPrinter.justify('C');
                  myPrinter.println("center");
                  myPrinter.justify('R');
                  myPrinter.println("right");
                  myPrinter.justify('L');
                  myPrinter.println("left");

                  uint8_t list[] = {5, 10, 15, 20, 25};
                  myPrinter.setTabs(list, 5);
                  myPrinter.print("1");
                  myPrinter.tab();
                  myPrinter.print("2");
                  myPrinter.tab();
                  myPrinter.print("3");
                  myPrinter.tab();
                  myPrinter.print("4");
                  myPrinter.println();

                  myPrinter.setMode(FONT_B, DOUBLE_WIDTH, DOUBLE_HEIGHT);
                  myPrinter.println("FONT_B, bigger");
                  myPrinter.unsetMode(FONT_B);
                  myPrinter.println("FONT_A, bigger");

                  myPrinter.feed(6);
                  myPrinter.identifyChars("ą ę");  // UTF-8
                }

                void loop() {
                  myPrinter.printFromSerial();  // open monitor and print something
                }
               
              

I then began work on the firebase following a tutorial I used in a previous week. A few reminders: There will be a conflict in the libraries on the operator “+”. There is probably a more elegant solution, but I chose to delete the “+”.

I updated the web app to contain a simple form so that I might test printing survey results to a form. I then updated my code to read from the firebase database and print to the printer.

Learning: the printer and the esp32 use two different baud rates, but just using the printer baud rate of 9600 still allows for printing to both the receipt printer and the serial monitor. However, if I wanted to add another output device with a different baud rate to the same esp32 I imagine I would run into challenges.

Customizing the receipt prints and website

Now that the printer is working with a generic form and print, it's time to make it relevant to the project.

Update the firebase to contain the relevant fields

database with money owed, has been printed, and money spent variables

Update or create the following files

script.js. This will enable firebase communication necessary below and calculations for the survey page.

main.cpp. It will now communicate with the firebase to update the values once the below files are in place.

styles.css

survey html. When a user clicks true there should be an increase of 100 on the store credit. If they click false the money owed will increase by 100. When they click the "print receipt" button at the bottom of the page, the firebase database should update with their moneyOwed and storeCredit values shown on the right panel of this screen. The printer should also print a receipt with that user's Money Owed and Store Credit.

survey page

To make for a more realistic checkout experience, create a welcome html page to start the checkout process. This button on this page will take users to the survey.

welcome page

Once the code is working, host the website on github pages. One challenge with platform io is that the index page is inside of the public folder, which sometimes prevents hosting on github pages. I made a index.html file at the main folder and redirected it to public/index.html

The "forever" printer

One of the project goals was to show the cumulative impact of PFAS consumption using a never-ending printer. This printer's receipts represented the constant purchase of goods with PFAS. Since this printer did not need to respond to an input, coding an Arduino UNO to output receipts consistently worked well.

printer with long receipt


               
                /*------------------------------------------------------------------------
                Based on sketch for Adafruit Thermal Printer library for Arduino.
                
              #include "Adafruit_Thermal.h"
              #include "adalogo.h"
              #include "adaqrcode.h"

              #include "SoftwareSerial.h"
              #define TX_PIN 6 // Arduino transmit  YELLOW WIRE  labeled RX on printer
              #define RX_PIN 5 // Arduino receive   GREEN WIRE   labeled TX on printer

              SoftwareSerial mySerial(RX_PIN, TX_PIN); // Declare SoftwareSerial obj first
              Adafruit_Thermal printer(&mySerial);     // Pass addr to printer constructor
              // Then see setup() function regarding serial & printer begin() calls.

              // Here's the syntax for hardware serial (e.g. Arduino Due) --------------
              // Un-comment the following line if using hardware serial:

              //Adafruit_Thermal printer(&Serial1);      // Or Serial2, Serial3, etc.

              // -----------------------------------------------------------------------

              void setup() {

                pinMode(7, OUTPUT); digitalWrite(7, LOW);

                mySerial.begin(19200);  // Initialize SoftwareSerial
                //Serial1.begin(19200); // Use this instead if using hardware serial
                printer.begin();        // Init printer (same regardless of serial type)


              }

              void loop() {

                // clothes receipt

                printer.doubleHeightOn();
                printer.println(F("Forever Mart"));
                printer.doubleHeightOff();
                printer.println("How long is forever?");
                printer.feed(1);
                delay(3000L);         // Sleep for 3 seconds

              
                printer.setFont('B');
                printer.println("Date: 2023-04-28     Time: FOREVER");
                delay(3000L);         // Sleep for 3 seconds
                printer.println("Cashier: PFAS producing brands");
                printer.println("Customer: Those who purchase PFAS containing clothes");


                printer.setFont('A');
                printer.println("Item: Waterproof clothing");

                //barcode 
                printer.printBarcode("FOREVER", CODE39);
                printer.setBarcodeHeight(100);
                printer.printBarcode("123456789123", UPC_A);
                printer.feed(2);
                printer.println("PFAS (Per- and polyfluoroalkyl substances) are a group of man-made chemicals that can have harmful effects on human health and the environment.");
                printer.feed(1);
                delay(3000L);         // Sleep for 3 seconds
                printer.println("Thank you for visiting. Don't forget to shop PFAS-free!");
                printer.feed(2);
              
                

                printer.sleep();      // Tell printer to sleep
                delay(3000L);         // Sleep for 3 seconds
                printer.wake();       // MUST wake() before printing again, even if reset

                // makeup 
                  printer.doubleHeightOn();
                printer.println(F("Forever Mart"));
                printer.doubleHeightOff();
                printer.println("How long is forever?");
                printer.feed(1);
                delay(3000L);         // Sleep for 3 seconds

              
                printer.setFont('B');
                printer.println("Date: 2023-04-28     Time: FOREVER");
                delay(3000L);         // Sleep for 3 seconds
                printer.println("Cashier: PFAS producing brands");
                printer.println("Customer: Those who purchase PFAS containing makeup");


                printer.setFont('A');
                printer.println("Item: Waterproof mascara");


                // Barcode examples:
                // CODE39 is the most common alphanumeric barcode:
                printer.printBarcode("ADAFRUT", CODE39);
                printer.setBarcodeHeight(100);
                // Print UPC line on product barcodes:
                printer.printBarcode("123456789123", UPC_A);
                printer.feed(2);
                printer.println("PFAS are in waterproof makeup, but you can shop PFAS free at Axiology (Axiology is also zero waste). BH Cosmetics, Burts Bees, Credo, cocokind, Fenty Beauty, Follain Florence by Mills, HandM, Kiko Milano, Lashfood, Mad Hippie ,Megababe, Pacifica , Physicians Formula, PYT Beauty, The Ordinary. source: greenmatters");
                printer.feed(1);
                delay(3000L);         // Sleep for 3 seconds
                printer.println("Thank you for visiting. Don't forget to shop PFAS-free!");
                printer.feed(2);
                

                

                printer.sleep();      // Tell printer to sleep
                delay(3000L);         // Sleep for 3 seconds
                printer.wake();       // MUST wake() before printing again, even if reset
                printer.setDefault(); // Restore printer to defaults
              }

              
              




The Receipt Box



laser cut file for box

The receipt box used 1/4 inch white acrylic and was laser cut using the below svg.

receipt box

The box was assembled using acrylic glue, clamps, and magnets for the back panel to come on and off easily to access the battery and electronics.

receipt box

I tested a few designs for the vinyl cut sticker, but the vinyl cutter seemed to have trouble with the smaller letters so I went with the second design.




The Forever Juice Label

The final Forever Juice label was simply printed on to adhesive sticker paper, but there was a good lesson learnt along the way. The first attempt was on a heat transfer machine. The process was fairly simple - print a reverse image, heat stamp it on to the adhesive, scrape the adhesive. As you can see below, the sticker had a black background and vibrant colors. After several tests, it was clear that the heat transfer could not absorb enough pigment for a fully black background. Instead, it was more of a grey. This was a simple insight, but given that it is a new machine at the SEC, it will be helpful for future prints.