HuskyBaseDevice.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 Creativa77.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00005  * use this file except in compliance with the License. You may obtain a copy of
00006  * the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00013  * License for the specific language governing permissions and limitations under
00014  * the License.
00015  */
00016 
00017 package com.github.c77.base_driver.husky;
00018 
00023 import com.github.c77.base_driver.BaseDevice;
00024 import com.github.c77.base_driver.BaseStatus;
00025 import com.github.c77.base_driver.OdometryStatus;
00026 import com.hoho.android.usbserial.driver.UsbSerialDriver;
00027 import com.hoho.android.usbserial.util.SerialInputOutputManager;
00028 
00029 import org.apache.commons.logging.Log;
00030 import org.apache.commons.logging.LogFactory;
00031 
00032 import java.io.IOException;
00033 import java.nio.ByteBuffer;
00034 import java.util.concurrent.ExecutorService;
00035 import java.util.concurrent.Executors;
00036 
00037 public class HuskyBaseDevice implements BaseDevice {
00038     private final long initialTime;
00039 
00040     HuskyPacketReader packetReader = new HuskyPacketReader();
00041     HuskyOdometryStatus odometryStatus = new HuskyOdometryStatus();
00042 
00043     // Husky low level commands
00044     private static final byte SOH = (byte) 0xAA;
00045     private static final byte PROTOCOL_VERSION = (byte) 0x1;
00046     private static final byte STX = (byte) 0x55;
00047 
00048     // Hardcoded speed (linear and angular) scale and limits
00049     private static final double SPEED_LIMIT = 100.0;
00050     private static final double SPEED_SCALE = 100.0;
00051 
00052     private static final Log log = LogFactory.getLog(HuskyBaseDevice.class);
00053 
00054     // Underlying USB-serial driver
00055     private final UsbSerialDriver serialDriver;
00056 
00057     public BaseStatus getBaseStatus() {
00058         BaseStatus baseStatus;
00059         baseStatus = new BaseStatus();
00060         return baseStatus;
00061     }
00062 
00063     @Override
00064     public OdometryStatus getOdometryStatus() {
00065         return odometryStatus;
00066     }
00067 
00068 
00069     public HuskyBaseDevice(UsbSerialDriver driver) {
00070         // Initialize timestamp for messages to be written to the Husky base
00071         initialTime = System.currentTimeMillis();
00072 
00073         // Open and initialize the underlying USB-serial driver
00074         serialDriver = driver;
00075         try {
00076             serialDriver.open();
00077             serialDriver.setParameters(115200, UsbSerialDriver.DATABITS_8,
00078                     UsbSerialDriver.STOPBITS_1, UsbSerialDriver.PARITY_NONE);
00079             log.info("Serial device opened correctly");
00080         } catch (IOException e) {
00081             log.error("Error setting up device: " + e.getMessage(), e);
00082             try {
00083                 serialDriver.close();
00084             } catch (Throwable t) {
00085             }
00086             throw new RuntimeException("Couldn't open USB device driver", e);
00087         }
00088 
00089         // Listen for USB-serial input events and call updateReceivedData whenever new data
00090         // is received
00091         final ExecutorService executorService = Executors.newSingleThreadExecutor();
00092         SerialInputOutputManager serialInputOutputManager;
00093         final SerialInputOutputManager.Listener listener =
00094             new SerialInputOutputManager.Listener() {
00095                 @Override
00096                 public void onRunError(Exception e) {
00097                 }
00098 
00099                 @Override
00100                 public void onNewData(final byte[] data) {
00101                     HuskyBaseDevice.this.updateReceivedData(data);
00102                 }
00103             };
00104         serialInputOutputManager = new SerialInputOutputManager(serialDriver, listener);
00105         executorService.submit(serialInputOutputManager);
00106     }
00107 
00111     private void updateReceivedData(final byte[] bytes) {
00112         HuskyPacket packet = null;
00113         try {
00114             // Parse the packet
00115             packet = packetReader.parse(ByteBuffer.wrap(bytes));
00116 
00117         } catch (HuskyParserException e) {
00118             log.error("Error parsing incoming packet", e);
00119         }
00120 
00121         // If we did get a new packet
00122         if(packet != null) {
00123             switch(packet.getMessageType()) {
00124 
00125                 // It's encoder data: update odometry
00126                 case HuskyPacket.TYPE_ENCODER_DATA:
00127                     odometryStatus.update(packet.getPayload());
00128                     break;
00129 
00130                 // Ignore the rest of the packets
00131                 default:
00132                     break;
00133             }
00134         }
00135     }
00136 
00140     @Override
00141     public void initialize() {
00142         log.info("Initializing");
00143         // Request the base to publish the encoders value
00144         sendEncodersRequest();
00145     }
00146 
00152     @Override
00153     public void move(double linearVelX, double angVelZ) {
00154         // The Husky base takes linear and angular velocities.
00155         // All we need to do is to scale and limit each value and fit it in the right format
00156         sendMovementPackage(
00157                 scaleAndLimitSpeed(linearVelX),
00158                 scaleAndLimitSpeed(angVelZ));
00159     }
00160 
00161     private static int scaleAndLimitSpeed(double speed) {
00162         return (int)Math.round(Math.max(Math.min(speed * SPEED_SCALE, SPEED_LIMIT), -1.0*SPEED_LIMIT));
00163     }
00164 
00168     private void sendEncodersRequest() {
00169         byte [] encoderRequestMessage = new byte[] {
00170             0x00, 0x48, 0x55, 0x0A, 0x00
00171         };
00172         write(buildPackage(encoderRequestMessage));
00173     }
00174 
00179     private void sendMovementPackage(int linearSpeed, int angSpeed) {
00180         int linearAccel = 0x00C8;         // Fixed acceleration of 5[m/s²]
00181         int MSGType = 0x0204;             // Set velocities using kinematic model
00182 
00183         //Little-endian encoding
00184         byte[] baseControlMsg = new byte[]{
00185             (byte) MSGType,
00186             (byte) (MSGType >> 8),
00187             STX,
00188             (byte) linearSpeed,
00189             (byte) (linearSpeed >> 8),
00190             (byte) angSpeed,
00191             (byte) (angSpeed >> 8),
00192             (byte) linearAccel,
00193             (byte) (linearAccel >> 8)
00194         };
00195 
00196         write(buildPackage(baseControlMsg));
00197     }
00198 
00199 
00203     byte[] buildPackage(byte[] payload) {
00204         char checksum = 0;
00205         int payloadLength = payload.length;
00206         byte[] pkg = new byte[payloadLength + 11];
00207         long msgTime = System.currentTimeMillis();
00208 
00209         byte Flags = (byte) 0x01;                        // ACK suppressed
00210         byte Length0 = (byte) (payloadLength + 8);
00211         byte Length1 = (byte) ~Length0;                  // It always is Length0's complement
00212         int TimeStamp = (int)msgTime - (int)initialTime; // Set TimeStamp in milliseconds using four bytes
00213 
00214         pkg[0] = SOH;
00215         pkg[1] = Length0;
00216         pkg[2] = Length1;
00217         pkg[3] = PROTOCOL_VERSION;
00218         pkg[4] = (byte) TimeStamp;
00219         pkg[5] = (byte) (TimeStamp >> 8);
00220         pkg[6] = (byte) (TimeStamp >> 16);
00221         pkg[7] = (byte) (TimeStamp >> 24);
00222         pkg[8] = Flags;
00223 
00224         for (int i = 9; i < payloadLength + 9; i++) {
00225             pkg[i] = payload[i - 9];
00226         }
00227 
00228         checksum = HuskyBaseUtils.checkSum(pkg);
00229         pkg[pkg.length - 2] = (byte)checksum;
00230         pkg[pkg.length - 1] = (byte)(checksum >> 8);
00231 
00232         return pkg;
00233     }
00234 
00239     private void write(byte[] command) {
00240         try {
00241             serialDriver.write(command, 1000);
00242         } catch(Throwable t) {
00243             log.error("Exception writing command: " + HuskyBaseUtils.byteArrayToString(command), t);
00244         }
00245     }
00246 }


android_base_controller
Author(s):
autogenerated on Fri Aug 28 2015 10:04:47