Skip to content
Snippets Groups Projects
Commit 27a10a15 authored by Thomas Oster's avatar Thomas Oster
Browse files

First (draft) implementation of a driver for the Lasersaur-Project

parent 281050e4
No related branches found
No related tags found
No related merge requests found
......@@ -21,6 +21,7 @@ package com.t_oster.liblasercut;
import com.t_oster.liblasercut.drivers.EpilogHelix;
import com.t_oster.liblasercut.drivers.EpilogZing;
import com.t_oster.liblasercut.drivers.LaosCutter;
import com.t_oster.liblasercut.drivers.Lasersaur;
/**
* This class contains Version information
......@@ -29,7 +30,7 @@ import com.t_oster.liblasercut.drivers.LaosCutter;
*/
public class LibInfo
{
private static String VERSION = "1.5.1";
private static String VERSION = "1.6";
public static String getVersion()
{
......@@ -41,7 +42,8 @@ public class LibInfo
return new Class[]{
EpilogZing.class,
EpilogHelix.class,
LaosCutter.class
LaosCutter.class,
Lasersaur.class
};
}
}
/**
* This file is part of VisiCut. Copyright (C) 2011 Thomas Oster
* <thomas.oster@rwth-aachen.de> RWTH Aachen University - 52062 Aachen, Germany
*
* VisiCut is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* VisiCut is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with VisiCut. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.t_oster.liblasercut.drivers;
import com.t_oster.liblasercut.*;
import com.t_oster.liblasercut.platform.Point;
import com.t_oster.liblasercut.platform.Util;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
/**
* This class implements a driver for the LAOS Lasercutter board. Currently it
* supports the simple code and the G-Code, which may be used in the future.
*
* @author Thomas Oster <thomas.oster@rwth-aachen.de>
*/
public class Lasersaur extends LaserCutter {
private static final String SETTING_COMPORT = "COM-Port/Device";
private static final String SETTING_BEDWIDTH = "Laserbed width";
private static final String SETTING_BEDHEIGHT = "Laserbed height";
private static final String SETTING_FLIPX = "X axis goes right to left (yes/no)";
private static final String SETTING_RASTER_WHITESPACE = "Additional space per Raster line (mm)";
private static final String SETTING_SEEK_RATE = "Max. Seek Rate (mm/min)";
private static final String SETTING_LASER_RATE = "Max. Laser Rate (mm/min)";
@Override
public String getModelName() {
return "Lasersaur";
}
private double addSpacePerRasterLine = 0.5;
/**
* Get the value of addSpacePerRasterLine
*
* @return the value of addSpacePerRasterLine
*/
public double getAddSpacePerRasterLine() {
return addSpacePerRasterLine;
}
/**
* Set the value of addSpacePerRasterLine
*
* @param addSpacePerRasterLine new value of addSpacePerRasterLine
*/
public void setAddSpacePerRasterLine(double addSpacePerRasterLine) {
this.addSpacePerRasterLine = addSpacePerRasterLine;
}
private double seekRate = 2000;
/**
* Get the value of seekRate
*
* @return the value of seekRate
*/
public double getSeekRate() {
return seekRate;
}
/**
* Set the value of seekRate
*
* @param seekRate new value of seekRate
*/
public void setSeekRate(double seekRate) {
this.seekRate = seekRate;
}
private double laserRate = 2000;
/**
* Get the value of laserRate
*
* @return the value of laserRate
*/
public double getLaserRate() {
return laserRate;
}
/**
* Set the value of laserRate
*
* @param laserRate new value of laserRate
*/
public void setLaserRate(double laserRate) {
this.laserRate = laserRate;
}
protected boolean flipXaxis = false;
/**
* Get the value of flipXaxis
*
* @return the value of flipXaxis
*/
public boolean isFlipXaxis() {
return flipXaxis;
}
/**
* Set the value of flipXaxis
*
* @param flipXaxis new value of flipXaxis
*/
public void setFlipXaxis(boolean flipXaxis) {
this.flipXaxis = flipXaxis;
}
protected String comPort = "/dev/ttyUSB0";
/**
* Get the value of port
*
* @return the value of port
*/
public String getComPort() {
return comPort;
}
/**
* Set the value of port
*
* @param comPort new value of port
*/
public void setComPort(String comPort) {
this.comPort = comPort;
}
private byte[] generateVectorGCode(VectorPart vp, int resolution) throws UnsupportedEncodingException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
PrintStream out = new PrintStream(result, true, "US-ASCII");
for (VectorCommand cmd : vp.getCommandList()) {
switch (cmd.getType()) {
case MOVETO:
int x = cmd.getX();
int y = cmd.getY();
move(out, x, y, resolution);
break;
case LINETO:
x = cmd.getX();
y = cmd.getY();
line(out, x, y, resolution);
break;
case SETPOWER:
setPower(out, cmd.getPower());
break;
case SETFOCUS:
float focus = cmd.getFocus();
break;
case SETSPEED:
int speed = cmd.getSpeed();
setSpeed(out, speed);
break;
case SETFREQUENCY:
int frequency = cmd.getFrequency();
break;
}
}
return result.toByteArray();
}
private int currentPower = -1;
private int currentSpeed = -1;
private void setSpeed(PrintStream out, int speedInPercent) {
if (speedInPercent != currentSpeed) {
out.printf(Locale.US, "G1 F%i\n", (int) ((double) speedInPercent * this.getLaserRate() / 100));
currentSpeed = speedInPercent;
}
}
private void setPower(PrintStream out, int powerInPercent) {
if (powerInPercent != currentPower) {
out.printf(Locale.US, "S%i\n", (int) (255d * powerInPercent / 100));
currentPower = powerInPercent;
}
}
private void move(PrintStream out, int x, int y, double resolution) {
out.printf(Locale.US, "G0 X%f Y%f\n", Util.px2mm(isFlipXaxis() ? Util.mm2px(bedWidth, resolution) - x : x, resolution), Util.px2mm(y, resolution));
}
private void line(PrintStream out, int x, int y, double resolution) {
out.printf(Locale.US, "G1 X%f Y%f\n", Util.px2mm(isFlipXaxis() ? Util.mm2px(bedWidth, resolution) - x : x, resolution), Util.px2mm(y, resolution));
}
private byte[] generatePseudoRaster3dGCode(Raster3dPart rp, int resolution) throws UnsupportedEncodingException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
PrintStream out = new PrintStream(result, true, "US-ASCII");
boolean dirRight = true;
for (int raster = 0; raster < rp.getRasterCount(); raster++) {
Point rasterStart = rp.getRasterStart(raster);
LaserProperty prop = rp.getLaserProperty(raster);
setSpeed(out, prop.getSpeed());
for (int line = 0; line < rp.getRasterHeight(raster); line++) {
Point lineStart = rasterStart.clone();
lineStart.y += line;
List<Byte> bytes = rp.getRasterLine(raster, line);
//remove heading zeroes
while (bytes.size() > 0 && bytes.get(0) == 0) {
bytes.remove(0);
lineStart.x += 1;
}
//remove trailing zeroes
while (bytes.size() > 0 && bytes.get(bytes.size() - 1) == 0) {
bytes.remove(bytes.size() - 1);
}
if (bytes.size() > 0) {
if (dirRight) {
//move to the first nonempyt point of the line
move(out, lineStart.x, lineStart.y, resolution);
byte old = bytes.get(0);
for (int pix = 0; pix < bytes.size(); pix++) {
if (bytes.get(pix) != old) {
if (old == 0) {
move(out, lineStart.x + pix, lineStart.y, resolution);
} else {
setPower(out, prop.getPower() * (0xFF & old) / 255);
line(out, lineStart.x + pix - 1, lineStart.y, resolution);
move(out, lineStart.x + pix, lineStart.y, resolution);
}
old = bytes.get(pix);
}
}
//last point is also not "white"
setPower(out, prop.getPower() * (0xFF & bytes.get(bytes.size() - 1)) / 255);
line(out, lineStart.x + bytes.size() - 1, lineStart.y, resolution);
} else {
//move to the last nonempty point of the line
move(out, lineStart.x + bytes.size() - 1, lineStart.y, resolution);
byte old = bytes.get(bytes.size() - 1);
for (int pix = bytes.size() - 1; pix >= 0; pix--) {
if (bytes.get(pix) != old || pix == 0) {
if (old == 0) {
move(out, lineStart.x + pix, lineStart.y, resolution);
} else {
setPower(out, prop.getPower() * (0xFF & old) / 255);
line(out, lineStart.x + pix + 1, lineStart.y, resolution);
move(out, lineStart.x + pix, lineStart.y, resolution);
}
old = bytes.get(pix);
}
}
//last point is also not "white"
setPower(out, prop.getPower() * (0xFF & bytes.get(0)) / 255);
line(out, lineStart.x, lineStart.y, resolution);
}
}
dirRight = !dirRight;
}
}
return result.toByteArray();
}
private byte[] generatePseudoRasterGCode(RasterPart rp, int resolution) throws UnsupportedEncodingException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
PrintStream out = new PrintStream(result, true, "US-ASCII");
boolean dirRight = true;
for (int raster = 0; raster < rp.getRasterCount(); raster++) {
Point rasterStart = rp.getRasterStart(raster);
LaserProperty prop = rp.getLaserProperty(raster);
setSpeed(out, prop.getSpeed());
setPower(out, prop.getPower());
for (int line = 0; line < rp.getRasterHeight(raster); line++) {
Point lineStart = rasterStart.clone();
lineStart.y += line;
//Convert BlackWhite line into line of 0 and 255 bytes
BlackWhiteRaster bwr = rp.getImages()[raster];
List<Byte> bytes = new LinkedList<Byte>();
boolean lookForStart = true;
for (int x = 0; x < bwr.getWidth(); x++) {
if (lookForStart) {
if (bwr.isBlack(x, line)) {
lookForStart = false;
bytes.add((byte) 255);
} else {
lineStart.x += 1;
}
} else {
bytes.add(bwr.isBlack(x, line) ? (byte) 255 : (byte) 0);
}
}
//remove trailing zeroes
while (bytes.size() > 0 && bytes.get(bytes.size() - 1) == 0) {
bytes.remove(bytes.size() - 1);
}
if (bytes.size() > 0) {
if (dirRight) {
//add some space to the left
move(out, Math.max(0, (int) (lineStart.x - Util.mm2px(this.addSpacePerRasterLine, resolution))), lineStart.y, resolution);
//move to the first nonempyt point of the line
move(out, lineStart.x, lineStart.y, resolution);
byte old = bytes.get(0);
for (int pix = 0; pix < bytes.size(); pix++) {
if (bytes.get(pix) != old) {
if (old == 0) {
move(out, lineStart.x + pix, lineStart.y, resolution);
} else {
setPower(out, prop.getPower() * (0xFF & old) / 255);
line(out, lineStart.x + pix - 1, lineStart.y, resolution);
move(out, lineStart.x + pix, lineStart.y, resolution);
}
old = bytes.get(pix);
}
}
//last point is also not "white"
setPower(out, prop.getPower() * (0xFF & bytes.get(bytes.size() - 1)) / 255);
line(out, lineStart.x + bytes.size() - 1, lineStart.y, resolution);
//add some space to the right
move(out, Math.min((int) Util.mm2px(bedWidth, resolution), (int) (lineStart.x + bytes.size() - 1 + Util.mm2px(this.addSpacePerRasterLine, resolution))), lineStart.y, resolution);
} else {
//add some space to the right
move(out, Math.min((int) Util.mm2px(bedWidth, resolution), (int) (lineStart.x + bytes.size() - 1 + Util.mm2px(this.addSpacePerRasterLine, resolution))), lineStart.y, resolution);
//move to the last nonempty point of the line
move(out, lineStart.x + bytes.size() - 1, lineStart.y, resolution);
byte old = bytes.get(bytes.size() - 1);
for (int pix = bytes.size() - 1; pix >= 0; pix--) {
if (bytes.get(pix) != old || pix == 0) {
if (old == 0) {
move(out, lineStart.x + pix, lineStart.y, resolution);
} else {
setPower(out, prop.getPower() * (0xFF & old) / 255);
line(out, lineStart.x + pix + 1, lineStart.y, resolution);
move(out, lineStart.x + pix, lineStart.y, resolution);
}
old = bytes.get(pix);
}
}
//last point is also not "white"
setPower(out, prop.getPower() * (0xFF & bytes.get(0)) / 255);
line(out, lineStart.x, lineStart.y, resolution);
//add some space to the left
move(out, Math.max(0, (int) (lineStart.x - Util.mm2px(this.addSpacePerRasterLine, resolution))), lineStart.y, resolution);
}
}
dirRight = !dirRight;
}
}
return result.toByteArray();
}
private byte[] generateInitializationCode() throws UnsupportedEncodingException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
PrintStream out = new PrintStream(result, true, "US-ASCII");
out.print("G54\n");//use table offset
out.print("G21\n");//units to mm
out.print("G90\n");//following coordinates are absolute
out.print("G0 X0 Y0\n");//move to 0 0
return result.toByteArray();
}
private byte[] generateShutdownCode() throws UnsupportedEncodingException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
PrintStream out = new PrintStream(result, true, "US-ASCII");
//back to origin and shutdown
out.print("G0 X0 Y0\n");//move to 0 0
return result.toByteArray();
}
@Override
public void sendJob(LaserJob job, ProgressListener pl) throws IllegalJobException, Exception {
pl.progressChanged(this, 0);
this.currentPower = -1;
this.currentSpeed = -1;
BufferedOutputStream out;
ByteArrayOutputStream buffer = null;
pl.taskChanged(this, "checking job");
checkJob(job);
buffer = new ByteArrayOutputStream();
out = new BufferedOutputStream(buffer);
pl.taskChanged(this, "buffering");
out.write(this.generateInitializationCode());
pl.progressChanged(this, 20);
if (job.contains3dRaster()) {
out.write(this.generatePseudoRaster3dGCode(job.getRaster3dPart(), job.getResolution()));
}
pl.progressChanged(this, 40);
if (job.containsRaster()) {
out.write(this.generatePseudoRasterGCode(job.getRasterPart(), job.getResolution()));
}
pl.progressChanged(this, 60);
if (job.containsVector()) {
out.write(this.generateVectorGCode(job.getVectorPart(), job.getResolution()));
}
pl.progressChanged(this, 80);
out.write(this.generateShutdownCode());
out.close();
System.out.write(buffer.toByteArray());
pl.taskChanged(this, "sent.");
pl.progressChanged(this, 100);
}
private List<Integer> resolutions;
@Override
public List<Integer> getResolutions() {
if (resolutions == null) {
resolutions = Arrays.asList(new Integer[]{
500
});
}
return resolutions;
}
protected double bedWidth = 250;
/**
* Get the value of bedWidth
*
* @return the value of bedWidth
*/
@Override
public double getBedWidth() {
return bedWidth;
}
/**
* Set the value of bedWidth
*
* @param bedWidth new value of bedWidth
*/
public void setBedWidth(double bedWidth) {
this.bedWidth = bedWidth;
}
protected double bedHeight = 280;
/**
* Get the value of bedHeight
*
* @return the value of bedHeight
*/
@Override
public double getBedHeight() {
return bedHeight;
}
/**
* Set the value of bedHeight
*
* @param bedHeight new value of bedHeight
*/
public void setBedHeight(double bedHeight) {
this.bedHeight = bedHeight;
}
private List<String> settingAttributes;
@Override
public List<String> getSettingAttributes() {
if (settingAttributes == null) {
settingAttributes = new LinkedList<String>();
settingAttributes.add(SETTING_BEDWIDTH);
settingAttributes.add(SETTING_BEDHEIGHT);
settingAttributes.add(SETTING_FLIPX);
settingAttributes.add(SETTING_COMPORT);
settingAttributes.add(SETTING_LASER_RATE);
settingAttributes.add(SETTING_SEEK_RATE);
settingAttributes.add(SETTING_RASTER_WHITESPACE);
}
return settingAttributes;
}
@Override
public String getSettingValue(String attribute) {
if (SETTING_RASTER_WHITESPACE.equals(attribute)) {
return "" + this.getAddSpacePerRasterLine();
} else if (SETTING_COMPORT.equals(attribute)) {
return this.getComPort();
} else if (SETTING_FLIPX.equals(attribute)) {
return this.isFlipXaxis() ? "yes" : "no";
} else if (SETTING_LASER_RATE.equals(attribute)) {
return "" + this.getLaserRate();
} else if (SETTING_SEEK_RATE.equals(attribute)) {
return "" + this.getSeekRate();
} else if (SETTING_BEDWIDTH.equals(attribute)) {
return "" + this.getBedWidth();
} else if (SETTING_BEDHEIGHT.equals(attribute)) {
return "" + this.getBedHeight();
}
return null;
}
@Override
public void setSettingValue(String attribute, String value) {
if (SETTING_RASTER_WHITESPACE.equals(attribute)) {
this.setAddSpacePerRasterLine(Double.parseDouble(value));
} else if (SETTING_COMPORT.equals(attribute)) {
this.setComPort(value);
} else if (SETTING_LASER_RATE.equals(attribute)) {
this.setLaserRate(Double.parseDouble(value));
} else if (SETTING_SEEK_RATE.equals(attribute)) {
this.setSeekRate(Double.parseDouble(value));
} else if (SETTING_FLIPX.equals(attribute)) {
this.setFlipXaxis("yes".equals(value));
} else if (SETTING_BEDWIDTH.equals(attribute)) {
this.setBedWidth(Double.parseDouble(value));
} else if (SETTING_BEDHEIGHT.equals(attribute)) {
this.setBedHeight(Double.parseDouble(value));
}
}
@Override
public int estimateJobDuration(LaserJob job) {
return 10000;
}
@Override
public LaserCutter clone() {
Lasersaur clone = new Lasersaur();
clone.comPort = comPort;
clone.laserRate = laserRate;
clone.seekRate = seekRate;
clone.bedHeight = bedHeight;
clone.bedWidth = bedWidth;
clone.flipXaxis = flipXaxis;
clone.addSpacePerRasterLine = addSpacePerRasterLine;
return clone;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment