From 9deb3fb71f2990eed45fb188491d23b29c0c0cc6 Mon Sep 17 00:00:00 2001 From: dwalend Date: Sun, 17 Jan 2021 22:31:27 -0500 Subject: [PATCH 1/6] GenericMode with a rereader --- src/main/java/ev3dev/sensors/GenericMode.java | 51 ++++++++++++------- .../sensors/nxt/NXTTemperatureSensor.java | 2 + 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/main/java/ev3dev/sensors/GenericMode.java b/src/main/java/ev3dev/sensors/GenericMode.java index 368b7d4c..a744ff03 100644 --- a/src/main/java/ev3dev/sensors/GenericMode.java +++ b/src/main/java/ev3dev/sensors/GenericMode.java @@ -1,9 +1,12 @@ package ev3dev.sensors; -import ev3dev.utils.Sysfs; +import ev3dev.utils.DataChannelRereader; import lejos.hardware.sensor.SensorMode; +import java.io.Closeable; import java.io.File; +import java.io.IOException; +import java.nio.file.Path; /** * Generic ev3dev sensor handler. @@ -12,9 +15,9 @@ * are valid only when the sensor itself is in the correct mode. * Otherwise, wrong data will be returned.

*/ -public class GenericMode implements SensorMode { - protected final File pathDevice; +public class GenericMode implements SensorMode, Closeable { + private final int sampleSize; private final String modeName; @@ -22,6 +25,8 @@ public class GenericMode implements SensorMode { private final float correctMax; private final float correctFactor; + private final DataChannelRereader[] rereaders; + /** * Create new generic sensor handler. * @param pathDevice Reference to the object responsible for mode setting and value reading. @@ -29,11 +34,11 @@ public class GenericMode implements SensorMode { * @param modeName Human-readable sensor mode name. */ public GenericMode( - final File pathDevice, - final int sampleSize, - final String modeName) { + final File pathDevice, + final int sampleSize, + final String modeName) { this(pathDevice, sampleSize, modeName, - Float.MIN_VALUE, Float.MAX_VALUE, 1.0f); + Float.MIN_VALUE, Float.MAX_VALUE, 1.0f); } /** @@ -42,23 +47,27 @@ public GenericMode( * @param pathDevice Reference to the object responsible for mode setting and value reading. * @param sampleSize Number of returned samples. * @param modeName Human-readable sensor mode name. - * @param correctMin Minimum value measured by the sensor. If the reading is lower, zero is returned. + * @param correctMin Minimum value measured by the sensor. If the reading is lower, negative infinity is returned * @param correctMax Maximum value measured by the sensor. If the reading is higher, positive infinity is returned. * @param correctFactor Scaling factor applied to the sensor reading. */ public GenericMode( - final File pathDevice, - final int sampleSize, - final String modeName, - final float correctMin, - final float correctMax, - final float correctFactor) { - this.pathDevice = pathDevice; + final File pathDevice, + final int sampleSize, + final String modeName, + final float correctMin, + final float correctMax, + final float correctFactor) { this.sampleSize = sampleSize; this.modeName = modeName; this.correctMin = correctMin; this.correctMax = correctMax; this.correctFactor = correctFactor; + + this.rereaders = new DataChannelRereader[sampleSize]; + for (int n = 0; n < sampleSize; n++) { + rereaders[n] = new DataChannelRereader(Path.of(pathDevice.toString(),"value" + n),32); + } } @Override @@ -71,7 +80,6 @@ public int sampleSize() { return sampleSize; } - /** * Fetches a sample from the sensor. * @@ -88,12 +96,12 @@ public void fetchSample(float[] sample, int offset) { // for all values for (int n = 0; n < sampleSize; n++) { // read - float reading = Sysfs.readFloat(this.pathDevice + "/" + "value" + n); + float reading = Float.parseFloat(rereaders[n].readString()); // apply correction reading *= correctFactor; if (reading < correctMin) { - reading = 0; + reading = Float.NEGATIVE_INFINITY; } else if (reading >= correctMax) { reading = Float.POSITIVE_INFINITY; } @@ -102,4 +110,11 @@ public void fetchSample(float[] sample, int offset) { sample[offset + n] = reading; } } + + @Override + public void close() throws IOException { + for (DataChannelRereader rereader: rereaders) { + rereader.close(); + } + } } diff --git a/src/main/java/ev3dev/sensors/nxt/NXTTemperatureSensor.java b/src/main/java/ev3dev/sensors/nxt/NXTTemperatureSensor.java index 55f94879..0021a993 100644 --- a/src/main/java/ev3dev/sensors/nxt/NXTTemperatureSensor.java +++ b/src/main/java/ev3dev/sensors/nxt/NXTTemperatureSensor.java @@ -51,6 +51,7 @@ private class InternalMode extends GenericMode { private final float correctMin; private final float correctMax; private final float correctFactor; + private final File pathDevice; public InternalMode(File pathDevice, int sampleSize, String modeName, float correctMin, float correctMax, float correctFactor) { @@ -59,6 +60,7 @@ public InternalMode(File pathDevice, int sampleSize, String modeName, this.correctMin = correctMin; this.correctMax = correctMax; this.correctFactor = correctFactor; + this.pathDevice = pathDevice; } @Override From 8ce1e718fc02d7844641532e801632ffce4360ae Mon Sep 17 00:00:00 2001 From: dwalend Date: Sun, 17 Jan 2021 22:39:06 -0500 Subject: [PATCH 2/6] Pulled back the negative infinity change --- src/main/java/ev3dev/sensors/GenericMode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ev3dev/sensors/GenericMode.java b/src/main/java/ev3dev/sensors/GenericMode.java index a744ff03..9f9359fc 100644 --- a/src/main/java/ev3dev/sensors/GenericMode.java +++ b/src/main/java/ev3dev/sensors/GenericMode.java @@ -101,7 +101,7 @@ public void fetchSample(float[] sample, int offset) { // apply correction reading *= correctFactor; if (reading < correctMin) { - reading = Float.NEGATIVE_INFINITY; + reading = 0; } else if (reading >= correctMax) { reading = Float.POSITIVE_INFINITY; } From 5dce516ed074d9285916d52883a37c1cc7b149d9 Mon Sep 17 00:00:00 2001 From: dwalend Date: Sun, 17 Jan 2021 22:47:53 -0500 Subject: [PATCH 3/6] Pulled back the negative infinity change --- src/main/java/ev3dev/sensors/GenericMode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ev3dev/sensors/GenericMode.java b/src/main/java/ev3dev/sensors/GenericMode.java index 9f9359fc..ef01d49d 100644 --- a/src/main/java/ev3dev/sensors/GenericMode.java +++ b/src/main/java/ev3dev/sensors/GenericMode.java @@ -47,7 +47,7 @@ public GenericMode( * @param pathDevice Reference to the object responsible for mode setting and value reading. * @param sampleSize Number of returned samples. * @param modeName Human-readable sensor mode name. - * @param correctMin Minimum value measured by the sensor. If the reading is lower, negative infinity is returned + * @param correctMin Minimum value measured by the sensor. If the reading is lower, 0 is returned * @param correctMax Maximum value measured by the sensor. If the reading is higher, positive infinity is returned. * @param correctFactor Scaling factor applied to the sensor reading. */ From 5afa275f6366bf639725fb024db28e84f24e6919 Mon Sep 17 00:00:00 2001 From: dwalend Date: Sat, 30 Jan 2021 22:04:04 -0500 Subject: [PATCH 4/6] Copied latest Rewriter --- .../ev3dev/utils/DataChannelRewriter.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index 3a5a1f09..c2383db2 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -1,10 +1,14 @@ package ev3dev.utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; +import java.nio.file.AccessDeniedException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; @@ -21,6 +25,8 @@ public class DataChannelRewriter implements Closeable { private final ByteBuffer byteBuffer; private final FileChannel channel; + private static final Logger log = LoggerFactory.getLogger(DataChannelRewriter.class); + /** * Create a DataChannelRewriter for path with a bufferLength byte buffer * @@ -28,12 +34,25 @@ public class DataChannelRewriter implements Closeable { * @param bufferLength length of the buffer to hold the structure */ public DataChannelRewriter(Path path, int bufferLength) { + this.path = path; this.byteBuffer = ByteBuffer.allocate(bufferLength); try { - this.channel = FileChannel.open(path, StandardOpenOption.WRITE); - } catch (IOException e) { + this.channel = keepTryingFileChannel(path); + } catch (IOException | InterruptedException e) { throw new RuntimeException("While opening " + path,e); + } //todo could also try Files.exists(pathToFind); + } + + @SuppressWarnings("BusyWait") + private static FileChannel keepTryingFileChannel(Path path) throws IOException, InterruptedException { + for (;;) { + try { + return FileChannel.open(path, StandardOpenOption.WRITE); + } catch (AccessDeniedException adx) { + log.debug("Retrying after 10 ms due to access exception",adx); + Thread.sleep(10); + } } } @@ -59,10 +78,14 @@ public synchronized void writeString(String string) { channel.write(byteBuffer,0); channel.force(false); } catch (IOException e) { - throw new RuntimeException("Problem writing path: " + path, e); + throw new RuntimeException("Problem reading path: "+path, e); } } + public void writeAsciiInt(int i) { + writeString(Integer.toString(i)); + } + public Path getPath() { return path; } @@ -72,4 +95,3 @@ public synchronized void close() throws IOException { channel.close(); } } - From 8f4d1b6c7f682b1cb79069fc8687a0e95237e040 Mon Sep 17 00:00:00 2001 From: dwalend Date: Sat, 30 Jan 2021 22:05:44 -0500 Subject: [PATCH 5/6] Copied latest base motor --- .../lego/motors/BaseRegulatedMotor.java | 114 +++++++++++++----- 1 file changed, 86 insertions(+), 28 deletions(-) diff --git a/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java b/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java index 5f99e069..c8ebdf6b 100644 --- a/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java +++ b/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java @@ -3,6 +3,8 @@ import ev3dev.hardware.EV3DevMotorDevice; import ev3dev.hardware.EV3DevPlatforms; import ev3dev.sensors.Battery; +import ev3dev.utils.DataChannelRereader; +import ev3dev.utils.DataChannelRewriter; import lejos.hardware.port.Port; import lejos.robotics.RegulatedMotor; import lejos.robotics.RegulatedMotorListener; @@ -10,6 +12,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -18,12 +23,12 @@ * Abstraction for a Regulated motors motors. * The basic control methods are: * forward, backward, reverseDirection, stop - * and flt. To set each motors's velocity, use {@link #setSpeed(int) + * and flt. To set each motor's velocity, use {@link #setSpeed(int) * setSpeed }. * The maximum velocity of the motors is limited by the battery voltage and load. * With no load, the maximum degrees per second is about 100 times the voltage * (for the large EV3 motors).
- * The velocity is regulated by comparing the tacho count with velocity times elapsed + * The velocity is regulated by comparing the tachoodometer count with velocity times elapsed * time, and adjusting motors power to keep these closely matched. Changes in velocity * will be made at the rate specified via the * setAcceleration(int acceleration) method. @@ -42,8 +47,9 @@ * @author Roger Glassey * @author Andy Shaw * @author Juan Antonio Breña Moral + * @author David Walend */ -public abstract class BaseRegulatedMotor extends EV3DevMotorDevice implements RegulatedMotor { +public abstract class BaseRegulatedMotor extends EV3DevMotorDevice implements RegulatedMotor, Closeable { private static final Logger log = LoggerFactory.getLogger(BaseRegulatedMotor.class); @@ -51,12 +57,25 @@ public abstract class BaseRegulatedMotor extends EV3DevMotorDevice implements Re protected final int MAX_SPEED_AT_9V; private int speed = 360; + + //todo never used protected int acceleration = 6000; private boolean regulationFlag = true; private final List listenerList; + private final DataChannelRereader odometerRereader; + private final DataChannelRereader stateRereader; + private final DataChannelRereader dutyCycleRereader; + private final DataChannelRereader speedRereader; + + private final DataChannelRewriter commandRewriter; + private final DataChannelRewriter stopCommandRewriter; + private final DataChannelRewriter dutyCycleRewriter; + private final DataChannelRewriter speedRewriter; + private final DataChannelRewriter positionRewriter; + /** * Constructor * @@ -70,6 +89,7 @@ public abstract class BaseRegulatedMotor extends EV3DevMotorDevice implements Re * @param offset offset * @param maxSpeed maxSpeed */ + //todo can we drop all these unused variables? public BaseRegulatedMotor(final Port motorPort, float moveP, float moveI, float moveD, float holdP, float holdI, float holdD, int offset, int maxSpeed) { @@ -96,12 +116,38 @@ public BaseRegulatedMotor(final Port motorPort, float moveP, float moveI, float this.detect(TACHO_MOTOR, port); //TODO Review to implement asynchronous solution Delay.msDelay(1000); - this.setStringAttribute(COMMAND, RESET); + + odometerRereader = new DataChannelRereader(Path.of(PATH_DEVICE.toString(),POSITION),8); + stateRereader = new DataChannelRereader(Path.of(PATH_DEVICE.toString(),STATE),32); + dutyCycleRereader = new DataChannelRereader(Path.of(PATH_DEVICE.toString(),DUTY_CYCLE),32); + speedRereader = new DataChannelRereader(Path.of(PATH_DEVICE.toString(),SPEED),32); + + commandRewriter = new DataChannelRewriter(Path.of(PATH_DEVICE.toString(),COMMAND),32); + stopCommandRewriter = new DataChannelRewriter(Path.of(PATH_DEVICE.toString(),STOP_COMMAND),32); + dutyCycleRewriter = new DataChannelRewriter(Path.of(PATH_DEVICE.toString(),DUTY_CYCLE),32); + speedRewriter = new DataChannelRewriter(Path.of(PATH_DEVICE.toString(),SPEED),32); + positionRewriter = new DataChannelRewriter(Path.of(PATH_DEVICE.toString(),POSITION_SP),32); + + commandRewriter.writeString(RESET); if (log.isDebugEnabled()) { log.debug("Motor ready to use on Port: {}", motorPort.getName()); } } + @Override + public void close() throws IOException { + odometerRereader.close(); + stateRereader.close(); + dutyCycleRereader.close(); + speedRereader.close(); + + commandRewriter.close(); + stopCommandRewriter.close(); + dutyCycleRewriter.close(); + speedRewriter.close(); + positionRewriter.close(); + } + /** * Removes this motors from the motors regulation system. After this call * the motors will be in float mode and will have stopped. Note calling any @@ -116,11 +162,11 @@ public boolean suspendRegulation() { } /** - * @return the current tachometer count. - * @see lejos.robotics.RegulatedMotor#getTachoCount() + * @return the current tachoodometer count. + * @see RegulatedMotor#getTachoCount() */ public int getTachoCount() { - return getIntegerAttribute(POSITION); + return odometerRereader.readAsciiInt(); } /** @@ -141,9 +187,9 @@ public float getPosition() { public void forward() { this.setSpeedDirect(this.speed); if (!this.regulationFlag) { - this.setStringAttribute(COMMAND, RUN_DIRECT); + commandRewriter.writeString(RUN_DIRECT); } else { - this.setStringAttribute(COMMAND, RUN_FOREVER); + commandRewriter.writeString(RUN_FOREVER); } for (RegulatedMotorListener listener : listenerList) { @@ -155,9 +201,9 @@ public void forward() { public void backward() { this.setSpeedDirect(-this.speed); if (!this.regulationFlag) { - this.setStringAttribute(COMMAND, RUN_DIRECT); + commandRewriter.writeString(RUN_DIRECT); } else { - this.setStringAttribute(COMMAND, RUN_FOREVER); + commandRewriter.writeString(RUN_FOREVER); } for (RegulatedMotorListener listener : listenerList) { @@ -184,6 +230,10 @@ public void coast() { doStop(COAST, false); } + public void coast(boolean immediateReturn) { + doStop(COAST, immediateReturn); + } + /** * Removes power from the motor and creates a passive electrical load. * This is usually done by shorting the motor terminals together. @@ -194,6 +244,10 @@ public void brake() { doStop(BRAKE, false); } + public void brake(boolean immediateReturn) { + doStop(BRAKE, immediateReturn); + } + /** * Causes the motor to actively try to hold the current position. * If an external force tries to turn the motor, the motor will “push back” to maintain its position. @@ -203,6 +257,10 @@ public void hold() { doStop(HOLD, false); } + public void hold(boolean immediateReturn) { + doStop(HOLD, immediateReturn); + } + /** * Causes motors to stop, pretty much * instantaneously. In other words, the @@ -227,8 +285,8 @@ public void stop(boolean immediateReturn) { * @param immediateReturn Whether the function should busy-wait until the motor stops reporting the 'running' state. */ private void doStop(String mode, boolean immediateReturn) { - this.setStringAttribute(STOP_COMMAND, mode); - this.setStringAttribute(COMMAND, STOP); + stopCommandRewriter.writeString(mode); + commandRewriter.writeString(STOP); if (!immediateReturn) { waitComplete(); @@ -252,7 +310,7 @@ private void doStop(String mode, boolean immediateReturn) { */ @Override public boolean isMoving() { - return (this.getStringAttribute(STATE).contains(STATE_RUNNING)); + return stateRereader.readString().contains(STATE_RUNNING); } /** @@ -269,9 +327,9 @@ public void setSpeed(int speed) { private void setSpeedDirect(int speed) { if (!this.regulationFlag) { - this.setIntegerAttribute(DUTY_CYCLE, speed); + dutyCycleRewriter.writeAsciiInt(speed); } else { - this.setIntegerAttribute(SPEED, speed); + speedRewriter.writeAsciiInt(speed); } } @@ -280,7 +338,7 @@ private void setSpeedDirect(int speed) { * will cause any current move operation to be halted. */ public void resetTachoCount() { - this.setStringAttribute(COMMAND, RESET); + commandRewriter.writeString(RESET); this.regulationFlag = true; } @@ -293,8 +351,8 @@ public void resetTachoCount() { */ public void rotate(int angle, boolean immediateReturn) { this.setSpeedDirect(this.speed); - this.setIntegerAttribute(POSITION_SP, angle); - this.setStringAttribute(COMMAND, RUN_TO_REL_POS); + positionRewriter.writeAsciiInt(angle); + commandRewriter.writeString(RUN_TO_REL_POS); if (!immediateReturn) { while (this.isMoving()) { @@ -302,7 +360,7 @@ public void rotate(int angle, boolean immediateReturn) { // possibly sleep for some short interval to not block } } - + //todo this should happen before the busy wait for (RegulatedMotorListener listener : listenerList) { listener.rotationStarted(this, this.getTachoCount(), this.isStalled(), System.currentTimeMillis()); } @@ -325,8 +383,8 @@ public void rotate(int angle) { */ public void rotateTo(int limitAngle, boolean immediateReturn) { this.setSpeedDirect(this.speed); - this.setIntegerAttribute(POSITION_SP, limitAngle); - this.setStringAttribute(COMMAND, RUN_TO_ABS_POS); + positionRewriter.writeAsciiInt(limitAngle); + commandRewriter.writeString(RUN_TO_ABS_POS); if (!immediateReturn) { while (this.isMoving()) { @@ -334,7 +392,7 @@ public void rotateTo(int limitAngle, boolean immediateReturn) { // possibly sleep for some short interval to not block } } - + //todo this should happen before the busy wait for (RegulatedMotorListener listener : listenerList) { listener.rotationStarted(this, this.getTachoCount(), this.isStalled(), System.currentTimeMillis()); } @@ -356,9 +414,9 @@ public void rotateTo(int limitAngle) { */ public int getSpeed() { if (!this.regulationFlag) { - return this.getIntegerAttribute(DUTY_CYCLE); + return dutyCycleRereader.readAsciiInt(); } else { - return this.getIntegerAttribute(SPEED); + return speedRereader.readAsciiInt(); } } @@ -369,7 +427,7 @@ public int getSpeed() { * @return true if the motors is stalled, else false */ public boolean isStalled() { - return (this.getStringAttribute(STATE).contains(STATE_STALLED)); + return (stateRereader.readString().contains(STATE_STALLED)); } /** @@ -414,13 +472,13 @@ public float getMaxSpeed() { return Battery.getInstance().getVoltage() * MAX_SPEED_AT_9V / 9.0f * 0.9f; } - @Override /** * sets the acceleration rate of this motor in degrees/sec/sec
* The default value is 6000; Smaller values will make speeding up. or stopping * at the end of a rotate() task, smoother; - * @param acceleration + * @param acceleration acceleration rate of this motor in degrees/sec/sec */ + @Override public void setAcceleration(int acceleration) { this.acceleration = Math.abs(acceleration); From e4ab34abf82e49abdd5ced87d3a9cbe362913e24 Mon Sep 17 00:00:00 2001 From: dwalend Date: Sat, 30 Jan 2021 22:15:16 -0500 Subject: [PATCH 6/6] BaseRegulatedMotor with rereaders and rewriters --- .../lego/motors/BaseRegulatedMotor.java | 17 ++--------------- .../java/ev3dev/utils/DataChannelRereader.java | 4 ++++ .../java/ev3dev/utils/DataChannelRewriter.java | 2 +- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java b/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java index c8ebdf6b..438310c0 100644 --- a/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java +++ b/src/main/java/ev3dev/actuators/lego/motors/BaseRegulatedMotor.java @@ -28,7 +28,7 @@ * The maximum velocity of the motors is limited by the battery voltage and load. * With no load, the maximum degrees per second is about 100 times the voltage * (for the large EV3 motors).
- * The velocity is regulated by comparing the tachoodometer count with velocity times elapsed + * The velocity is regulated by comparing the tachometer count with velocity times elapsed * time, and adjusting motors power to keep these closely matched. Changes in velocity * will be made at the rate specified via the * setAcceleration(int acceleration) method. @@ -89,7 +89,6 @@ public abstract class BaseRegulatedMotor extends EV3DevMotorDevice implements Re * @param offset offset * @param maxSpeed maxSpeed */ - //todo can we drop all these unused variables? public BaseRegulatedMotor(final Port motorPort, float moveP, float moveI, float moveD, float holdP, float holdI, float holdD, int offset, int maxSpeed) { @@ -162,7 +161,7 @@ public boolean suspendRegulation() { } /** - * @return the current tachoodometer count. + * @return the current tachometer count. * @see RegulatedMotor#getTachoCount() */ public int getTachoCount() { @@ -230,10 +229,6 @@ public void coast() { doStop(COAST, false); } - public void coast(boolean immediateReturn) { - doStop(COAST, immediateReturn); - } - /** * Removes power from the motor and creates a passive electrical load. * This is usually done by shorting the motor terminals together. @@ -244,10 +239,6 @@ public void brake() { doStop(BRAKE, false); } - public void brake(boolean immediateReturn) { - doStop(BRAKE, immediateReturn); - } - /** * Causes the motor to actively try to hold the current position. * If an external force tries to turn the motor, the motor will “push back” to maintain its position. @@ -257,10 +248,6 @@ public void hold() { doStop(HOLD, false); } - public void hold(boolean immediateReturn) { - doStop(HOLD, immediateReturn); - } - /** * Causes motors to stop, pretty much * instantaneously. In other words, the diff --git a/src/main/java/ev3dev/utils/DataChannelRereader.java b/src/main/java/ev3dev/utils/DataChannelRereader.java index 36066091..26bbe9fe 100644 --- a/src/main/java/ev3dev/utils/DataChannelRereader.java +++ b/src/main/java/ev3dev/utils/DataChannelRereader.java @@ -69,6 +69,10 @@ public synchronized String readString() { } } + public int readAsciiInt() { + return Integer.parseInt(readString()); + } + public Path getPath() { return path; } diff --git a/src/main/java/ev3dev/utils/DataChannelRewriter.java b/src/main/java/ev3dev/utils/DataChannelRewriter.java index c2383db2..59aecd9c 100644 --- a/src/main/java/ev3dev/utils/DataChannelRewriter.java +++ b/src/main/java/ev3dev/utils/DataChannelRewriter.java @@ -78,7 +78,7 @@ public synchronized void writeString(String string) { channel.write(byteBuffer,0); channel.force(false); } catch (IOException e) { - throw new RuntimeException("Problem reading path: "+path, e); + throw new RuntimeException("Problem reading path: " + path, e); } }