RLPark 1.0.0
Reinforcement Learning Framework in Java

RoombaSerialConnection.java

Go to the documentation of this file.
00001 package rlpark.plugin.irobot.internal.roomba;
00002 
00003 import gnu.io.SerialPort;
00004 
00005 import java.io.IOException;
00006 import java.util.Arrays;
00007 
00008 import rlpark.plugin.irobot.internal.descriptors.DropDescriptors;
00009 import rlpark.plugin.irobot.internal.descriptors.IRobotObservationReceiver;
00010 import rlpark.plugin.irobot.internal.serial.SerialPortToRobot;
00011 import rlpark.plugin.irobot.internal.serial.SerialPortToRobot.SerialPortInfo;
00012 import rlpark.plugin.rltoys.envio.observations.Legend;
00013 import rlpark.plugin.robot.internal.disco.datagroup.DropScalarGroup;
00014 import rlpark.plugin.robot.internal.disco.drops.Drop;
00015 import rlpark.plugin.robot.internal.sync.LiteByteBuffer;
00016 import rlpark.plugin.robot.internal.sync.Syncs;
00017 import rlpark.plugin.robot.observations.ObservationVersatile;
00018 import zephyr.plugin.core.api.synchronization.Chrono;
00019 
00020 public class RoombaSerialConnection implements IRobotObservationReceiver {
00021   static public final boolean SetupFireflyMandatory = false;
00022   private static final byte PacketID = 100;
00023   private final Drop sensorDrop = newSensorDrop();
00024   protected final DropScalarGroup sensors = new DropScalarGroup(sensorDrop);
00025   private final LiteByteBuffer byteBuffer = new LiteByteBuffer(sensorDrop.dataSize());
00026   private final byte[] Header = { 19, (byte) (1 + sensorDrop.dataSize()), PacketID };
00027   protected SerialPortToRobot serialPort;
00028   protected final String fileName;
00029   private boolean packetValid = false;
00030 
00031   public RoombaSerialConnection(String fileName) {
00032     this.fileName = fileName;
00033   }
00034 
00035   public static Drop newSensorDrop() {
00036     // return new Drop(IRobotLabels.RoombaSensorDropName, new DropData[] { new
00037     // DropByteArray("Data", 80) });
00038     // DropData[] descriptors = new DropData[] { new
00039     // DropBit(IRobotLabels.WheelDropLeft, 3),
00040     // new DropBit(IRobotLabels.WheelDropRight, 2), new
00041     // DropBit(IRobotLabels.BumpLeft, 1),
00042     // new DropBit(IRobotLabels.BumpRight, 0), new DropEndBit("EndPacket7") };
00043     // return new Drop(IRobotLabels.RoombaSensorDropName, descriptors);
00044     return DropDescriptors.newRoombaSensorDrop();
00045   }
00046 
00047   private boolean setupFirefly(SerialPortToRobot serialPort) {
00048     if (serialPort.purge() > 0)
00049       return true;
00050     System.out.println("Setting up Roomba's firefly...");
00051     try {
00052       serialPort.sendAndReceive("$$$", "CMD\r\n");
00053       serialPort.sendAndReceive("U,115k,N\r", "AOK\r\n");
00054       serialPort.send("---\r");
00055     } catch (IOException e) {
00056       System.out.println("Setting up Firefly has failed...");
00057       if (SetupFireflyMandatory) {
00058         e.printStackTrace();
00059         return false;
00060       }
00061     }
00062     return true;
00063   }
00064 
00065   private boolean setupRoomba(final SerialPortToRobot serialPort) {
00066     System.out.println("Setting up Roomba...");
00067     serialPort.wakeupRobot();
00068     do {
00069       if (!send(new char[] { 128 }))
00070         return false;
00071       if (!send(new char[] { 131 }))
00072         return false;
00073       if (!send(new char[] { 150, 0 }))
00074         return false;
00075     } while (purgeIFN());
00076     // send(new char[] { 148, 1, PacketID })
00077     return true;
00078   }
00079 
00080   public boolean purgeIFN() {
00081     int purge = serialPort.purge();
00082     if (purge > 0) {
00083       System.out.println("Data on the link: " + purge);
00084       return true;
00085     }
00086     return false;
00087   }
00088 
00089   @Override
00090   public void initialize() {
00091     SerialPortInfo serialPortInfo = new SerialPortInfo(115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
00092                                                        SerialPort.PARITY_NONE, SerialPort.FLOWCONTROL_RTSCTS_IN
00093                                                            | SerialPort.FLOWCONTROL_RTSCTS_OUT);
00094     serialPort = SerialPortToRobot.tryOpenPort(fileName, serialPortInfo);
00095     if (serialPort == null)
00096       return;
00097     serialPort.wakeupRobot();
00098     if (!setupFirefly(serialPort)) {
00099       serialPort.close();
00100       return;
00101     }
00102     if (!setupRoomba(serialPort))
00103       serialPort.close();
00104   }
00105 
00106   @Override
00107   public int packetSize() {
00108     return sensorDrop.dataSize();
00109   }
00110 
00111   @Override
00112   public ObservationVersatile waitForData() {
00113     pingRobot();
00114     return waitDataStream();
00115   }
00116 
00117   private final Chrono pingChrono = new Chrono(Chrono.longTimeAgo());
00118   private boolean dockOn = false;
00119 
00120   private void pingRobot() {
00121     if (pingChrono.getCurrentChrono() < 1.0)
00122       return;
00123     if (dockOn)
00124       send(new char[] { 139, 2, 0, 0 });
00125     else
00126       send(new char[] { 139, 4, 0, 0 });
00127     dockOn = !dockOn;
00128     pingChrono.start();
00129   }
00130 
00131   protected ObservationVersatile waitForDataRequest() {
00132     if (!send(new char[] { 142, 100 }))
00133       return null;
00134     byte[] data;
00135     try {
00136       data = serialPort.read(sensorDrop.dataSize());
00137     } catch (IOException e) {
00138       e.printStackTrace();
00139       return null;
00140     }
00141     if (data.length < sensorDrop.dataSize())
00142       System.err.println("data incomplete");
00143     byteBuffer.clear();
00144     byteBuffer.put(data);
00145     return Syncs.createObservation(System.currentTimeMillis(), byteBuffer, sensors);
00146   }
00147 
00148   private boolean send(char[] cs) {
00149     try {
00150       serialPort.send(cs);
00151     } catch (IOException e) {
00152       e.printStackTrace();
00153       return false;
00154     }
00155     return true;
00156   }
00157 
00158   private ObservationVersatile waitDataStream() {
00159     try {
00160       if (!packetValid)
00161         alignOnHeader();
00162       packetValid = readNextPacket(byteBuffer);
00163     } catch (IOException e) {
00164       e.printStackTrace();
00165       packetValid = false;
00166     }
00167     if (!packetValid)
00168       return null;
00169     return Syncs.createObservation(System.currentTimeMillis(), byteBuffer, sensors);
00170   }
00171 
00172   private boolean readNextPacket(LiteByteBuffer byteBuffer) throws IOException {
00173     byte checkSum = 01;
00174     byte[] data = null;
00175     while (checkSum != 0) {
00176       data = serialPort.read(byteBuffer.capacity() + Header.length + 1);
00177       if (!Arrays.equals(Header, Arrays.copyOf(data, Header.length)))
00178         return false;
00179       checkSum = computeChecksum(data);
00180     }
00181     byteBuffer.clear();
00182     byteBuffer.put(Arrays.copyOfRange(data, Header.length, data.length - 1));
00183     return true;
00184   }
00185 
00186   private byte computeChecksum(byte[] data) {
00187     int sum = 0;
00188     for (byte b : data)
00189       sum += b;
00190     return (byte) sum;
00191   }
00192 
00193   private void alignOnHeader() throws IOException {
00194     int checkedPosition = 0;
00195     int nbFailed = 0;
00196     while (checkedPosition < Header.length) {
00197       byte[] read = serialPort.read(1);
00198       if (read.length == 0)
00199         continue;
00200       if (read[0] == Header[checkedPosition]) {
00201         checkedPosition++;
00202       } else {
00203         nbFailed++;
00204         if (nbFailed > 1000) {
00205           serialPort.purge();
00206           System.out.println("Packet header cannot be found... just noise on the link");
00207           nbFailed = 0;
00208         }
00209         checkedPosition = 0;
00210       }
00211     }
00212     serialPort.read(sensorDrop.dataSize() + 1);
00213   }
00214 
00215   @Override
00216   public boolean isClosed() {
00217     return serialPort == null || serialPort.isClosed();
00218   }
00219 
00220   @Override
00221   public void sendMessage(byte[] bytes) {
00222     try {
00223       serialPort.send(bytes);
00224     } catch (IOException e) {
00225       e.printStackTrace();
00226       serialPort.close();
00227     }
00228   }
00229 
00230   @Override
00231   public Legend legend() {
00232     return sensors.legend();
00233   }
00234 
00235   @Override
00236   public void close() {
00237     serialPort.close();
00238   }
00239 }
 All Classes Namespaces Files Functions Variables Enumerations
Zephyr
RLPark