AdSense

Samstag, 10. November 2018

Halbautomatischer Mehrfarbendruck mit dem Ultimaker 2+

(English version) Sehr lange, ziemlich genau 2 Jahre ist hier nichts mehr passiert - das will ich nun ändern. Ich arbeite momentan an einem Projekt, welches ich auf jeden Fall teilen will: Ich rüste meinen Ultimaker 2+ um, sodass ich mehrere Farben drucken kann, bis zu 15 ist da der aktuelle Plan. Dazu werde ich in Zukunft, vor allem wenn ich den Umbau überhaupt ersteinmal vorgenommen habe, mehr schreiben. Heute möchte ich aber schonmal die Vorstufe davon präsentieren: Halbautomatischer Mehrfarbendruck mit dem Ultimaker 2+. Die Grundidee ist dabei sowohl beim vollautomatischen als auch beim halbautomatischen Mehrfarbendruck, dass nur eine Nozzle benutzt wird und der Drucker immer das alte Filament herauszieht und dann das neue durchdrückt, vergleichbar mit dem Prusa i3 Multi-Material Upgrade, hier wird auch nur eine Nozzle verwendet.

Zuerst einmal: Was meine ich mit halbautomatisch? Ganz einfach: Der Drucker druckt eine Farbe, irgendwann wirft er das Material aus und wartet, bis ich das andere Material hineingetan habe. Damit kann man einfache Sachen drucken, welche z.B. aus einer Grundfarbe bestehen und ab einer gewissen Höhe eine andere Farbe haben - Beispiele wären hierfür z.B. Schrift auf einem Objekt, ein Leitkegel (https://www.thingiverse.com/thing:3207478) oder z.B. aus dem Bereich des Geländebaus dieses "Gemüsebeet" (https://www.thingiverse.com/thing:3207486).

Was musste ich dafür anpassen? Am Drucker? Gar nichts! Das ist das Tolle. Als Slicer habe ich nun "Slic3r" genommen, da ich hier benutzerdefinierten G-Code einfügen kann und die Software theoretisch beliebig viele Extruder unterstützt. Ich werde hier jetzt Schritt für Schritt erklären, wie meine Druckprofile in Slic3r aussehen. Zuerst die Printer Settings in Slic3r:

Hier habe ich jetzt für jeden Extruder das Folgende eingestellt:

Im Bereich Custom G-code habe ich die folgenden Sachen stehen:
Start G-code
M109 S[first_layer_temperature] ; heat nozzle to first layer temperature and wait until reached
G21 ; metric values
G90 ; absolute positioning
M82 ; Extruder to Absolute
G28 ; home all axes
G1 X7 Y7 F6000 ; bring extruder to the front
G1 Z25 F2000 ; Raise Bed to Head
G92 E0 ; zero the extruded length
T0 ; Select Extruder 1
G92 E0 ; Zero Extrude L
G1 F200 E8 ; Extrude 16 @ 200mm/s
G92 E0 ; Zero Extrude L
G1 F50 E4 ; Extrude 16 @ 50mm/s
G92 E0 ; Zero Extrude L
G1 F20 E2 ; Extrude 2 @ 20mm/s
G1 X100 Y7 F6000 ; bring extruder to the front
G92 E0 ; Zero Extrude L
G92 E0 ; zero the extruded length again
End G-code
; Add Change Tool To Extruder 0 here

G92 E0 ; zero the extruded length
G1 E-2 F200 ; Extrude(Retract) -2mm @ 50mm/s
G28 ; home all
M104 S0 ; turn off heaters
M140 S0 ; turn off bed
M84 ; disable motors
Before layer change G-code
;XXX Before Layer Change
After layer change G-code
;LayerChange
G90 ; absolute positioning
G1 X190 Y190 F6000;

G92 E0 ; zero the extruded length
;G1 E7 F2100 ; Retraction compensation


;Prime Tower

;Prime Tower Routine
G91; Relative mode
G1 Z-1 F2100; Lower Head 1mm
G90 ; absolute positioning
G1 X180 Y190 F6000;
G91; Relative mode

;Rectangle around
G1 Y16 E7.1 F600
G1 X-128 E1 F1200
G1 Y-16 E0.1
G1 X128 E1
G1 Y-16 E0.1
G1 X-128 E1
G1 Y16 E0.1

;Prime Nozzle
;G1 X-128 F3600;No extrusion because part of border


G1 X16 Y-16 F6000
G1 Y32 E0.1 F1200
G1 X16  F6000
G1 Y-32 E0.1 F1200
G1 X16 F6000
G1 Y32 E0.1 F1200
G1 X16 F6000
G1 Y-32 E0.1 F1200
G1 X16 F6000
G1 Y32 E0.1 F1200
G1 X16 F6000
G1 Y-32 E0.1 F1200
G1 X16 F6000
G1 Y32 E0.1 F1200
G1 X16 F6000
;G1 E-7 F2100 ; Retract
G1 Y-32 E-6.9 F1200;No extrusion because part of border

G1 Z1 F2100; Raise Head 1mm

G90 ; absolute positioning
G92 E0 ; zero the extruded length


;Retract
;G92 E0
;LayerEnd
Tool change G-code
;XXX Tool Change
;M104 S100
G90 ; absolute positioning
G1 X190 Y190 F6000;

G92 E0 ; zero the extruded length
G1 E-399 F10000 ; Extrude(Retract) -500mm @ 50mm/s
G1 E-40[next_extruder] F30 ; Extrude(Retract) -1mm @ 1mm/s
G1 E-715 F10000 ; Extrude(Retract) -500mm @ 50mm/s

G92 E0 ; zero the extruded length
G1 F50 E-40 ; Extrude 8 @ 50mm/s

M0;

;M104 S[temperature_0]
G90 ; absolute positioning
G92 E0 ; zero the extruded length
G1 F50 E20 ; Extrude 8 @ 50mm/s

G92 E0 ; zero the extruded length
G1 E700 F10000 ; Extrude(Insert)500mm @ 50mm/s

G92 E0 ; zero the extruded length
G1 F50 E20 ; Extrude 16 @ 50mm/s


;Prime Tower

;Prime Tower Routine
G91; Relative mode
G1 Z-1 F2100; Lower Head 1mm
G90 ; absolute positioning
G1 X180 Y190 F6000;
G91; Relative mode

;Prime Nozzle
G1 Y1 F6000
G1 Y[next_extruder] F6000
G1 X-128 E2 F700
G1 Y-16 F6000
G1 X128 E2 F700
G1 Y-1 F6000
G1 Y-[next_extruder] F6000
G1 X-128 F6000

G1 X1 F6000
G1 X[next_extruder] F6000
G1 Y32 E0.2 F700
G1 X16 F6000
G1 Y-32 E0.2 F700
G1 X16 F6000
G1 Y32 E0.2 F700
G1 X16 F6000
G1 Y-32 E0.2 F700
G1 X16 F6000
G1 Y32 E0.2 F700
G1 X16 F6000
G1 Y-32 E0.2 F700
G1 X16 F6000
G1 Y32 E0.2 F700
G1 X16 F6000
G1 Y-32 E-6.8 F700

G1 Z1 F2100; Raise Head 1mm

G90 ; absolute positioning
G92 E0 ; zero the extruded length


;Retract
;G92 E0
;ToolEnd
Als nächstes kommen die Filament Settings für Filament und Cooling:







 
Als nächstes kommt nun der größte Block, nämlich die Print Settings mit allen Unterkategorien:














Hier sollte natürlich der richtige Pfad zu dem entsprechenden Skript eingetragen werden. Ich musste nämlich ein Post-Script schreiben, welches meinen G-Code bearbeitet, da Slic3r T0, T1, ... für die verschiedenen Extruder verwendet - ich aber nur einen benutze. Füttert man den Ultimaker mit T1, so bewegt sich der erste (und einzige) Extruder nicht mehr, was in diesem Fall ja der falsche Ansatz wäre. Das Post-Script tut 2 Dinge:
  • Alle T1, T2, ... zu T0 ändern
  • Ein Problem mit der Retraction beheben - Slic3r macht eine Retraction bei Tools die ich nicht benutze bzw. schiebt das Material nach dem Custom G-Code wieder in die Nozzle. Das macht er aber nicht, wenn ich ein Tool zum ersten Mal verwende, da Slic3r ja in diesem Tool auch kein Material herausgezogen hat. Daher checkt mein Post-Script, ob in der entsprechenden Zeile nach einem Tool Change ein E7-Befehl ist, also ob das Material 7mm wieder in die Nozzle gedrückt wird, falls nicht fügt das Post-Script dies hinzu
Das Post-Script ist in Octave (Matlab-ähnlich) geschrieben, das sollte man sich also ebenfalls installieren. Mein PostScript "StartOctave.bat" sieht so aus:
C:\Octave\Octave-4.2.1\octave.bat C:\Slic3rSkripte\OctavePostScript.m %1
Es ruft also die Datei "OctavePostScript.m" auf, welche so aussieht:
s = argv(){1};

myfile = fopen("testOctave.txt", "w");
fprintf(myfile, "%s\r\n", s);
fclose(myfile);

%s = "I:\Traffic_Cone_Rings_Orange.gcode";
myfile = fopen (s, "r");
outText = [];
tline = fgetl(myfile);
i = 1;
outText{i} = tline;
while ischar(tline)
  i = i+1;
  outText{i} = tline;
 
 
  tline = fgetl(myfile);
end
imax = i;
fclose(myfile);

myfile = fopen(s, "w");
%fprintf(myfile, ";EDITED!\r\n");
insertLine = 0;
for i=1:imax
  tempLine = outText{i};
 
  if (size(tempLine,2) > 1)
    if (tempLine(1) == "T")
      outText{i} = "T0";
    end
  end
 
 
  if (strcmp(tempLine,";ToolEnd"))
    insertLine = 7;
  end
  
  if (insertLine > 0)
    insertLine = insertLine -1;
  end
 
  if (insertLine == 1)
    if (tempLine(4) == "E")
    else
      fprintf(myfile, "G1 E7.00000 F2100.00000\r\n");
      fprintf(myfile, "G92 E0 \r\n");
    end
  end

  fprintf(myfile, "%s\r\n", outText{i});
end
fclose(myfile);
Nun muss also nur noch ein Objekt in Slic3r geladen werden, über Rechtsklick-Settings kann man dann mit "Load Part" die weiteren Farb-Objekte dazu laden und dann den jeweiligen Extruder bzw. die jeweilige Farbe einstellen. Für Tests könnte man also die Thingiverse-Links oben von mir nutzen.

Der Quellcode ist definitiv noch ausbaufähig, wer Verbesserungsvorschläge hat kann diese mir gerne mitteilen, man sollte das alles auch unter dem Hintergrund betrachten, dass ich bereits versuche, alle auf einen automatischen Materialwechsel auszulegen, sodass einige Sachen vielleicht teilweise etwas zu kompliziert aussehen könnten.

Sonntag, 11. September 2016

DHT11 Sensor mit Arduino auslesen

(English version) Vor einizger Zeit habe ich einen Temperatur- und Luftfeuchte-Sensor gekauft, die Bezeichnung lautet DHT11. Der Sensor ist einfach zu benutzen und verträgt sowohl 3,3V als auch 5V. Der Sensor hat 4 Pins, für den normalen Betrieb werden aber nur 3 Pins benötigt.
Der linke Pin (wie im Bild erkennbar) wird mit 5V verbunden, der rechte Pin mit GND. Der linke der beiden mittleren Pins ist der Signal-Pin, dieser wird mit einen beliebigen Digital-Pin am Arduino verbunden (in diesem Fall ist das Kanal 2). Außerdem wird noch ein 10k Widerstand zwischen dem Daten-Pin und 5V benötigt.

Als nächstes benötigt man die entsprechende Library, diese gibt es hier: Download. In der Arduino Software wird dann der Sensor wie folgt ausgelesen. Der Quellcode sollte selbsterklärend sein. Falls ein Sensor mit höherer Genauigkeit benötigt wird kann auch ein DHT22 benutzt werden, das muss dann entsprechend in DHTTYPE geändert werden.

#include "DHT.h"
#define DHTPIN 2

#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);

  dht.begin();
}

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(" *C ");

  delay(2000);
}

Sonntag, 17. Juli 2016

3D-Druckprofile für den Ultimaker 2

(English version) Nachdem lange Zeit nichts hier auf dem Blog passiert ist möchte ich ein weiteres Thema aufnehmen: 3D-Druck. Ich selbst besitze einen Ultimaker 2 und möchte in diesem ersten Post nun einmal die Druckprofile vorstellen, welche ich benutze. Ich drucke ausschließlich mit schwarzem PLA von Innofill - dadurch muss ich kein Feintuning vornehmen wenn ich neues Material kaufe, da die Eigenschaften gleich bleiben.

Ultimaker 2:
Am Drucker selbst habe ich relativ wenig eingestellt. Ich habe drei Profile: Fast, Fine und Ultrafine. Für alle drei benutze ich als Heatbed Temperature 70 °C. Das sorgt dafür, dass der Druck sehr gut anhaftet. Die Nozzle Temperatures sind 210 °C für Fast, 195 °C für Fine und 172 °C für Ultrafine. 172 °C ist sehr nahe am Schmelzpunkt, daher muss bei Temperaturwechsel in der Wohnung (Sommer / Winter) auch diese Temperatur leicht angepasst werden, im Winter habe ich eher 175 °C.

Druckprofile für Cura:
Im allgemeinen braucht man bei PLA keine Kühlung durch die Lüfter, aktiviert man diese dennoch führt das dazu, dass sich der Druck an den Kanten vom Druckbett hochzieht. Daher haben die Profile Fast und Fine eine Minimum Fan Speed von 10%, während bei Ultrafine 60% eingestellt ist, sodass kleine Strukturen besser gekühlt werden und nicht während dem Druck anfangen zusammenzuschmelzen.
Die Layer Height ist 0,1 mm für Fast und 0,05 mm für Fine und Ultrafine. Die Shell Thickness ist 0,8 mm.
Als Druckgeschwindigkeit benutze ich 25-40 für Fast, 20-25 für Fine und 10-25 für Ultrafine.

Wer Interesse an den Profilen hat kann sie hier herunterladen:
Fast
Fine
Ultrafine

Mittwoch, 23. September 2015

nrf24l01+ mit dem ATtiny84

(English version) Ich habe bereits erklärt, wie man das Funkmodul nrf24l01+ am Arduino bzw. ATmega betreibt. Die Details können in diesem Post nachgelesen werden. Möchte man das Funkmodul jedoch an einem ATtinyx4, wie zum Beispiel dem ATtiny84 betreiben, sind einige Anpassungen nötig.

In diesem Post möchte ich erklären, wie man eine Funkstrecke zwischen einem Arduino und dem ATtiny aufbaut. Ich verwende dazu das ping-Bespiel der Mirf-Library. Der Arduino sendet ein Ping-Signal aus, der ATtiny empfängt es und sendet es zurück.

Voraussetzung ist, dass ihr die ATtiny-Cores für die Arduino IDE installiert habt, wie ich es HIER beschrieben habe.

Nötige Libraries

Das Modul nrf24l01+ kommuniziert über SPI mit dem Mikrocontroller. Der ATtiny hat anders als der ATmega keine hardwareseitige Unterstützung für SPI, SPI muss also softwareseitig emuliert werden. Dies geschieht über das sogenannte Universal Serial Interface (USI). Dafür gibt es zum Glück wie immer eine fertige Library, wir müssen uns also um nix kümmern. Außerdem sind Änderungen an der Mirf-Library notwendig, doch auch hier hat sich schon jemand die Arbeit gemacht und eine passend Lib erstellt. Beide Libs können HIER herunter geladen werden. Nachdem ihr die beiden Ordner "Mirf" und "SPI85" in den entsprechenden "libraries"-Ordner der Arduino IDE kopiert habt, stehen euch die Libs wie gewohnt zur Verfügung.

Hardware

Die Verkabelung erfolgt ähnlich wie im Beispiel mit dem ATmega. Es müssen CSN, CE, SCK, MOSI und MISO sowie VCC und GND angeschlossen werden. Ich weise nochmal darauf hin, dass das Modul mit 3,3V betrieben werden muss! Folgende Grafik zeigt eine mögliche Verkabelung mit dem ATtiny84:
  
Wichtiger Hinweis: im Datenblatt des ATtiny gibt es zwar Pins, die mit MISO, MOSI und SCK bezeichnet sind, diese sind aber NUR zum Anschluss des Programmers (z.B. USBasp geeignet). Das Funkmodul muss mit den Pins USI-DI (entspricht MISO), USI-DO (entspricht MOSI) und USCK (entspricht SCK) verbunden werden. Standardmäßig sind dies die Pins D4 bis D6 (siehe Grafik oben). Prinzipiell sind die Pins aber frei wählbar. Wichtig ist, dass USI-DI nicht auf den MISO-Pin des Programmers gelegt werden darf. Dieses gilt ebenso für USI-DO und den MOSI-Pin. 

Software

Auf dem Arduino läuft unverändert das Beispiel "ping_client" der Mirf-Library. Auf dem ATtiny läuft eine angepasst Version des Beispiels "ping_server":

#include <SPI85.h>
#include <Mirf.h>
#include <MirfHardwareSpi85Driver.h>

// This USI was defined in SPI85.cpp
// Not to be confused with SPI (MOSI/MISO) used by ICSP pins
// Refer to page 61 of attiny84 datahseet
// USI pins could be redefined here
//#define USI-DO  5
//#define USI-DI  4
//#define USCK   6

#define CE    7    
#define CSN   3 

void setup(){

  
  /*   * Set the SPI Driver.   */

  Mirf.spi = &MirfHardwareSpi85;
    
  /*   * Setup pins / SPI.   */
  
  Mirf.cePin = CE;
  Mirf.csnPin = CSN;
  Mirf.init();
  
  /*   * Configure reciving address.   */
   
  Mirf.setRADDR((byte *)"serv1");
  
  /*   * Set the payload length to sizeof(unsigned long) the   * return type of millis().   *   * NB: payload on client and server must be the same.   */
   
  Mirf.payload = sizeof(unsigned long);
  
  /*   * Write channel and payload config then power up reciver.   */
   
  Mirf.config();

}

void loop(){
  /*   * A buffer to store the data.   */
   
  byte data[Mirf.payload];
  
  /*   * If a packet has been recived.   *   * isSending also restores listening mode when it    * transitions from true to false.   */
   
  if(!Mirf.isSending() && Mirf.dataReady()){

    /*     * Get load the packet into the buffer.     */
     
    Mirf.getData(data);
    
    /*     * Set the send address.     */
     
     
    Mirf.setTADDR((byte *)"clie1");
    
    /*     * Send the data back to the client.     */
     
    Mirf.send(data);
    
    /*     * Wait untill sending has finished     *     * NB: isSending returns the chip to receving after returning true.     */
      
    
  }
}

Der einzige Unterschied im Vergleich zur Version für den ATmega ist, dass SPI85.h sowie MirfHardwareSpi85Driver.h eingebunden werden und im setup() MirfHardwareSpi85 als SPI-Treiber ausgewählt wird:
Mirf.spi = &MirfHardwareSpi85;

Wenn ihr den Code mit eurem Programmer auf den ATtiny übertragt, sollte der pingende Arduino nun eine Antwort vom ATtiny bekommen.

Ein kleiner Hinweis zum Schluss: bei mir gab es Probleme mit dem Upload der Software über den USBasp, sobald das Funkmodul am ATtiny angeschlossen war. Das liegt vermutlich daran, dass sich der USBasp sowie das Modul die Pins am ATtiny teilen. Ich muss daher während dem flashen des ATtiny die Spannungsversorgung des Funkmoduls unterbrechen, dann klappt alles problemlos.

Dienstag, 22. September 2015

ATtiny mit der Arduino IDE programmieren - RELOADED

(English version) Vor einiger Zeit habe ich schon mal einen Beitrag zum Thema "ATtiny und Arduino" verfasst. In diesem habe ich erklärt, wie man die sogenannten "ATtiny-Cores" für Arduino installiert, damit man mit der Arduino IDE auch ATtinys programmieren kann.

Da ich für ein anderes Projekt einen anderen Core verwendet habe, möchte ich diesen hier auch nochmals kurz vorstellen. Es handelt sich dabei um Core-Dateien für ATtiny25, ATtiny45, ATtiny85, ATtiny24, ATtiny44 und ATtiny84.

Die nötigen Dateien können HIER heruntergeladen werden. Das entpackte Verzeichnis wird dann ebenfalls in den Ordner "hardware" kopiert. Die Ordnerstruktur sähe dann beispielsweise so aus: "C:\Programme\Arduino\hardware\tiny". Im Ordner "tiny" öffnet ihr den Unterordner "avr" und bennent dort die Datei "Prospective Boards.txt" um in "boards.txt" - sonst wird der Core von der IDE nicht erkannt.

Nach einem Neustart der Arduino IDE könnt ihr dann unter "Werkzeuge" - "Platine" den gewünschten ATtiny auswählen und ihn mit einem Programmer wie z.B. dem USBasp programmieren ("Sketch" - "Hochladen mit Programmer"). Wichtig ist, dass die Fuses im ATtiny richtig gesetzt sind und zur ausgewählten Platine passen.

Die Pinbelegung kann der Datei "pins_arduino.c" im Ordner "tiny\avr\cores\tiny" entnommen werden. Für den ATtinyx4 lautet sie beispielsweise:
//
//                                        +-\/-+
//                               VCC  1|    |14  GND
//                     (D  0)  PB0  2|    |13  AREF (D 10)
//                     (D  1)  PB1  3|    |12  PA1  (D  9)
//                               PB3  4|    |11  PA2  (D  8)
//  PWM  INT0  (D  2)  PB2  5|    |10  PA3  (D  7)
//    PWM        (D  3)  PA7  6|    |9   PA4  (D  6)
//    PWM        (D  4)  PA6  7|    |8   PA5  (D  5)        PWM
//                                       +----+

Dienstag, 10. Februar 2015

Serielle Kommunikation mit Matlab oder C#

(English version) Im vorigen Post (Herzschlag-Sensor ansteuern) habe ich erklärt, wie man mit einem Arduino über die serielle Schnittstelle den Wert des Herzschlag-Sensors sendet. In diesem Post will ich nun erklären, wie man diese Daten mit Matlab oder C# ausliest. Anfangen werde ich mit Matlab. Zuerst muss ein serieller Port geöffnet werden:

s = serial('COM3');
fopen(s);


Hier muss man einfach den entsprechenden COM-Port eintragen. Danach kann man auch schon alle verfügbaren Zeichen einlesen:

str = fscanf(s);

Das Problem daran ist allerdings, dass es auch sein kann, das eine Nachricht vom Arduino erst halb gesendet wurde und alle bisher gesendeten Zeichen eingelesen werden. Das kann man umgehen indem man z.B. alle gelesenen Zeichen in einen String schreibt und diesen dann ausliest. Am Ende sollte man nicht vergessen, den Port wieder zu schließen:

fclose(s);

Als nächstes möchte ich nun erklären wie man mit C# kommuniziert. Prinzipiell muss hier auch zuerst ein Port geöffnet werden:

port = new SerialPort("COM3", 9600);
port.Open();

Danach kann man direkt alle existierenden Zeichen lesen (analog zum Beispiel mit Matlab):

string indata = sp.ReadExisting();

In C# muss man den Port nicht unbedingt schließen, da dies beim Beenden des Programmes automatisch passiert.