package org.reprap.machines; /* * TODO: To do's: * * TODO: fixup warmup segments GCode (forgets to turn on extruder) * TODO: fixup all the RR: println commands * TODO: find a better place for the code. You cannot even detect a layer change without hacking now. * TODO: read Zach's GCode examples to check if I messed up. * TODO: make GCodeWriter a subclass of NullCartesian, so I don't have to fix code all over the place. */ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import javax.media.j3d.*; import javax.swing.JCheckBoxMenuItem; import org.reprap.Attributes; import org.reprap.CartesianPrinter; import org.reprap.Preferences; import org.reprap.Extruder; import org.reprap.ReprapException; import org.reprap.gui.Previewer; import org.reprap.devices.NullExtruder; /** * */ public class GCodeWriter implements CartesianPrinter { /** * */ private Previewer previewer = null; /** * */ double totalDistanceMoved = 0.0; /** * */ double totalDistanceExtruded = 0.0; //double extrusionSize, extrusionHeight, infillWidth; /** * */ double currentX, currentY, currentZ; /** * */ private double overRun; /** * */ private long delay; /** * */ private long startTime; /** * */ private Extruder extruders[]; /** * */ private int extruder; /** * */ private int extruderCount; // Added by Blerik, needs JavaDoc private java.io.PrintStream file; private int requestedSpeed; private int currentSpeed; private int temperature; /** * @param config */ public GCodeWriter(Preferences config) { startTime = System.currentTimeMillis(); extruderCount = config.loadInt("NumberOfExtruders"); extruders = new NullExtruder[extruderCount]; for(int i = 0; i < extruderCount; i++) { String prefix = "Extruder" + i + "_"; extruders[i] = new NullExtruder(config, i); } extruder = 1; currentX = 0; currentY = 0; currentZ = 0; // I open the file here because I have config here // and it seems like the host recreates the writer // for each print job String filename = config.loadString("Port(name)"); if (filename.equals("stdout")) { file = System.out; } else { try { OutputStream out = new FileOutputStream(filename); file = new PrintStream(out); } catch (FileNotFoundException e) { System.err.println("Problem with filename, printing to stdout"); file = System.out; } } requestedSpeed = 0; currentSpeed = 0; temperature = config.loadInt("Extruder0_ExtrusionTemp(C)"); } /* (non-Javadoc) * @see org.reprap.Printer#calibrate() */ public void calibrate() { } /** * @param startX * @param startY * @param startZ * @param endX * @param endY * @param endZ * @throws ReprapException * @throws IOException */ public void printSegment(double startX, double startY, double startZ, double endX, double endY, double endZ, boolean turnOff) throws ReprapException, IOException { moveTo(startX, startY, startZ, true, true); printTo(endX, endY, endZ, turnOff); } /* (non-Javadoc) * @see org.reprap.Printer#moveTo(double, double, double, boolean, boolean) */ public void moveTo(double x, double y, double z, boolean startUp, boolean endUp) throws ReprapException, IOException { if (isCancelled()) return; totalDistanceMoved += segmentLength(x - currentX, y - currentY); //TODO - next bit needs to take account of startUp and endUp if (z != currentZ) totalDistanceMoved += Math.abs(currentZ - z); double deltaX = round(x - currentX); double deltaY = round(y - currentY); double deltaZ = round(z - currentZ); file.print("G0"); file.print(" X" + deltaX + " Y" + deltaY); if (deltaZ != 0) file.print(" Z" + deltaZ); file.println(); currentX = x; currentY = y; currentZ = z; } /* (non-Javadoc) * @see org.reprap.Printer#printTo(double, double, double) */ public void printTo(double x, double y, double z, boolean turnOff) throws ReprapException, IOException { if (previewer != null) previewer.addSegment(currentX, currentY, currentZ, x, y, z); if (isCancelled()) return; double distance = segmentLength(x - currentX, y - currentY); if (z != currentZ) distance += Math.abs(currentZ - z); totalDistanceExtruded += distance; totalDistanceMoved += distance; double deltaX = round(x - currentX); double deltaY = round(y - currentY); double deltaZ = round(z - currentZ); file.print("G1"); file.print(" X" + deltaX + " Y" + deltaY); if (deltaZ != 0) file.print(" Z" + deltaZ); if (currentSpeed != requestedSpeed) { file.print(" F" + requestedSpeed); currentSpeed = requestedSpeed; } file.println(); currentX = x; currentY = y; currentZ = z; } private double round(double in) { return Math.round(in * 1000) / 1000.; } /* (non-Javadoc) * @see org.reprap.Printer#selectMaterial(int) */ public void selectExtruder(int materialIndex) { if (isCancelled()) return; if(materialIndex < 0 || materialIndex >= extruderCount) System.err.println("Selected material (" + materialIndex + ") is out of range."); else extruder = materialIndex; // if (previewer != null) // previewer.setExtruder(extruders[extruder]); } /* (non-Javadoc) * @see org.reprap.Printer#selectMaterial(int) */ public void selectExtruder(Attributes att) { for(int i = 0; i < extruderCount; i++) { if(att.getMaterial().equals(extruders[i].toString())) { selectExtruder(i); return; } } System.err.println("selectExtruder() - extruder not found for: " + att.getMaterial()); } /* (non-Javadoc) * @see org.reprap.Printer#terminate() */ public void terminate() throws IOException { } public void stopExtruding() { file.println("M103"); } public void stopValve() { System.err.println("GCodeWriter: stopValve() function called; this has the wrong M code!!!"); file.println("M103"); } /** * @return speed of the extruder */ public int getSpeed() { return 200; } /* (non-Javadoc) * @see org.reprap.Printer#getFastSpeed() */ public int getFastSpeed() { return getSpeed(); } /** * @return angle speedup length */ public double getAngleSpeedUpLength() { return 1; } /** * @return angle speed factor */ public double getAngleSpeedFactor() { return 0; } /* (non-Javadoc) * @see org.reprap.Printer#setSpeed(int) */ public void setSpeed(int speed) { // TODO: convert feedrate from RepRap host value to GCode value requestedSpeed = speed; } /* (non-Javadoc) * @see org.reprap.Printer#setFastSpeed(int) */ public void setFastSpeed(int speed) { file.println("RR: set fast speed: " + speed); } /* (non-Javadoc) * @see org.reprap.Printer#getSpeedZ() */ public int getSpeedZ() { return 200; } /* (non-Javadoc) * @see org.reprap.Printer#setSpeedZ(int) */ public void setSpeedZ(int speed) { // TODO: MiniMug prints this, but I don't know what to do with it //file.println("RR: set speed Z: " + speed); } /** * @return the extruder speeds */ public int getExtruderSpeed() { return 200; } /** * @param speed */ public void setExtruderSpeed(int speed) { file.println("RR: set extruder speed: " + speed); } /* (non-Javadoc) * @see org.reprap.Printer#setPreviewer(org.reprap.gui.Previewer) */ public void setPreviewer(Previewer previewer) { this.previewer = previewer; } /** * @param temperature */ public void setTemperature(int temperature) { file.println("RR: set temperature: " + temperature); } /** * outline speed and the infill speed */ public double getOutlineSpeed() { return 1.0; } /** * @return the infill speed */ public double getInfillSpeed() { return 1.0; } /* (non-Javadoc) * @see org.reprap.Printer#dispose() */ public void dispose() { // TODO: fix this to be more flexible // Fan off file.println("M9"); // Extruder off file.println("M103"); // heater off file.println("M104 P0"); if (!file.equals(System.out)) { file.close(); } } /* (non-Javadoc) * @see org.reprap.Printer#isCancelled() */ public boolean isCancelled() { // if (previewer != null) // return previewer.isCancelled(); return false; } /* (non-Javadoc) * @see org.reprap.Printer#initialise() */ public void initialise() { if (previewer != null) previewer.reset(); // TODO: Fix this to be more flexible // TODO: check if RapRap uses mm as scale file.println("G21"); // Set incremental positioning, so you can // decide where to print in the beginning // without messing up the rest of the Gcode file.println("G91"); file.println("M104 P" + temperature); } /* (non-Javadoc) * @see org.reprap.Printer#getX() */ public double getX() { return currentX; } /* (non-Javadoc) * @see org.reprap.Printer#getY() */ public double getY() { return currentY; } /* (non-Javadoc) * @see org.reprap.Printer#getZ() */ public double getZ() { return currentZ; } /* (non-Javadoc) * @see org.reprap.Printer#getTotalDistanceMoved() */ public double getTotalDistanceMoved() { return totalDistanceMoved; } /* (non-Javadoc) * @see org.reprap.Printer#getTotalDistanceExtruded() */ public double getTotalDistanceExtruded() { return totalDistanceExtruded; } /** * @param x * @param y * @return segment length in millimeters */ public double segmentLength(double x, double y) { return Math.sqrt(x*x + y*y); } /* (non-Javadoc) * @see org.reprap.Printer#getExtrusionSize() */ // public double getExtrusionSize() { // return extrusionSize; // } // // public double getExtrusionHeight() { // return extrusionHeight; // } // // public double getInfillWidth() { // return infillWidth; // } /* (non-Javadoc) * @see org.reprap.Printer#setCooling(boolean) */ public void setCooling(boolean enable) { file.println("RR: set cooling: " + enable); } /** * Get the length before the end of a track to turn the extruder off * to allow for the delay in the stream stopping. * @return overrun in millimeters */ public double getOverRun() { return overRun; }; /** * Get the number of milliseconds to wait between turning an * extruder on and starting to move it. * @return delay in milliseconds */ public long getDelay() { return delay; }; /* (non-Javadoc) * @see org.reprap.Printer#getTotalElapsedTime() */ public double getTotalElapsedTime() { long now = System.currentTimeMillis(); return (now - startTime) / 1000.0; } /* (non-Javadoc) * @see org.reprap.Printer#printStartDelay(long) */ public void printStartDelay(boolean firstInLayer) { // This would extrude for the given interval to ensure polymer flow. // TODO - How do we communicate milliseconds here? (AB) file.println("M101"); } /* (non-Javadoc) * @see org.reprap.Printer#setLowerShell(javax.media.j3d.Shape3D) */ public void setLowerShell(BranchGroup ls) { if(previewer != null) previewer.setLowerShell(ls); } /* (non-Javadoc) * @see org.reprap.Printer#setZManual() */ public void setZManual() { setZManual(0.0); file.println("RR: set Z manual"); } /* (non-Javadoc) * @see org.reprap.Printer#setZManual(double) */ public void setZManual(double zeroPoint) { file.println("RR: set Z manual: " + zeroPoint); } /* (non-Javadoc) * @see org.reprap.Printer#homeToZeroX() */ public void homeToZeroX() throws ReprapException, IOException { file.println("G0 X-999"); } /* (non-Javadoc) * @see org.reprap.Printer#homeToZeroY() */ public void homeToZeroY() throws ReprapException, IOException { file.println("G0 Y-999"); } /* (non-Javadoc) * @see org.reprap.Printer#getExtruder() */ public Extruder getExtruder() { return extruders[extruder]; } /* (non-Javadoc) * @see org.reprap.Printer#getExtruder(String) */ public Extruder getExtruder(String name) { for(int i = 0; i < extruderCount; i++) if(name.equals(extruders[i].toString())) return extruders[i]; return null; } /* (non-Javadoc) * @see org.reprap.Printer#getExtruder(String) */ public Extruder[] getExtruders() { return extruders; } // /** // * Moves nozzle back and forth over wiper // */ // public void wipeNozzle() throws ReprapException, IOException { // // if (getExtruder().getNozzleWipeEnabled() == false) return; // // else { // // int freq = getExtruder().getNozzleWipeFreq(); // double datumX = getExtruder().getNozzleWipeDatumX(); // double datumY = getExtruder().getNozzleWipeDatumY(); // double strokeX = getExtruder().getNozzleWipeStrokeX(); // double strokeY = getExtruder().getNozzleWipeStrokeY(); // // //setSpeed(fastSpeedXY); // double clearTime = getExtruder().getNozzleClearTime(); // if(clearTime > 0) // { // moveTo(datumX, datumY + strokeY, currentZ, false, false); // extruders[extruder].setExtrusion(extruders[extruder].getExtruderSpeed()); // try // { // Thread.sleep((long)(1000*clearTime)); // } catch (Exception ex) // { // } // extruders[extruder].setExtrusion(0); // } // // // Moves nozzle over wiper // for (int w=0; w < freq; w++) // { // moveTo(datumX, datumY + strokeY, currentZ, false, false); // moveTo(datumX, datumY, currentZ, false, false); // moveTo(datumX + strokeX, datumY, currentZ, false, false); // moveTo(datumX + strokeX, datumY + strokeY, currentZ, false, false); // } // // // } // } /** * Just finished a layer * @param layerNumber */ public void finishedLayer(int layerNumber) throws Exception { double datumX = getExtruder().getNozzleWipeDatumX(); double datumY = getExtruder().getNozzleWipeDatumY(); double strokeX = getExtruder().getNozzleWipeStrokeX(); double strokeY = getExtruder().getNozzleWipeStrokeY(); double coolTime = getExtruder().getCoolingPeriod(); if(coolTime > 0 && (layerNumber != 0)) getExtruder().setCooler(true); setSpeed(getFastSpeed()); // Go home, X first homeToZeroX(); homeToZeroY(); // If wiping, nudge the clearer blade if (getExtruder().getNozzleWipeEnabled()) { moveTo(datumX, datumY, currentZ, false, false); setSpeed(getExtruder().getXYSpeed()); moveTo(datumX + strokeX, datumY, currentZ, false, false); moveTo(datumX, datumY, currentZ, false, false); } } /** * Deals with all the actions that need to be done between one layer * and the next. */ public void betweenLayers(int layerNumber) throws Exception { double datumX = getExtruder().getNozzleWipeDatumX(); double datumY = getExtruder().getNozzleWipeDatumY(); double strokeX = getExtruder().getNozzleWipeStrokeX(); double strokeY = getExtruder().getNozzleWipeStrokeY(); double coolTime = getExtruder().getCoolingPeriod(); double clearTime = getExtruder().getNozzleClearTime(); double waitTime = getExtruder().getNozzleWaitTime(); // Do half the extrusion between layers now if (getExtruder().getNozzleWipeEnabled()) { if(clearTime > 0) { getExtruder().setExtrusion(extruders[extruder].getExtruderSpeed()); Thread.sleep((long)(500*clearTime)); getExtruder().setExtrusion(0); } } // Now is a good time to garbage collect System.gc(); // Cooling period if(coolTime > 0 && (layerNumber != 0)) { //Debug.d("Start of cooling period"); // Wait for cooling time Thread.sleep((long)(1000*coolTime)); getExtruder().setCooler(false); Thread.sleep((long)(200 * coolTime)); //Debug.d("End of cooling period"); } } /** * Just about to start the next layer * @param layerNumber */ public void startingLayer(int layerNumber) throws Exception { double datumX = getExtruder().getNozzleWipeDatumX(); double datumY = getExtruder().getNozzleWipeDatumY(); double strokeX = getExtruder().getNozzleWipeStrokeX(); double strokeY = getExtruder().getNozzleWipeStrokeY(); double coolTime = getExtruder().getCoolingPeriod(); double clearTime = getExtruder().getNozzleClearTime(); double waitTime = getExtruder().getNozzleWaitTime(); // Do the other half of the clearing extrude then // Wipe the nozzle on the doctor blade if (getExtruder().getNozzleWipeEnabled()) { if(clearTime > 0) { getExtruder().setExtrusion(extruders[extruder].getExtruderSpeed()); Thread.sleep((long)(500*clearTime)); getExtruder().setExtrusion(0); Thread.sleep((long)(1000*waitTime)); } moveTo(datumX, datumY + strokeY, currentZ, false, false); } setSpeed(getFastSpeed()); } public void setSegmentPause(JCheckBoxMenuItem segmentPause) {} /** * Set the source checkbox used to determine if there should * be a pause between layers. * * @param layerPause The source checkbox used to determine * if there should be a pause. This is a checkbox rather than * a boolean so it can be changed on the fly. */ public void setLayerPause(JCheckBoxMenuItem layerPause) {} public void setCancelled(boolean c) {} }