Thermodrucker Projekt

Hallo,

ich suche eine Möglichkeit für die Umsetzung eines Projektes. Ich versuche mal zu erklären, was am Ende bei raus kommen soll. Ich habe fünf Thermodrucker (adafruit Thermoprinter ttl), die jeweils in unterschiedlichen Zeitabstanden, kleine Text und Bitmap Grafiken drucken sollen. Also bei Sekunde 0 druckt Drucker 1 , bei Sekunden 30 Drucker 2, bei Sekunde 60 Drucker 3, usw. Jeder drucker muss innerhalb von 2h ca 70 Texte und Bilder drucken.
Bisher gibt es eine Excel Tabelle in der steht, wann welcher Text gedruckt werden soll.
Ich suche nun eine Möglichkeit das ganze möglichst leicht umzusetzen. Hätte auch noch 5 Arduinos, bin jedoch auch für andere Plattformen offen, wenn es den Ablauf erleichtert.
Wichtig ist, dass das Timing der einzelnen Drucker relativ genau stimmt und das es die Möglichkeit gibt das ganze zu loopen

Vielen Dank und viele Grüße

Na ok, aber was ist jetzt deine Frage ?

Bisher gibt es eine Excel Tabelle

na dann. Exportiere das in ein struct mit diesen Variablen:

drucker
startzeit
ausgabe

dann ein Array daraus und ein (oder fünf) Arduino kann das abarbeiten.

jzero:
Hätte auch noch 5 Arduinos ...

Welchen Typs?

jzero:
Wichtig ist, dass das Timing der einzelnen Drucker relativ genau stimmt ...

Ein Arduino ist keine Atomuhr, was manchmal relativ störend, manchmal aber auch relativ egal ist. Temperaturkompensierte Uhrmodule wie DS3231 kommen auf weniger als ein paar Minuten Abweichung pro Jahr. Was brauchst Du?

jzero:
Ich suche nun eine Möglichkeit das ganze möglichst leicht umzusetzen.

Ein UNO scheint zu genügen, allerdings kann ich mangels Drucker nicht testen, aber der Kompiler ist zufrieden:

/*------------------------------------------------------------------------
  You may need to edit the PRINTER_FIRMWARE value in Adafruit_Thermal.h
  to match your printer (hold feed button on powerup for test page).
  ------------------------------------------------------------------------*/
#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"

SoftwareSerial mySerial1(2,3); // Declare SoftwareSerial obj first, RX_PIN, TX_PIN
SoftwareSerial mySerial2(4,5);
SoftwareSerial mySerial3(6,7);
SoftwareSerial mySerial4(8,9);
SoftwareSerial mySerial5(10,11);
Adafruit_Thermal printer1(&mySerial1);     // Pass addr to printer constructor
Adafruit_Thermal printer2(&mySerial2);
Adafruit_Thermal printer3(&mySerial3);
Adafruit_Thermal printer4(&mySerial4);
Adafruit_Thermal printer5(&mySerial5);

void setup() {
  // NOTE: SOME PRINTERS NEED 9600 BAUD instead of 19200, check test page.
  mySerial1.begin(19200);  // Initialize SoftwareSerial
  mySerial2.begin(19200);  // Initialize SoftwareSerial
  mySerial3.begin(19200);  // Initialize SoftwareSerial
  mySerial4.begin(19200);  // Initialize SoftwareSerial
  mySerial5.begin(19200);  // Initialize SoftwareSerial
  printer1.begin();        // Init printer (same regardless of serial type)
  printer2.begin();        // Init printer (same regardless of serial type)
  printer3.begin();        // Init printer (same regardless of serial type)
  printer4.begin();        // Init printer (same regardless of serial type)
  printer5.begin();        // Init printer (same regardless of serial type)

  printer1.println(F("Drucker 1"));
  printer2.println(F("Drucker 2"));
  printer3.println(F("Drucker 3"));
  printer4.println(F("Drucker 4"));
  printer5.println(F("Drucker 5"));
}

void loop() {
}

Basiert auf A_printertest.ino.

Sollte wohl noch einmal etwas konkreter in meinen Aussagen werden..
Es sind 5 Arduino Uno vorhanden.
Die einzelnen Drucke sollten +-1 Sekunde genau starten.

Ich sollte auch erwähnen, dass ich es sich hierbei um ein studentisches Projekt handelt. Ich habe zwar Erfahrung mit Arduino, aber keine große Programmiererfahrung, bis auf Basics in Javascript.

Super, vielen dank. Ich werde den Code morgen testen und Rückmeldung geben.

Bisher habe ich noch Probleme zu verstehen, wie ich die Daten nach und nach auf den Arduino lade. Da alle Texte und Bilder zusammen sicher zu groß sind, um sie auf einmal auf den Arduino zu laden, frage ich mich wie das wohl funktionieren könnte.

jzero:
Bisher habe ich noch Probleme zu verstehen, wie ich die Daten nach und nach auf den Arduino lade. Da alle Texte und Bilder zusammen sicher zu groß sind, um sie auf einmal auf den Arduino zu laden, frage ich mich wie das wohl funktionieren könnte.

Tabelle auf SD-Karte als csv oder sowas speichern und mit dem Arduino lesen. Beispiele findest Du in der Bibliothek SdFat.

jzero:
Die einzelnen Drucke sollten +-1 Sekunde genau starten.

Über welchen Zeitraum?

Der UNO rechnet mit Millisekunden, ist aber relativ zur Uhrzeit der Atomuhr in Braunschweig nicht besonders genau bezogen auf die Zeit und die Schwankung.

jzero:
Bisher habe ich noch Probleme zu verstehen, wie ich die Daten nach und nach auf den Arduino lade. Da alle Texte und Bilder zusammen sicher zu groß sind, um sie auf einmal auf den Arduino zu laden, frage ich mich wie das wohl funktionieren könnte.

beschreibe dein Projekt genauer.
Woher kommen die Daten, wie groß sind diese in welchen Intervall wird es einen Ausdruck geben.
Wie kommst du überhaupt darauf, einen (5) Arduino nutzen zu wollen.

Beschreibe auch was das Endprodukt wirklich macht, denn nur “5 Stellen wo bedruckte Papierzettel rauskommen” ist ein wenig mager.

Sollte wohl noch einmal etwas konkreter in meinen Aussagen werden..

Ja!

Tipp:
LAN, LIN, CAN, RS485

Danke für die Tipps bisher, mit dem Code von agmue habe ich inzwischen die Drucker parallel zum laufen gebracht. Musste nur noch die TX und RX Pins definieren mit:

#define TX_PIN1 2 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN1 3 // Arduino receive   GREEN WIRE   labeled TX on printer

#define TX_PIN2 6 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN2 5 // Arduino receive   GREEN WIRE   labeled TX on printer

SoftwareSerial mySerial1(RX_PIN1, TX_PIN1);
SoftwareSerial mySerial2(RX_PIN2, TX_PIN2);

So dann jetzt nochmal genauer zum Aufbau:

in einem Raum werden im Abstand von einem Meter Thermodrucker Modell QR701 TTL aufgestellt. Der Druck soll wie folgt ablaufen:
Drucker1 0:00
Drucker2 0:20
Drucker3 0:40
Drucker4 1:00
Drucker5 1:20
Drucker1 1:40
Drucker2 2:00
Drucker3 2:20
Drucker4 2:40
Drucker5 3:00
Drucker1 3:20
Drucker2 3:40
Drucker3 4:00
Drucker4 4:20
Drucker5 4:40
usw.

So jetzt nochmal zur Tabelle mit den Daten. In der Excel Datei, gibt es für jeden Drucker eine Tabelle mit einer Spalte mit 70 Zeilen. In jeder Zeile befindet sich ein anderer Text mit max 900 Zeichen. Der Text beinhaltet generierte Texte. Die Bitmap Grafiken werden vereinheitlicht, jetzt gibt es nur noch eine Bitmap Grafik mit 24kB die über jedem Text abgedruckt werden soll. Hierbei handelt es sich um fünf einfarbige 5 eckige Sterne. Die Grafiken wandle ich mit Hilfe dieses Processing Scripts in eine für Arduino verwertbare Datei.

Beim den Test heute habe ich noch ein weiteres Problem festgestellt. Wenn ich den Text mit println ausgebe, wird der Text zwar ausgedruckt allerdings für meine Zwecke in der falschen Richtung, also doppelt Spiegelverkehrt. Siehe Abbildung:

Ich dachte vl ist die Lösung auch die Texte zuerst in Illustrator anzulegen und dann mit dem Processing Script in eine Bitmap umzuwandeln. Allerdings ist dann das Problem, dass in der Variable zu viele Zeichen sind. Jedenfalls kommt beim compilen folgende Fehlermeldung: "size of variable is too large"
Fände die Variante über Illustrator allerdings spannend, da ich dann eine andere Schriftart, Abstände usw. verwenden könnte. Die Einzelnen Texte in Illustrator anzulegen und mit Processing in eine für Arduino verarbeitbare Datei zu verarbeiten, wäre für mich kein Problem.

Das Processing Skript gibt Dateien aus, welche wie folgt aufgebaut sind (in meinem Fall natürlich viel länger, als hier abgebildet):

#ifndef _txt_h_
#define _txt_h_

#define txt_width  380
#define txt_height 989

static const uint8_t PROGMEM txt_data[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
#endif

Habe außerdem gerade beim kramen noch eine Arduino Mega gefunden, der noch funktioniert. Habe mir jetzt auch einen SD Karten Slot bestellt und bin gespannt, ob ich das hin bekomme.

jzero:
Ich sollte auch erwähnen, dass ich es sich hierbei um ein studentisches Projekt handelt.

Bei Studierenden bin ich etwas pingeliger, Du wirst ja schließlich auch meine Zukunft gestalten :wink:

jzero:
Danke für die Tipps bisher, mit dem Code von agmue habe ich inzwischen die Drucker parallel zum laufen gebracht.

Sehr schön!

jzero:
Musste nur noch die TX und RX Pins definieren mit:

Nö. Ich vermute, Du mißverstehst #define. Diese beiden Varianten tun dasselbe:

#define TX_PIN1 2 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN1 3 // Arduino receive   GREEN WIRE   labeled TX on printer
SoftwareSerial mySerial1(RX_PIN1, TX_PIN1);
SoftwareSerial mySerial1(3, 2);  // RX_PIN, TX_PIN

In "TX_PIN1" steckt natürlich eine erläuternde Bedeutung für den Leser, für den Kompiler ist es nur eine Textersetzung. Manche mögen lieber diese Variante:

const byte TX_PIN1 = 2 // Arduino transmit  YELLOW WIRE  labeled RX on printer
const byte RX_PIN1 = 3 // Arduino receive   GREEN WIRE   labeled TX on printer
SoftwareSerial mySerial1(RX_PIN1, TX_PIN1);

jzero:
So jetzt nochmal zur Tabelle mit den Daten.

Der SD-Karte ist egal, was Du speicherst, Du mußt es nur am PC bearbeiten und im Arduino auswerten können.

jzero:
Habe außerdem gerade beim kramen noch eine Arduino Mega gefunden, der noch funktioniert.

Dann hast Du genügend Pins und auch mehr Speicher, das kann im Zweifel nicht Schaden. Ich habe schon Programme auf dem Mega entwickelt und dann für den UNO/Nano/PriMini eingedanpft.

Danke für die Hilfe, langsam glaube ich zu verstehen, wie ich vorgehen muss. Werde die nächsten Tage weiter viel lesen und versuchen zu verstehen.

Nochmal eine Verständnisfrage:
Angenommen ich konvertiere Text und Bild zu einer bmp mit dem Converter aus dem obrigen Post. Dann erhalte ich jeweils eine Header Datei, die Text und Bild als bmp beinhaltet. Wäre es dann möglich bzw sinnvoll alle .h Header Dateien auf die SD Karte zu packen und im Loop alle Header Dateien nacheinander mit 20 Sekunden Verzögerung immer in der Reihenfolge der Drucker 1-5 auszudrucken?

Hier ist der Code den ich bisher habe, der einfachheit erstmal mit einem Drucker:

#include "Adafruit_Thermal.h"


#include "b8.h"



// Here's the new syntax when using SoftwareSerial (e.g. Arduino Uno) ----
// If using hardware serial instead, comment out or remove these lines:

#include "SoftwareSerial.h"


#define TX_PIN2 6 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define RX_PIN2 5 // Arduino receive   GREEN WIRE   labeled TX on printer

SoftwareSerial mySerial2(RX_PIN2, TX_PIN2);
// Declare SoftwareSerial obj first   
Adafruit_Thermal printer2(&mySerial2);// 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() {


  // NOTE: SOME PRINTERS NEED 9600 BAUD instead of 19200, check test page.
 
  mySerial2.begin(9600); // Initialize SoftwareSerial
  //Serial1.begin(19200); // Use this instead if using hardware serial
 
    printer2.begin();// Init printer (same regardless of serial type)

  // The following calls are in setup(), but don't *need* to be.  Use them
  // anywhere!  They're just here so they run one time and are not printed
  // over and over (which would happen if they were in loop() instead).



}

void loop() {
  printer2.printBitmap(b7_width, b7_height, b7_data);
printer2.printBitmap(b8_width, b8_height, b8_data);

}

Ich würde gerne erreichen, dass dieser Befehl

printer2.printBitmap(b8_width, b8_height, b8_data);

immer durch eine neue header datei ausgetauscht wird, durch die nächste .h Datei, die sich auf der SD Karte befindet und es auf den nächsten der 5 Drucker springt.

Oder gibt es eine Möglichkeit das ganze einfacher zu lösen?

jzero:
Wäre es dann möglich bzw sinnvoll alle .h Header Dateien auf die SD Karte zu packen

Nein, denn die h-Dateien sind Teil des Programms und werden vom Kompiler benötigt.

Wenn der Programmspeicher des Arduinos ausreicht, dann kannst Du alle h-Dateien einbinden.

Wenn nicht, brauchst Du einen größeren Arduino oder packst die Daten auf die SD-Karte.

Nein. Was erwartest du dir von der .h auf der SD Karte? Damit kann der Arduino zur Laufzeit nichts anfangen. Der kompiliert nicht!

Das klingt logisch. D.h. die Variablen die bisher in den h-Dateien gespeichert werden kommen dann in eine csv? auf der SD Karte.
Aber ist es grundsätzlich möglich, in der loop Funktion je Durchlauf eine neue Zeile einzulesen und dann auf einem Drucker zu drucken? Die Drucker müssten dann von 1-5 rotieren.

Du kannst aber nicht 5 Dateien gleichzeitig öffnen. Dann müsstest Du die Daten in der richtigen Reihenfolge in einer Datei sammeln.

Gruß Tommy

jzero:
… die Variablen die bisher in den h-Dateien gespeichert werden …

Weder Variablen noch Konstanten, sondern Programmspeicher PRGMEM.

jzero:
… kommen dann in eine csv? auf der SD Karte.

Ja, so wäre mein Vorschlag (ich habe das noch nie gemacht!).

jzero:
Aber ist es grundsätzlich möglich, in der loop Funktion je Durchlauf eine neue Zeile einzulesen und dann auf einem Drucker zu drucken? Die Drucker müssten dann von 1-5 rotieren.

Ja.

Ob man csv-Datei und Grfikdateien trennt oder alles ein eine Datei schreibt, müßte man überlegen.

So, nachdem ich Probleme mit den Druckernetzteilen hatte, geht’s hiermit wieder weiter.

Programmspeicher PRGMEM ist dazu nötig, dass es nicht im SRAM sondern im Flash Speicher gespeichert wird, oder? Der ist ja in dem Fall deutlich größer und somit genau das was ich brauche.

Ich habe nun eine Weile versucht Daten von einer SD-Karte zu lesen und an den Drucker weiter zu geben. Daran scheitere ich heute allerdings schon eine Weile.
Hier ist der Versuch dazu:

/*------------------------------------------------------------------------
  Example sketch for Adafruit Thermal Printer library for Arduino.
  Demonstrates a few text styles & layouts, bitmap printing, etc.

  IMPORTANT: DECLARATIONS DIFFER FROM PRIOR VERSIONS OF THIS LIBRARY.
  This is to support newer & more board types, especially ones that don't
  support SoftwareSerial (e.g. Arduino Due).  You can pass any Stream
  (e.g. Serial1) to the printer constructor.  See notes below.

  You may need to edit the PRINTER_FIRMWARE value in Adafruit_Thermal.h
  to match your printer (hold feed button on powerup for test page).
  ------------------------------------------------------------------------*/

#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"
#include <SPI.h>
#include <SD.h>
#include "b7.h"

//SD Karte File
File myFile;
// Pins für Drucker
#define RX_PIN1 9 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define TX_PIN1 10 // Arduino receive   GREEN WIRE   labeled TX on printer

#define RX_PIN2 5 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define TX_PIN2 6 // Arduino receive   GREEN WIRE   labeled TX on printer

#define RX_PIN3 11 // Arduino transmit  YELLOW WIRE  labeled RX on printer
#define TX_PIN3 12 // Arduino receive   GREEN WIRE   labeled TX on printer



// Software Serial für Drucker
SoftwareSerial mySerial1(RX_PIN1, TX_PIN1);
SoftwareSerial mySerial2(RX_PIN2, TX_PIN2);
SoftwareSerial mySerial3(RX_PIN3, TX_PIN3);

Adafruit_Thermal printer1(&mySerial1);
Adafruit_Thermal printer2(&mySerial2);
Adafruit_Thermal printer3(&mySerial3);


void setup() {


// Drucker
  mySerial1.begin(9600);
  mySerial2.begin(9600); // Initialize SoftwareSerial
  mySerial3.begin(9600);
 
 printer1.begin();
 printer2.begin();
 printer3.begin();
 
//SD Karte einlesen
Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(53)) {      
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

// SD Karte test.txt öffnen und in Serial Monitor ausgeben
  myFile = SD.open("test.txt");
  if (myFile) {
  

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  }
 

  
// Mit drei Drucker nacheinander drucken



printer1.printBitmap(b7_width, b7_height, b7_data);
printer2.printBitmap(b7_width, b7_height, b7_data);
printer3.printBitmap(b7_width, b7_height, b7_data);

}

void loop() {

}

Der Einfachheit halber, habe ich bisher nur mit drei Drucker gearbeitet. Soweit funktioniert bisher, dass die Daten einer bitmap Datei aus der txt Datei im Serial Monitor ausgegeben werden. Die txt-Datei auf der SD Karte beinhaltet im Moment genau den Inhalt der b7.h Datei (siehe Anhang, war zu groß um es einzubinden), welche ich auch im Sketch eingebunden habe. Diese ist im Moment noch eingebunden, um zu testen, ob die drei Drucker nacheinander drucken können.
Im nächsten Schritt würde ich gerne schaffen, dass die b7.h nichtmehr eingebunden werden muss, sondern direkt von einer csv die auf der SD karte liegt ausgelesen wird und gedruckt werden kann. Ich weiß allerdings nicht, wie ich das am besten mache. Muss in der csv nur der reine bitmap Code eingefügt werden und nicht der Befehl es in den PRGMEM Speicher zu laden, oder muss der komplette inhalt der b7.h in jeweils eine Zeile der csv Datei? Habe mich heute schon eine Weile damit beschäftigt, aber komme leider nicht weiter.

Vielen Dank für die Hilfe und viele Grüße
Johannes

b7.h (145 KB)

jzero:
Programmspeicher PRGMEM ist dazu nötig, dass es nicht im SRAM sondern im Flash Speicher gespeichert wird, oder?

Ja.

jzero:
Der ist ja in dem Fall deutlich größer und somit genau das was ich brauche.

Für den Mega2560 reicht der Speicher auch für fünf Grafiken:

[sub]Der Sketch verwendet 130574 Bytes (51%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 1231 Bytes (15%) des dynamischen Speichers, 6961 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.
[/sub]

Damit kannst Du zwischen Grafikdaten

  • im Programmspeicher
  • auf der SD-Karte
    wählen.