com.brianziman.robotics
Class SCIP11

java.lang.Object
  extended by com.brianziman.robotics.SCIP11

public class SCIP11
extends java.lang.Object

SCIP 1.1 Java Interface for Hokuyo URG-04LX Laser Sensor

Copyright 2007 - Brian Ziman

This class implements the SCIP 1.1 protocol for the Hokuyo URG-04LX Laser sensor. It communicates over a socket to Prof. Sean Luke's serialdaemon utility which communicates directly with the serial port.

The JavaDoc for the public methods will provide useful information for end users. The more useful public methods may throw a runtime exception, SCIPException is something weird happens, for example, if the connection to the serialdaemon dies, or if invalid data is received from the laser. The response in these situations is undefined, which is why it is a runtime exception that does not and should not be explicitely caught, unless you're really sure you know how to handle it.

Each function returns a status code, which according to the spec, indicates merely success or failure. Whenever a failure is recorded, a message is sent to standard output. On the off chance that the status code is important, there is a public method to retreive the last error status, which resets the status field to zero. I wouldn't count on it having anything meaningful, though.

This interface is implemented precisely according to the SCIP spec, however there are at least a few obvious mistakes in the spec, and a few things that are probably mistakes. In cases where I wasn't sure, I followed the spec, and I'm hoping testing will reveal whether the spec was indeed correct, or not.

The following information is based on the URG Series Communication Protocol Specification (SCIP Version 1.1).

Host to Sensor commands are in the format:

|Command|Parameter|LF/CR|

The Sensor will then respond in the format:

|Command|Parameter|LF|Status|LF|Data|LF|LF|

Commands:

Version Information

 Command is 'V' (0x56)
 No parameter.
 Request is:
 |'V'|LF/CR|

 Response is:
 |'V'         |LF|
 |Status      |LF|
 |Vendor Info |LF|
 |Product Info|LF|
 |Firmware Ver|LF|
 |Protocol Ver|LF|
 |Serial Num  |LF|LF|
 

Laser Illumination Control

 Command is 'L' (0x4C)
 Parameter is 1 byte Control Code.
 '1' switches laser on.
 '0' switches laser off.
 (Are these 0x31 and 0x30? or 0x01 and 0x00? Need to check.)
 Request is:
 |'L'|'0'/'1'|LF/CR|

 Response is:
 |'L'|'0'/'1'|LF|Status|LF|LF|
 

Communication Settings (Ignored when using USB connection)

 Command is 'S' (0x53)
 Parameter is 6 ascii digit baud rate, followed by 7 digit reserved.
 "019200" sets 19.2kbps (default)
 "057600" sets 57.6kbps
 "115200" sets 115.2kbps
 "250000" sets 250.0kbps
 "500000" sets 500.0kbps
 "750000" sets 750.0kbps
 Request is:
 |'S'|aaaaaa|rrrrrrr|LF/CR|

 Response is:
 |'S'|aaaaaa|rrrrrrr|Status|LF|LF|  (why is there no LF before Status here?)
 

Distance Data Acquisition

 Command is 'G' (0x47)
 Parameters are 3 digit starting point, 3 digit ending point,
            and 2 digit cluster count.
            Starting and ending point range from 0..768.
            Cluster count is from 0..99.
            (Encoded using ascii digits 0x30-0x39).
 Request is:
 |'G'|sss|eee|cc|LF/CR|
 
 Response is:
 |'G'|sss|eee|cc|LF|Status|Data|LF|LF|
 Where data is broken into blocks of 64 bytes followed by LF.

 Sensor measures range of 4095mm with 1mm resolution.
 Data point is expressed with 12 bits (0..4095).  12 bit
 value is encoded as follows:

 1234mm = 010011 010010(binary)
        = 0x13 0x12
  +0x30 = 0x43 0x42 = 'C','D' (ascii)

 Starting and ending point refer to steps in the field of
 angular detection.  This field is a range of 240 degrees,
 with a dead zone of 120 degrees at the rear.
 Step 0 is at -135 degrees from front (right), Step 384 is at 0 degrees
 (facing front), and Step 768 is at +135 degrees (left).
 Step 0 and 768 are both in the deadzone.
 Measurable range is from Step 44 to Step 725.
 Each step has a resolution of 360deg/1024 = 0.3515625 deg.

 I assume that the "cluster" parameter, which refers to the
 number of neighboring points that are grouped as a cluster
 would reduce the amount of data returned.

 For example, if start is at "44" and end is at "725" and
 cluster is "01", then you would expect some 680 data points.

 If cluster were "20", then you might expect only 34 data points,
 each of which is perhaps the average of a 7 degree arc?

 Sensors will return values between 20mm and 4094mm.  Anything
 less than 20mm will result in an error code at that data point.

 Error codes for data points are (don't ask me what they mean):

  0    "Possibility of detected object is at 22m"
  1-5  "Reflected light has low intensity"
  6    "Possibility of detected object is at 5.7m"
  7    "Distance data on the preceding and succeeding steps have errors"
  8    "Others"
  9    "The same step had error in the last two scan"
 10-15 "Others"
 16    "Possibility of detected object is in the range 4096mm"
 17    "Others"
 18    "Unspecified"
 19    "Non-Measurable Distance"
 


Field Summary
static java.lang.String BAUD_019200
          19.2kbps baud rate.
static java.lang.String BAUD_057600
          57.6kbps baud rate.
static java.lang.String BAUD_115200
          115.2kbps baud rate.
static java.lang.String BAUD_250000
          250kbps baud rate.
static java.lang.String BAUD_500000
          500kbps baud rate.
static java.lang.String BAUD_750000
          750kbps baud rate.
static java.lang.String KEY_FIRMWARE
          Firmware Version.
static java.lang.String KEY_PRODUCT
          Product Information.
static java.lang.String KEY_PROTOCOL
          Protocol Version.
static java.lang.String KEY_SERIAL
          Sensor Serial Number.
static java.lang.String KEY_STATUS
          Undocumented Status Field.
static java.lang.String KEY_VENDOR
          Vendor Information.
static int MAX_CLUSTER
          Largest number of clusters permitted.
static int MAX_STEP
          Maximum step value for laser that corresponds with 135 degrees to the left of forward.
static int MIN_CLUSTER
          Smallest number of clusters permitted.
static int MIN_STEP
          Minimum step value for laser that corresponds with -135 degrees to the right of forward.
 
Constructor Summary
SCIP11(int port)
           
 
Method Summary
 void disable()
          Disable the laser.
 java.util.ArrayList<java.lang.Integer> doDistanceCommand(int start, int end, int cluster)
           Internal method to request sensor data from the laser.
 void doLaserCommand(boolean enable)
          Internal method to enable or disable the laser.
 void doSettingsCommand(java.lang.String baud)
          Internal method to configures the baud rate of the device.
 java.util.HashMap<java.lang.String,java.lang.String> doVersionCommand()
           Internal method to return a map of version info from the laser.
 void enable()
          Enable the laser.
 double getAngleOffset()
          Retreive the angle offset.
static java.lang.String getErrorFromData(int c)
          If a data point less than 20 is returned, it corresponds to an error code as documented.
 java.lang.String getFirmwareVersion()
          Returns static firmware version from laser.
 byte getLastError()
          Return the last error code byte generated by the laser and clear the code.
 java.lang.String getProductInfo()
          Returns static product information from laser.
 java.lang.String getProtocolVersion()
          Returns static protocol version from laser.
 int getRange(double angle)
          Returns the range detected at the given angle, measured in degrees, and within the angular range of the sensor, -120 degrees to +120 degrees.
 long getScanTime()
           
 java.lang.String getSensorSerialNumber()
          Returns static sensor serial number from laser.
 java.lang.String getSensorStatus()
          Returns undocumented static status field laser.
 java.lang.String getVendorInfo()
          Returns static vendor information from laser.
static void main(java.lang.String[] args)
          Only useful for testing.
 void setAngleOffset(double d)
          The Hokuyo laser ranger considers forward to be zero degrees, however, some systems, such as the sensor array on the Pioneer robots, consider zero degrees to be in other locations (for the Pioneers, that would be on the right).
 void setBaud(java.lang.String baud)
          Set the baud rate using one of the BAUD_n constants.
 void setScanTime(long l)
          This method specifies the number of milliseconds per scan of the laser.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

MIN_STEP

public static final int MIN_STEP
Minimum step value for laser that corresponds with -135 degrees to the right of forward.

See Also:
Constant Field Values

MAX_STEP

public static final int MAX_STEP
Maximum step value for laser that corresponds with 135 degrees to the left of forward.

See Also:
Constant Field Values

MIN_CLUSTER

public static final int MIN_CLUSTER
Smallest number of clusters permitted.

See Also:
Constant Field Values

MAX_CLUSTER

public static final int MAX_CLUSTER
Largest number of clusters permitted.

See Also:
Constant Field Values

KEY_VENDOR

public static final java.lang.String KEY_VENDOR
Vendor Information.

See Also:
Constant Field Values

KEY_PRODUCT

public static final java.lang.String KEY_PRODUCT
Product Information.

See Also:
Constant Field Values

KEY_FIRMWARE

public static final java.lang.String KEY_FIRMWARE
Firmware Version.

See Also:
Constant Field Values

KEY_PROTOCOL

public static final java.lang.String KEY_PROTOCOL
Protocol Version.

See Also:
Constant Field Values

KEY_SERIAL

public static final java.lang.String KEY_SERIAL
Sensor Serial Number.

See Also:
Constant Field Values

KEY_STATUS

public static final java.lang.String KEY_STATUS
Undocumented Status Field.

See Also:
Constant Field Values

BAUD_019200

public static final java.lang.String BAUD_019200
19.2kbps baud rate.

See Also:
Constant Field Values

BAUD_057600

public static final java.lang.String BAUD_057600
57.6kbps baud rate.

See Also:
Constant Field Values

BAUD_115200

public static final java.lang.String BAUD_115200
115.2kbps baud rate.

See Also:
Constant Field Values

BAUD_250000

public static final java.lang.String BAUD_250000
250kbps baud rate.

See Also:
Constant Field Values

BAUD_500000

public static final java.lang.String BAUD_500000
500kbps baud rate.

See Also:
Constant Field Values

BAUD_750000

public static final java.lang.String BAUD_750000
750kbps baud rate.

See Also:
Constant Field Values
Constructor Detail

SCIP11

public SCIP11(int port)
       throws java.io.IOException
Throws:
java.io.IOException
Method Detail

enable

public void enable()
Enable the laser. Note, an error is generated if you try to enable the laser if it is already enabled, or disable it if it's already disabled. It logs an "Error" warning to stderr, but does not throw an exception.


disable

public void disable()
Disable the laser. Note, an error is generated if you try to enable the laser if it is already enabled, or disable it if it's already disabled. It logs an "Error" warning to stderr, but does not throw an exception.


setBaud

public void setBaud(java.lang.String baud)
Set the baud rate using one of the BAUD_n constants. This function has no effect when using USB for communication.


getVendorInfo

public java.lang.String getVendorInfo()
Returns static vendor information from laser.


getProductInfo

public java.lang.String getProductInfo()
Returns static product information from laser.


getFirmwareVersion

public java.lang.String getFirmwareVersion()
Returns static firmware version from laser.


getProtocolVersion

public java.lang.String getProtocolVersion()
Returns static protocol version from laser.


getSensorSerialNumber

public java.lang.String getSensorSerialNumber()
Returns static sensor serial number from laser.


getSensorStatus

public java.lang.String getSensorStatus()
Returns undocumented static status field laser.


getRange

public int getRange(double angle)
Returns the range detected at the given angle, measured in degrees, and within the angular range of the sensor, -120 degrees to +120 degrees. Zero degrees is forward, -120 degrees is back and to the right, +120 degrees is back and to the left. According to the Hokuyo data sheet, the scan time is 100ms / scan. That means, we can cache data for up to that long. If you want to collect a whole set of data at a time, call doDistanceCommand() directly.


setScanTime

public void setScanTime(long l)
This method specifies the number of milliseconds per scan of the laser. This defaults to 100ms, as specified by the Hokuyo data sheet, however you may have a faster laser (or a slower one), so you can adjust the scan time here.


getScanTime

public long getScanTime()

setAngleOffset

public void setAngleOffset(double d)
The Hokuyo laser ranger considers forward to be zero degrees, however, some systems, such as the sensor array on the Pioneer robots, consider zero degrees to be in other locations (for the Pioneers, that would be on the right). This method allows you to "set" the zero direction. The argument to this method tells the API what angle from forward you want to consider the zero angle. So to match the Pioneer, you would pass in 90. Default is zero.


getAngleOffset

public double getAngleOffset()
Retreive the angle offset.


doVersionCommand

public java.util.HashMap<java.lang.String,java.lang.String> doVersionCommand()

Internal method to return a map of version info from the laser. Most users should access this data via getVendorInfo(), getProductInfo(), getFirmwareVersion(), getProtocolVersion(), and getSensorSerialNumber().

 The keys are: 
 KEY_VENDOR   = "Vender Information" // sic 
 KEY_PRODUCT  = "Product Information" 
 KEY_FIRMWARE = "Firmware Version" 
 KEY_PROTOCOL = "Protocol Version" 
 KEY_SERIAL   = "Sensor Serial Number"
 KEY_STATUS   = "Undocumented Status Field"

 The values are informational strings.
 


doLaserCommand

public void doLaserCommand(boolean enable)
Internal method to enable or disable the laser. Most users should use enable() or disable() methods. Note, an error is generated if you try to enable the laser if it is already enabled, or disable it if it's already disabled. It logs an "Error" warning to stderr, but does not throw an exception.


doSettingsCommand

public void doSettingsCommand(java.lang.String baud)
Internal method to configures the baud rate of the device. The argument is one of 019200, 057600, 115200, 250000, 500000, 750000. This method has no effect when communicating via USB. Most users should use the method setBaud() for this function.


doDistanceCommand

public java.util.ArrayList<java.lang.Integer> doDistanceCommand(int start,
                                                                int end,
                                                                int cluster)

Internal method to request sensor data from the laser. The getRange() method provides simpler access to range data.

Starting and ending point range from 0..768. Cluster count is from 0..99.

Sensor measures range of 4095mm with 1mm resolution.

Starting and ending point refer to steps in the field of angular detection. This field is a range of 240 degrees, with a dead zone of 120 degrees at the rear. Step 0 is at -135 degrees from front (right), Step 384 is at 0 degrees (facing front), and Step 768 is at +135 degrees (left). Step 0 and 768 are both in the deadzone. Measurable range is from Step 44 to Step 725. Each step has a resolution of 360deg/1024 = 0.3515625 deg.

I assume that the "cluster" parameter, which refers to the number of neighboring points that are grouped as a cluster would reduce the amount of data returned.

For example, if start is at "44" and end is at "725" and cluster is "01", then you would expect some 680 data points.

If cluster were "20", then you might expect only 34 data points, each of which is perhaps the average of a 7 degree arc?

Sensors will return values between 20mm and 4094mm. Anything less than 20mm will result in an error code at that data point.

Error codes for data points are (don't ask me what they mean):

  0    "Possibility of detected object is at 22m"
  1-5  "Reflected light has low intensity"
  6    "Possibility of detected object is at 5.7m"
  7    "Distance data on the preceding and succeeding steps have errors"
  8    "Others"
  9    "The same step had error in the last two scan"
 10-15 "Others"
 16    "Possibility of detected object is in the range 4096mm"
 17    "Others"
 18    "Unspecified"
 19    "Non-Measurable Distance"
 


getLastError

public byte getLastError()
Return the last error code byte generated by the laser and clear the code.


main

public static void main(java.lang.String[] args)
                 throws java.lang.Exception
Only useful for testing.

Throws:
java.lang.Exception

getErrorFromData

public static final java.lang.String getErrorFromData(int c)
If a data point less than 20 is returned, it corresponds to an error code as documented. This method returns the string associated with that error code.