RLPark 1.0.0
Reinforcement Learning Framework in Java
|
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 }