Skip to content

Commit

Permalink
Ruida: various driver bug fixes and improvments (#197)
Browse files Browse the repository at this point in the history
* Ruida: use sweep mode for engraving

The ruida controller supports multiple movement modes. These can be set
using the 0xCA01 and 0xCA41 commands. There are two types of movement
modes: regular and sweep. Both types have seperate hardware settings
for acceleration.

The regular mode (0x0) is used for regular cuts.

The sweeping modes are used for engraving:
- (0x1) bidirectional x-sweep
- (0x2) unidirectional x-sweep
- (0x?) unidirectional y-sweep
- (0x?) bidirectional y-sweep

The controller automatically adds appropriately sized padding on both
sides, so the padding code generation of LibLaserCut is removed
entirely.

The sweeping modes only support straight moves. However, due to the
imprecision of relative moves, slightly skewed raster lines might occur,
which cause the controller to do the padding moves twice (first to reach
the relative offset, and then again to reach the same height as the
destination). Work around this issue by only generating absolute moves.

The movement mode is set using the 0xCA01 command. The vendor software
also sets the movement mode via 0xCA41 for every layer, without any
obvious effect on the controllers behavior. To keep the machine code as
close to the vendors software as possible, generate 0xCA41 as well.
Annoyingly, the mode ids are swapped for 0xCA41.

* Ruida: fix 0xC902 speed conversion

The speed value for 0xC902 has to be given in µm/s as a 32 bit integer.
Use absoluteMM() to scale the internal speed value by a factor of 1000.

* Ruida: calculate speed percentage from maximum cutting speed

Fixes: #190

* Ruida: round instead of flooring

* Rudia: remove unnecessary array stop command

The 0xEB command is used to end an array opened with the 0xEA command,
but the array feature of the Ruida controller is currently not utilized
by LibLaserCut at all.

Therefore, remove the unnecessary and probably wrong array stop command.

* Ruida: fix layer property code generation

Previously only the first layer properly generated the layer property
code, due to missing resets of layer-specific variables.

Reset the layer-specific variables after every layer.

Fixes: #194

* Ruida: force first movement

When the machine code is generated, the initial position of the laser
is unknown. The initial state of the hardware might differ from [0,0].

Even worse: the instantiation of the driver is reused across multiple
laser runs, so the driver retains the position of the last movement, but
the controller might move to a different position after execution has
finished.

Instead of assuming a laser position, always force the generation of
machine code for the first movement by setting last_xy to NaN and
adding code to handle moves from an unknown position.

Fixes: #189

* Ruida: add missing reset of instance variables

vector_count and travel_distance should only count a single run, but the
instance of the driver is reused. Therefore, both variables are reset
when a new machine code generation is started.
  • Loading branch information
fblaese authored Dec 9, 2023
1 parent 462b57c commit c2bee3a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 53 deletions.
99 changes: 47 additions & 52 deletions src/main/java/de/thomas_oster/liblasercut/drivers/Ruida.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ public class Ruida extends LaserCutter
protected static final String SETTING_MAX_POWER = "Max laser power (%)";
protected static final String SETTING_BED_WIDTH = "Bed width (mm)";
protected static final String SETTING_BED_HEIGHT = "Bed height (mm)";
protected static final String SETTING_USE_BIDIRECTIONAL_RASTERING = "Use bidirectional rastering";
protected static final String SETTING_RASTER_PADDING = "Extra padding at ends of raster scanlines (mm)";
protected static final String SETTING_RASTER_OUTSIDE = "Allow raster padding outside machine limits (negative and positive)";
protected static final Locale FORMAT_LOCALE = Locale.US;

protected static final String[] uploadMethodList = {UPLOAD_METHOD_FILE, UPLOAD_METHOD_IP, UPLOAD_METHOD_SERIAL};
Expand Down Expand Up @@ -187,42 +184,36 @@ public boolean canEstimateJobDuration()
* 'runway' for laser to get up to speed when rastering (in mm)
*
*/
private Double rasterPadding = 20.;
@Deprecated
private transient Double rasterPadding = 0.;

@Override
public double getRasterPadding() {
if (rasterPadding == null) rasterPadding = 20.;
return rasterPadding;
}

public void setRasterPadding(Double rasterPadding) {
this.rasterPadding = rasterPadding;
return 0;
}

/*
* allow padding to move laser head outside of 'bed'
*/

private boolean allowOutsidePadding;
@Deprecated
private transient boolean allowOutsidePadding;

@Override
public boolean getRasterPaddingAllowOutsideMachineSpace() {
return this.allowOutsidePadding;
}

public void setRasterPaddingAllowOutsideMachineSpace(boolean allowOutsidePadding) {
this.allowOutsidePadding = allowOutsidePadding;
return false;
}

/**
* When rastering, whether to always cut from left to right, or to cut in both
* directions? (i.e. use the return stroke to raster as well)
*/
protected boolean useBidirectionalRastering = true;
@Deprecated
protected transient boolean useBidirectionalRastering = true;

public boolean getUseBidirectionalRastering()
{
return useBidirectionalRastering;
// currently only bidirectional rastering is supported (work mode has to be tested for unidirectional rastering)
return true;
}

public void setUseBidirectionalRastering(boolean useBidirectionalRastering)
Expand Down Expand Up @@ -269,12 +260,12 @@ private void find_and_write_bounding_box(LaserJob job) throws IOException
}


private transient double last_x = 0.0;
private transient double last_y = 0.0;
private transient double last_x = Double.NaN;
private transient double last_y = Double.NaN;
private transient int vector_count = 0;
private transient long travel_distance = 0;

private void vector(double x, double y, double dpi, boolean as_cut) throws IOException
private void vector(double x, double y, double dpi, boolean as_cut, boolean force_abs) throws IOException
{
double x_mm = Util.px2mm(x, dpi);
double y_mm = Util.px2mm(y, dpi);
Expand All @@ -287,16 +278,20 @@ private void vector(double x, double y, double dpi, boolean as_cut) throws IOExc
if ((dx == 0.0) && (dy == 0.0)) {
return;
}
if (vector_count % 10 == 0) { /* enforce absolute every 10 vectors */

/* enforce absolute every 10 vectors */
if (vector_count % 10 == 0 || force_abs || Double.isNaN(dx) || Double.isNaN(dy)) {
as_absolute = true;
}
else {
as_absolute = Math.max(Math.abs(dx), Math.abs(dy)) > 8.191;
}
vector_count += 1;

long distance = (long)Math.sqrt(dx*dx + dy*dy);
travel_distance += distance;
if (!Double.isNaN(dx) && !Double.isNaN(dy)) {
long distance = (long)Math.sqrt(dx*dx + dy*dy);
travel_distance += distance;
}

// estimate the new real position
last_x = x_mm;
Expand Down Expand Up @@ -552,6 +547,11 @@ public void sendJob(LaserJob job, ProgressListener pl, List<String> warnings) th
}

public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
last_x = Double.NaN;
last_y = Double.NaN;
vector_count = 0;
travel_distance = 0;

try {
stream = new ByteStream(out, (byte)0x88); // 0x11, 0x38
if (UPLOAD_METHOD_SERIAL.equals(uploadMethod)) {
Expand Down Expand Up @@ -591,10 +591,12 @@ public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
for (JobPart p : job.getParts())
{
float focus;
boolean engrave = false;

if ((p instanceof RasterPart) || (p instanceof Raster3dPart))
{
p = convertRasterizableToVectorPart((RasterizableJobPart)p, job, this.useBidirectionalRastering, true, true);
engrave = true;
p = convertRasterizableToVectorPart((RasterizableJobPart)p, job, getUseBidirectionalRastering(), true, true);
}
/* FALLTHRU */
if (p instanceof VectorPart)
Expand Down Expand Up @@ -624,12 +626,10 @@ public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
* Move the laserhead (laser on) from the current position to the x/y position of this command.
*/
if (first_vector) {
first_vector = false;

stream.hex("ca0100");
stream.hex("ca01").byteint(engrave ? 1 : 0); // processing mode (00: cut, 01: bidirectional x-sweep, 02: unidirectional x-sweep)
stream.hex("ca02").byteint(part_number); // start_layer
stream.hex("ca0113"); // blow on
stream.hex("c902").longint((int)currentSpeed);
stream.hex("c902").absoluteMM((int)currentSpeed);
// power for laser #1
stream.hex("c601").percent((int)currentMinPower);
stream.hex("c602").percent((int)currentMaxPower);
Expand All @@ -638,7 +638,12 @@ public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
stream.hex("ca030f");
stream.hex("ca1000");
}
vector(cmd.getX(), cmd.getY(), p.getDPI(), cmd.getType() == CmdType.LINETO);

vector(cmd.getX(), cmd.getY(), p.getDPI(), cmd.getType() == CmdType.LINETO, engrave);

if (first_vector) {
first_vector = false;
}
break;
}
case SETPROPERTY:
Expand All @@ -650,21 +655,21 @@ public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
currentMinPower = cmd_layer_percent("c631", part_number, currentMinPower, prop.getMinPower());
currentMaxPower = cmd_layer_percent("c632", part_number, currentMaxPower, prop.getPower());
// prop speed is in %, ruida speed is in mm/s (0..1000)
currentSpeed = cmd_layer_absoluteMM("c904", part_number, currentSpeed, prop.getSpeed() * 10);
currentSpeed = cmd_layer_absoluteMM("c904", part_number, currentSpeed, prop.getSpeed() * getMaxVectorCutSpeed() / 100);
// focus - n/a
// frequency
stream.hex("c660").byteint(part_number).hex("00").longint(prop.getFrequency());
// color - red for now
long color = (0 << 16) + (0 << 8) + 100;; //(normalizeColor(this.blue) << 16) + (normalizeColor(this.green) << 8) + normalizeColor(this.red);
stream.hex("ca06").byteint(part_number).longint(color);
// CA 41
stream.hex("ca41").byteint(part_number).byteint(0);
stream.hex("ca41").byteint(part_number).byteint(engrave ? 2 : 0); // processing mode (00: cut, 02: bidirectional x-sweep, 01: unidirectional x-sweep)
}
else {
currentMinPower = cmd_percent("c601", currentMinPower, prop.getMinPower());
currentMaxPower = cmd_percent("c602", currentMaxPower, prop.getPower());
// prop speed is in %, ruida speed is in mm/s (0..1000)
currentSpeed = cmd_absoluteMM("c902", currentSpeed, prop.getSpeed() * 10);
currentSpeed = cmd_absoluteMM("c902", currentSpeed, prop.getSpeed() * getMaxVectorCutSpeed() / 100);
}
break;
}
Expand All @@ -675,12 +680,17 @@ public void writeJobCode(LaserJob job, ProgressListener pl) throws IOException {
}
}
}

part_number++;
first_prop = true;
first_vector = true;
currentMinPower = -1;
currentMaxPower = -1;
currentSpeed = -1;
}

/* work interval */
stream.hex("DA010620").longint(travel_distance).longint(travel_distance);
/* finish */
stream.hex("EB");
/* stop */
stream.hex("E700");
/* eof */
Expand Down Expand Up @@ -925,9 +935,6 @@ else if (getExportPath() != null && getExportPath().length() > 0)
SETTING_MAX_POWER,
SETTING_BED_WIDTH,
SETTING_BED_HEIGHT,
SETTING_USE_BIDIRECTIONAL_RASTERING,
SETTING_RASTER_PADDING,
SETTING_RASTER_OUTSIDE
};

@Override
Expand All @@ -954,12 +961,6 @@ public Object getProperty(String attribute) {
return this.getBedWidth();
} else if (SETTING_BED_HEIGHT.equals(attribute)) {
return this.getBedHeight();
} else if (SETTING_USE_BIDIRECTIONAL_RASTERING.equals(attribute)) {
return this.getUseBidirectionalRastering();
} else if (SETTING_RASTER_PADDING.equals(attribute)) {
return this.getRasterPadding();
} else if (SETTING_RASTER_OUTSIDE.equals(attribute)) {
return this.getRasterPaddingAllowOutsideMachineSpace();
}
return null;
}
Expand Down Expand Up @@ -993,12 +994,6 @@ public void setProperty(String attribute, Object value) {
this.setBedHeigth((Double)value);
} else if (SETTING_BED_WIDTH.equals(attribute)) {
this.setBedWidth((Double)value);
} else if (SETTING_USE_BIDIRECTIONAL_RASTERING.equals(attribute)) {
this.setUseBidirectionalRastering((Boolean) value);
} else if (SETTING_RASTER_PADDING.equals(attribute)) {
this.setRasterPadding((Double) value);
} else if (SETTING_RASTER_OUTSIDE.equals(attribute)) {
this.setRasterPaddingAllowOutsideMachineSpace((Boolean) value);
}
}

Expand Down Expand Up @@ -1088,7 +1083,7 @@ public ByteStream longint(long val) throws IOException {
* append relative value
*/
public ByteStream relative(double d, boolean signed) throws IOException {
int val = (int)Math.floor(d);
int val = (int)Math.round(d);
// System.out.println("rel" + ((signed)?"Signed":"Unsigned") + "ValueToByteArray(" + d + " -> " + val + ")");
if (signed) {
if (val > 8191) {
Expand Down
2 changes: 1 addition & 1 deletion test-output/de.thomas_oster.liblasercut.drivers.Ruida.out
Original file line number Diff line number Diff line change
@@ -1 +1 @@
қ��p �m{��z��҉p�����������p ��� ������p���鉉 ��pى�� ������pY���鉉 ��p�� � ����������p�ī�pۉ��� ������p[����鉉 ��pi���� ������p뉉��鉉 ���9���л���B����5���鉉��� �ď�������I��� �ċ�� B������ ��Ћ��� ę����� ���� ���� ϱ�� ����� �����������鉉�������[/���/Ѣ����}�� ��"��"w?m"��/_���[/���m�����鉉 ��pۉ���������_p[��� -�����]pi����������_p뉉� -�����]����������_����m��m���� ������ -�����_�������U�����wE�w��w��wE��o��c����� A��� -����5�������U�����u��w���c����� A��� -��������� -�����]�����U����]�u��w���cpۉ���������Op[��� �E����Mpi����������Op뉉� �E����My�3��m���� ���� �����O������剉���w��w��wE������]�������3���%��k��� �E���%������������u�����m��]��m��� %㉉��M� ������ۉ����dp�`
қ��p �m{��z��҉p�����������p ��� ������p���鉉 ��pى�� ������pY���鉉 ��p�� � ����������p�ī�pۉ��� ������p[����鉉 ��pi���� ������p뉉��鉉 ���9���л���B����5���鉉��� �ď�������I��� �ċ�� B���5��� ��Ћ��� ę����� ���� ���� ϱ�� ����� �����������鉉�������[/���/Ѣ����}�� ��"�{"w�m"�;/Ѣ���[/���m�����鉉 ��p� ��������_p[ ����U����]pi ��������_p� ����U����]�9 ��л ��B� ��5���� ���� �ď ������I �� ċ � B���5��� ��Ћ��� ę����������_����q����_�����W����_���������_����������_�����U����_�����U������������������M���������W�������������������������������5�����U���5�����U��������q����������������������������U����������U����]����q����]���������]pۋ����]����Op[���������Mpi�����]����Op닉��������M�9���л���B����5���鋉��� �ď�������I��� ċ�� B���5��� ��Ћ��� ę�����3����O����������O�����[����O����剉��O����剉��󢉉������󂉉�������󢉉�e����󂉉��]���%��������%����3���%��������%���������颉��3���邉���]����M����3����M� ������e����ep�`
Expand Down

0 comments on commit c2bee3a

Please sign in to comment.