package org.reprap.machines; import java.io.IOException; import java.lang.Math; import org.reprap.Preferences; import org.reprap.ReprapException; import org.reprap.comms.snap.SNAPAddress; import org.reprap.devices.NullExtruder; import org.reprap.devices.SNAPExtruder; import org.reprap.devices.SNAPStepperMotor; import org.reprap.devices.pseudo.LinePrinter; import org.reprap.gui.CalibrateZAxis; import org.reprap.Extruder; import org.reprap.utilities.Debug; /** * * A Reprap printer is a 3-D cartesian printer with one or more * extruders * */ public class SNAPReprap extends GenericRepRap { /** * */ //private Communicator communicator = org.reprap.Main.getCommunicator(); /** * our line printer object. */ private LinePrinter layerPrinter; /** * @param prefs * @throws Exception */ public SNAPReprap() throws Exception { super(); layerPrinter = new LinePrinter(motorX, motorY, extruders[extruder]); try { currentX = convertToPositionZ(motorX.getPosition()); currentY = convertToPositionZ(motorY.getPosition()); } catch (Exception ex) { throw new Exception("Warning: X and/or Y controller not responding, cannot continue"); } try { currentZ = convertToPositionZ(motorZ.getPosition()); } catch (Exception ex) { System.err.println("Z axis not responding and will be ignored"); excludeZ = true; } } public void loadMotors() { try { motorX = new SNAPStepperMotor(org.reprap.Main.getCommunicator(), new SNAPAddress(Preferences.loadGlobalInt("XAxisAddress")), 1); motorY = new SNAPStepperMotor(org.reprap.Main.getCommunicator(), new SNAPAddress(Preferences.loadGlobalInt("YAxisAddress")), 2); motorZ = new SNAPStepperMotor(org.reprap.Main.getCommunicator(), new SNAPAddress(Preferences.loadGlobalInt("ZAxisAddress")), 3); motorX.setPrinter(this); motorY.setPrinter(this); motorZ.setPrinter(this); } catch (Exception ex){ ex.printStackTrace(); } } public void loadExtruders() { extruders = new SNAPExtruder[extruderCount]; super.loadExtruders(); } public Extruder extruderFactory(int count) { try { String prefix = "Extruder" + count + "_"; SNAPAddress addy = new SNAPAddress(Preferences.loadGlobalInt(prefix + "Address")); return new SNAPExtruder(org.reprap.Main.getCommunicator(), addy, count, this); } catch (Exception e) { return new NullExtruder(count, this); } } public void refreshPreferences() { super.refreshPreferences(); motorX.refreshPreferences(); motorY.refreshPreferences(); motorZ.refreshPreferences(); } public void startRun() { } /** * Wait while the motors move about * @throws IOException */ public void waitTillNotBusy() throws IOException { motorX.waitTillNotBusy(); } /* (non-Javadoc) * @see org.reprap.Printer#calibrate() */ public void calibrate() { } /** * Go to the purge point */ public void moveToPurge() { singleMove(dumpX, dumpY, currentZ, getExtruder().getFastXYFeedrate()); } /* (non-Javadoc) * @see org.reprap.Printer#moveTo(double, double, double, boolean, boolean) */ public void moveTo(double x, double y, double z, double feedrate, boolean startUp, boolean endUp) throws ReprapException, IOException { if (isCancelled()) return; currentFeedrate = feedrate; int stepperX = convertToStepX(x); int stepperY = convertToStepY(y); int stepperZ = convertToStepZ(z); int currentStepperX = convertToStepX(currentX); int currentStepperY = convertToStepY(currentY); int currentStepperZ = convertToStepZ(currentZ); if (currentStepperX == stepperX && currentStepperY ==stepperY && currentStepperZ == stepperZ && !startUp) return; // We don't need to lift a whole layer up. Half a layer should do // and will dribble less. Remember the Z axis is kinda slow... double liftedZ = z + (extruders[extruder].getMinLiftedZ()); int stepperLiftedZ = convertToStepZ(liftedZ); int targetZ; // Raise head slightly before move? if(startUp) { targetZ = stepperLiftedZ; currentZ = liftedZ; } else { targetZ = stepperZ; currentZ = z; } if (targetZ != currentStepperZ) { totalDistanceMoved += Math.abs(currentZ - liftedZ); int zSpeed = convertFeedrateToSpeedZ(getFastFeedrateZ()); if (!excludeZ) motorZ.seekBlocking(zSpeed, targetZ); if (idleZ) motorZ.setIdle(); currentStepperZ = targetZ; } int currentSpeedXY = convertFeedrateToSpeedXY(getFeedrate()); layerPrinter.moveTo(stepperX, stepperY, currentSpeedXY, false, false); totalDistanceMoved += segmentLength(x - currentX, y - currentY); currentX = x; currentY = y; if(endUp) { targetZ = stepperLiftedZ; currentZ = liftedZ; } else { targetZ = stepperZ; currentZ = z; } // Move head back down to surface? if(targetZ != currentStepperZ) { totalDistanceMoved += Math.abs(currentZ - z); int zSpeed = convertFeedrateToSpeedZ(maxFeedrateZ); if (!excludeZ) motorZ.seekBlocking(zSpeed, targetZ); if (idleZ) motorZ.setIdle(); currentStepperZ = targetZ; } } /* (non-Javadoc) * @see org.reprap.Printer#printTo(double, double, double, boolean) */ public void printTo(double x, double y, double z, double feedrate, boolean stopExtruder, boolean closeValve) throws ReprapException, IOException { if (isCancelled()) return; EnsureNotEmpty(); if (isCancelled()) return; EnsureHot(); if (isCancelled()) return; currentFeedrate = feedrate; maybeReZero(); int stepperX = convertToStepX(x); int stepperY = convertToStepY(y); int stepperZ = convertToStepZ(z); if ((stepperX != layerPrinter.getCurrentX() || stepperY != layerPrinter.getCurrentY()) && z != currentZ) throw new ReprapException("Reprap cannot print a line across 3 axes simultaneously"); // if (previewer != null) // previewer.addSegment(convertToPositionX(layerPrinter.getCurrentX()), // convertToPositionY(layerPrinter.getCurrentY()), currentZ, // x, y, z); if (isCancelled()) return; if (z != currentZ) { Debug.d("Printing a vertical extrusion. Should we do that?"); // Print a simple vertical extrusion double distance = Math.abs(currentZ - z); totalDistanceExtruded += distance; totalDistanceMoved += distance; extruders[extruder].setMotor(true); int zSpeed = convertFeedrateToSpeedZ(maxFeedrateZ); if (!excludeZ) motorZ.seekBlocking(zSpeed, stepperZ); extruders[extruder].setMotor(false); currentZ = z; return; } // Otherwise printing only in X/Y plane double deltaX = x - currentX; double deltaY = y - currentY; double distance = segmentLength(deltaX, deltaY); totalDistanceExtruded += distance; totalDistanceMoved += distance; if (segmentPauseCheckbox != null && distance > 0) if(segmentPauseCheckbox.isSelected()) segmentPause(); int currentSpeedXY = convertFeedrateToSpeedXY(getExtruder().getFastXYFeedrate()); //System.out.println("close: " + closeValve + ", stop ex:" + stopExtruder); layerPrinter.printTo(stepperX, stepperY, currentSpeedXY, getExtruder().getExtruderSpeed(), stopExtruder, closeValve); currentX = x; currentY = y; } public void stopMotor() throws IOException { layerPrinter.stopMotor(); } public void stopValve() throws IOException { layerPrinter.stopValve(); } /* Move to zero stop on X axis. * (non-Javadoc) * @see org.reprap.Printer#homeToZeroX() */ public void homeToZeroX() throws ReprapException, IOException { int fastSpeedXY = convertFeedrateToSpeedXY(getExtruder().getFastXYFeedrate()); motorX.homeReset(fastSpeedXY); layerPrinter.zeroX(); super.homeToZeroX(); } /* Move to zero stop on Y axis. * (non-Javadoc) * @see org.reprap.Printer#homeToZeroY() */ public void homeToZeroY() throws ReprapException, IOException { int fastSpeedXY = convertFeedrateToSpeedXY(getExtruder().getFastXYFeedrate()); motorY.homeReset(fastSpeedXY); layerPrinter.zeroY(); super.homeToZeroX(); } /* Move to zero stop on Z axis. * (non-Javadoc) * @see org.reprap.Printer#homeToZeroZ() */ public void homeToZeroZ() throws ReprapException, IOException { int fastSpeedZ = convertFeedrateToSpeedZ(getFastFeedrateZ()); motorZ.homeReset(fastSpeedZ); super.homeToZeroZ(); } public void home() { try { int fastSpeedXY = convertFeedrateToSpeedXY(getExtruder().getFastXYFeedrate()); int fastSpeedZ = convertFeedrateToSpeedZ(getFastFeedrateZ()); motorX.homeReset(fastSpeedXY); motorY.homeReset(fastSpeedXY); if (!excludeZ) motorZ.homeReset(fastSpeedZ); } catch (Exception e) { System.err.println("Error homing all axes."); } } /* (non-Javadoc) * @see org.reprap.Printer#terminate() */ public void terminate() throws Exception { motorX.setIdle(); motorY.setIdle(); if (!excludeZ) motorZ.setIdle(); super.terminate(); } /* (non-Javadoc) * @see org.reprap.Printer#dispose() */ public void dispose() { motorX.dispose(); motorY.dispose(); motorZ.dispose(); super.dispose(); // communicator.close(); // communicator.dispose(); } /** * */ private void EnsureNotEmpty() { if (!extruders[extruder].isEmpty()) return; while (extruders[extruder].isEmpty() && !isCancelled()) { //if (previewer != null) //previewer. setMessage("Extruder is out of feedstock. Waiting for refill."); machineWait(1000); } //if (previewer != null) previewer. setMessage(null); } /** * @throws ReprapException * @throws IOException */ private void EnsureHot() throws ReprapException, IOException { if(extruders[extruder].getTemperatureTarget() <= Preferences.absoluteZero() + 1) return; double threshold = extruders[extruder].getTemperatureTarget() * 0.90; // Changed from 0.95 by Vik. if (extruders[extruder].getTemperature() >= threshold) return; double x = currentX; double y = currentY; int tempReminder=0; temperatureReminder(); Debug.d("Moving to heating zone"); double oldFeedrate = getFeedrate(); // Ensure the extruder is off extruders[extruder].setMotor(false); moveToHeatingZone(); while(extruders[extruder].getTemperature() < threshold && !isCancelled()) { //if (previewer != null) previewer. setMessage("Waiting for extruder to reach working temperature (" + Math.round(extruders[extruder].getTemperature()) + ")"); machineWait(1000); // If it stays cold for 10s, remind it of its purpose. if (tempReminder++ >10) { tempReminder=0; temperatureReminder(); } } Debug.d("Returning to previous position"); moveTo(x, y, currentZ, currentFeedrate, true, false); currentFeedrate = oldFeedrate; //if (previewer != null) previewer. setMessage(null); } /** A bodge to fix the extruder's current tendency to forget what temperature * it is supposed to be reaching. * * Vik */ private void temperatureReminder() { if(extruders[extruder].getTemperatureTarget() < Preferences.absoluteZero()) return; Debug.d("Reminding it of the temperature"); try { extruders[extruder].setTemperature(extruders[extruder].getTemperatureTarget(), false); //setTemperature(Preferences.loadGlobalInt("ExtrusionTemp")); } catch (Exception e) { System.err.println("Error resetting temperature."); } } /** * Moves the head to the predefined heating area * @throws IOException * @throws ReprapException */ private void moveToHeatingZone() throws ReprapException, IOException { //setFeedrate(getFastFeedrateXY()); moveTo(1, 1, currentZ, getExtruder().getFastXYFeedrate(), true, false); } /* (non-Javadoc) * @see org.reprap.Printer#setZManual(double) */ public void setZManual(double zeroPoint) throws IOException { int zSpeed = convertFeedrateToSpeedZ(getFastFeedrateZ()); CalibrateZAxis msg = new CalibrateZAxis(null, motorZ, scaleZ, zSpeed); msg.setVisible(true); try { synchronized(msg) { msg.wait(); } } catch (Exception ex) { } msg.dispose(); motorZ.setPosition(convertToStepZ(zeroPoint)); } /** * All machine dwells and delays are routed via this function, rather than * calling Thread.sleep - this allows them to generate the right G codes (G4) etc. * * The RS232/USB etc comms system doesn't use this - it sets its own delays. * @param milliseconds */ public void machineWait(double milliseconds) { if(milliseconds <= 0) return; try { Thread.sleep((long)milliseconds); } catch (InterruptedException e) { } } public void waitWhileBufferNotEmpty() { } public void slowBuffer() { } public void speedBuffer() { } /** * Load a GCode file to be made. * @return the name of the file */ public String loadGCodeFileForMaking() { System.err.println("SNAP RepRap: attempt to load GCode file."); //super.loadGCodeFileForMaking(); return null; } /** * Set an output file * @return */ public String setGCodeFileForOutput(String fileRoot) { System.err.println("SNAP RepRap: cannot generate GCode file."); return null; } /** * If a file replay is being done, do it and return true * otherwise return false. * @return */ public boolean filePlay() { return false; } }