Skip to content

Commit

Permalink
Updated Protocol for firmware v1.1, and accumulate scans in backgroun…
Browse files Browse the repository at this point in the history
…d thread
  • Loading branch information
dcyoung committed Apr 21, 2017
1 parent c7cafac commit fab0612
Show file tree
Hide file tree
Showing 19 changed files with 783 additions and 168 deletions.
69 changes: 64 additions & 5 deletions libsweep/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,30 +185,54 @@ void sweep_device_start_scanning(sweep_device_s device, sweep_error_s* error)
```

Signals the `sweep_device_s` to start scanning.
If the motor is stationary (0Hz), will automatically set motor speed to default 5Hz.
Will block until the the motor speed is stable (uses `sweep_device_wait_until_motor_ready` internally).
Starts internal background thread to accumulate and queue up scans. Scans can then be retrieved using `sweep_device_get_scan`.
In case of error a `sweep_error_s` will be written into `error`.


```c++
void sweep_device_stop_scanning(sweep_device_s device, sweep_error_s* error)
```
Signals the `sweep_device_s` to stop scanning.
Blocks for ~35ms to allow time for the trailing data stream to collect and flush internally, before sending a second stop command and validate the response.
In case of error a `sweep_error_s` will be written into `error`.
```c++
void sweep_device_wait_until_motor_ready(sweep_device_s device, sweep_error_s* error)
```

Blocks until the `sweep_device_s` is ready, or the method times out (after 8 seconds). A device is ready when the motor speed has stabilized to the current setting, and the calibration routine is complete. The worst case wait time is around 6 seconds, which includes both motor stabilization and calibration. For visual reference, the blue LED on the device will blink unil the device is ready. This method is useful when the device is powered on, or when adjusting motor speed. If the device is NOT ready, it will respond to certain commands (`DS` or `MS`) with a status code indicating a failure to execute the command. Therefore, it is best practice to avoid this entirely by calling `sweep_device_wait_until_motor_ready` before calling a command that requires a ready device.
In case of error a `sweep_error_s` will be written into `error`.

```c++
bool sweep_device_get_motor_ready(sweep_device_s device, sweep_error_s* error)
```
Returns `true` if the device is ready. A device is ready if the motor speed has stabilized to the current setting, and the calibration routine is complete.
This method can be used to create a non-blocking alternative to `sweep_device_wait_until_motor_ready` in user programs.
For visual reference, the blue LED on the device will blink during calibration/speed stabilization, and stop blinking when the device is ready.
In case of error a `sweep_error_s` will be written into `error`.
```c++
int32_t sweep_device_get_motor_speed(sweep_device_s device, sweep_error_s* error)
```

Returns the `sweep_device_s`'s motor speed in Hz.
Returns the `sweep_device_s`'s motor speed setting in Hz.
If the motor speed is currently changing, the returned motor speed is the target speed at which the device will stabilize.
In case of error a `sweep_error_s` will be written into `error`.

```c++
void sweep_device_set_motor_speed(sweep_device_s device, int32_t hz, sweep_error_s* error)
```
Sets the `sweep_device_s`'s motor speed in Hz.
The device supports speeds of 1 Hz to 10 Hz.
Blocks until prior motor speed has stabilized.
The device supports speeds of 0 Hz to 10 Hz, but be careful that the device is not set at 0Hz before calling `sweep_device_start_scanning`.
In case of error a `sweep_error_s` will be written into `error`.
```c++
int32_t sweep_device_get_sample_rate(sweep_device_s device, sweep_error_s* error)
```
Expand All @@ -221,8 +245,8 @@ void sweep_device_set_sample_rate(sweep_device_s device, int32_t hz, sweep_error
```
Sets the `sweep_device_s`'s sample rate in Hz.
The device supports sample rates of 500 Hz, 750 Hz and 1000 Hz.
The device guarantees for those sample rates but they can be slightly higher by a maximum of roughly 50-100 Hz.
The device supports setting sample rate to the following values: 500 Hz, 750 Hz and 1000 Hz.
These sample rates are not exact. They are general ballpark values. The actual sample rate may differ slightly.
In case of error a `sweep_error_s` will be written into `error`.
```c++
Expand All @@ -245,9 +269,11 @@ Opaque type representing a single full 360 degree scan from a `sweep_device_s`.
sweep_scan_s sweep_device_get_scan(sweep_device_s device, sweep_error_s* error)
```
Blocks waiting for the `sweep_device_s` to accumulate a full 360 degree scan into `sweep_scan_s`.
Returns the ordered readings (1st to last) from a single scan.
Retrieves the oldest scan from a queue of scans accumulated in a background thread. Blocks until a scan is available. To be used after calling `sweep_device_start_scanning`.
In case of error a `sweep_error_s` will be written into `error`.
```c++
void sweep_scan_destruct(sweep_scan_s scan)
```
Expand Down Expand Up @@ -278,7 +304,40 @@ int32_t sweep_scan_get_signal_strength(sweep_scan_s scan, int32_t sample)

Returns the signal strength (0 low -- 255 high) for the `sample`th sample in the `sweep_scan_s`.

<!--
#### Alternative direct functions
Many of the SDK methods block for various reasons, such as waiting for a data stream to terminate, waiting for the device to finish calibrating, or waiting for the motor speed to stabilize. This can be an issue for low-level applications where blocking isn't ideal. The following methods (mostly non-blocking) are provided as a workaround. Care must be taken when using these methods as they can error on valid failures if the state of the device is not checked before hand.
```c++
void sweep_device_attempt_start_scanning(sweep_device_s device, sweep_error_s* error)
```
Non-blocking alternative to `sweep_device_start_scanning`.
Signals the `sweep_device_s` to start scanning.
Will only succeed if the motor speed is \>0Hz and stable.
User is responsible for checking these conditions before calling. User can check that motor speed has stabilized using `sweep_device_get_motor_ready` and that motor speed is \> 0Hz using `sweep_device_get_speed`.
Will NOT start an internal background thread. User is responsible for keeping up with incoming scans by calling `sweep_device_get_scan_direct`.
In case of error a `sweep_error_s` will be written into `error`. This method will error on legitimate failures (ex: the motor speed is stationary or has not yet stabilized).
```c++
sweep_scan_s sweep_device_get_scan_direct(sweep_device_s device, sweep_error_s* error)
```
Returns the ordered readings from the 2nd reading of the current scan through the 1st reading of the subsequent scan.
Blocks waiting for the `sweep_device_s` to accumulate a full 360 degree scan into `sweep_scan_s`. To be used after calling `sweep_device_attempt_start_scanning`, NOT after `sweep_device_start_scanning`.
In case of error a `sweep_error_s` will be written into `error`.
```c++
void sweep_device_attempt_set_motor_speed(sweep_device_s device, int32_t hz, sweep_error_s* error)
```
Non-blocking alternative to `sweep_device_set_motor_speed`.
Sets the `sweep_device_s`'s motor speed in Hz.
Will only succeed if the device is ready. A device is only ready if the motor speed has stabilized to the current setting and the calibration routine is complete.
Proper use involves checking that the motor speed has stabilized (using `sweep_device_get_motor_ready`) before attempting to adjust the motor speed to a new value.
In case of error a `sweep_error_s` will be written into `error`. This method will error on legitimate failures (ex: the motor speed has not yet stabilized).
-->
### License

Copyright © 2016 Daniel J. Hofmann
Expand Down
124 changes: 101 additions & 23 deletions libsweep/doc/serial_protocol_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Command Symbol (2 bytes) | Parameter (2 bytes) | Line Feed(LF) | Status (2 bytes
**LR** - Adjust LiDAR Sample Rate
**LI** - LiDAR Info
**MI** - Motor Information
**MZ** - Motor Ready
**IV** - Version Info
**ID** - Device Info
**RR** - Reset Device
Expand All @@ -97,6 +98,14 @@ Header response
D | S | Status | SUM | LF
| --- | --- | ---| --- | --- |

DS command is not guaranteed to succeed. There are a few conditions where it will fail. In the event of a failure, the two status bytes are used to communicate the failure.

Status Code (2 byte ASCII code):
- `'00'`: Successfully processed command. Data acquisition effectively initiated.
- `'12'`: Failed to process command. Motor speed has not yet stabilized. Data acquisition NOT initiated. Wait until motor speed has stabilized before trying again.
- `'13'`: Failed to process command. Motor is currently stationary (0Hz). Data acquisition NOT initiated. Adjust motor speed before trying again.

### (SENSOR -> HOST)
Data Block (7 bytes) - repeat indefinitely

sync/error (1byte) | Azimuth - degrees(float) (2bytes) | Distance - cm(int) (2bytes) | Signal Strength (1byte) | Checksum (1byte)
Expand Down Expand Up @@ -136,50 +145,73 @@ D | X | Status | SUM | LF

---
#### MS - Adjust Motor Speed
* Adjusts motor speed to integer value between 0Hz and 10Hz (Default Speed - 5Hz)
Adjusts motor speed setting to the specified code indicating a motor speed between 0Hz and 10Hz. This sets the target speed setting, but the motor will take time (~6 seconds) to adjust and stabilize to the new setting. The blue LED on the device will flash while the speed is stabilizing.

#### (HOST -> SENSOR)

M | S | Speed Parameter (2 bytes) | LF
M | S | Speed Code (2 bytes) | LF
| --- | --- | ---| --- |

Speed Parameter:
00 - 10 : 10 different speed levels according to Hz, increments of 1. ie: 01,02,..
00 = Motor stopped
(Note: ASCII encoded, ie: '05' = 0x3035)

#### (SENSOR -> HOST)

M | S | Speed(Hz) (2 bytes) | LF | Status | Sum | LF
M | S | Speed Code (2 bytes) | LF | Status | Sum | LF
| --- | --- | ---| --- | --- | ---| --- |

Speed Code (2 byte ASCII code):
- `'00'` = 0Hz
- `'01'` = 1Hz
- `'02'` = 2Hz
- `'03'` = 3Hz
- `'04'` = 4Hz
- `'05'` = 5Hz
- `'06'` = 6Hz
- `'07'` = 7Hz
- `'08'` = 8Hz
- `'09'` = 9Hz
- `'10'`= 10Hz

(Note: codes are ASCII encoded, ie: in '05' = 0x3035)

MS command is not guaranteed to succeed. There are a few conditions where it will fail. In the event of a failure, the two status bytes are used to communicate the failure.

Status Code (2 byte ASCII code):
- `'00'`: Successfully processed command. Motor speed setting effectively changed to new value.
- `'11'`: Failed to process command. The command was sent with an invalid parameter. Use a valid parameter when trying again.
- `'12'`: Failed to process command. Motor speed has not yet stabilized to the previous setting. Motor speed setting NOT changed to new value. Wait until motor speed has stabilized before trying to adjust it again.

---
#### LR - Adjust LiDAR Sample Rate
Default Sample Rate - 500-600Hz

#### (HOST -> SENSOR)

L | R | Speed Parameter (2 bytes) | LF
L | R | Sample Rate Code (2 bytes) | LF
| --- | --- | ---| --- |

Sample Rate Parameter Code:
01 = 500-600Hz
02 = 750-800Hz
03 = 1000-1050Hz
(Note: codes are ASCII encoded, ie: '02' = 0x3032)

#### (SENSOR -> HOST)

L | R | Sample Rate Code (2 bytes) | LF | Status | Sum | LF
| --- | --- | ---| --- | ---| --- | --- |

Sample Rate Code (2 byte ASCII code):
- `'01'` = 500-600Hz
- `'02'` = 750-800Hz
- `'03'` = 1000-1050Hz

(Note: codes are ASCII encoded, ie: '02' = 0x3032)

LR command is not guaranteed to succeed. There are a few conditions where it will fail. In the event of a failure, the two status bytes are used to communicate the failure.

Status Code (2 byte ASCII code):
- `'00'`: Successfully processed command. Sample Rate setting effectively changed to new value.
- `'11'`: Failed to process command. The command was sent with an invalid parameter. Use a valid parameter when trying again.

(Note: codes are ASCII encoded, ie: '11' = 0x3131)

---
#### LI - LiDAR Information
Returns current LiDAR Sample Rate Code:
01 = 500-600Hz
02 = 750-800Hz
03 = 1000-1050Hz
(Note: codes are ASCII encoded, ie: '02' = 0x3032)
Returns the current LiDAR Sample Rate Code.

#### (HOST -> SENSOR)

Expand All @@ -191,10 +223,16 @@ L | I | LF
L | I | Sample Rate Code (2 bytes) | LF |
| --- | --- | --- | --- |

Sample Rate Code (2 byte ASCII code):
- `'01'` = 500-600Hz
- `'02'` = 750-800Hz
- `'03'` = 1000-1050Hz

(Note: codes are ASCII encoded, ie: '02' = 0x3032)

---
#### MI - Motor Information
* Returns current motor speed code 00 - 10. (ie: rotation frequency in Hz)
(Note: motor speed code is ASCII encoded, ie: in '05' = 0x3035)
Returns current motor speed code representing the rotation frequency (in Hz) of the current target motor speed setting. This does not mean that the motor speed is stabilized yet.

#### (HOST -> SENSOR)

Expand All @@ -203,11 +241,50 @@ M | I | LF

#### (SENSOR -> HOST)

M | I | Speed(Hz) (2 bytes) | LF |
M | I | Speed Code (Hz) (2 bytes) | LF |
| --- | --- | ---| --- |

Speed Code (2 byte ASCII code):
- `'00'` = 0Hz
- `'01'` = 1Hz
- `'02'` = 2Hz
- `'03'` = 3Hz
- `'04'` = 4Hz
- `'05'` = 5Hz
- `'06'` = 6Hz
- `'07'` = 7Hz
- `'08'` = 8Hz
- `'09'` = 9Hz
- `'10'`= 10Hz

(Note: codes are ASCII encoded, ie: in '05' = 0x3035)

---
#### MZ - Motor Ready/Stabilized
Returns a ready code representing whether or not the motor speed has stabilized.

#### (HOST -> SENSOR)

M | Z | LF
| --- | --- | ---|

#### (SENSOR -> HOST)

M | Z | Ready Code (2 bytes) | LF |
| --- | --- | --- | --- |

Ready Code (2 byte ASCII code):

- `'00'` = motor speed has stabilized.
- `'01'` = motor speed has not yet stabilized.

(Note: codes are ASCII encoded, ie: '01' = 0x3031)

While adjusting motor speed, the sensor will NOT be able to accomplish certain actions such as `DS` or `MS`. After powering on the device or adjusting motor speed, the device will allow ~6 seconds for the motor speed to stabilize. The `MZ` command allows the user to repeatedly query the motor speed state until the return code indicates the motor speed has stabilized. After the motor speed is noted as stable, the user can safely send commands like `DS` or `MS`.

---
#### IV - Version Details
Returns details about the device's version information.
* Model
* Protocol Version
* Firmware Version
Expand All @@ -231,6 +308,7 @@ Example:
---

#### ID - Device Info
Returns details about the device's current state/settings.
* Bit Rate
* Laser State
* Mode
Expand All @@ -254,7 +332,7 @@ Example:
---

#### RR - Reset Device
* Reset Scanner
Resets the device. Green LED indicates the device is resetting and cannot receive commands. When the LED turns blue, the device has successfully reset.

#### (HOST -> SENSOR)

Expand Down
7 changes: 4 additions & 3 deletions libsweep/examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,24 @@ int main(int argc, char* argv[]) {
// All functions which can potentially fail write into an error object
sweep_error_s error = NULL;

// Create a Sweep device from default USB serial port; there is a second constructor for advanced usage
// Create a Sweep device from the specified USB serial port; there is a second constructor for advanced usage
sweep_device_s sweep = sweep_device_construct_simple(port, &error);
check(error);

// The Sweep's rotating speed in Hz
int32_t speed = sweep_device_get_motor_speed(sweep, &error);
check(error);

fprintf(stdout, "Motor Speed: %" PRId32 " Hz\n", speed);
fprintf(stdout, "Motor Speed Setting: %" PRId32 " Hz\n", speed);

// The Sweep's sample rate in Hz
int32_t rate = sweep_device_get_sample_rate(sweep, &error);
check(error);

fprintf(stdout, "Sample Rate: %" PRId32 " Hz\n", rate);
fprintf(stdout, "Sample Rate Setting: %" PRId32 " Hz\n", rate);

// Capture scans
fprintf(stdout, "Beginning data acquisition as soon as motor speed stabilizes...\n");
sweep_device_start_scanning(sweep, &error);
check(error);

Expand Down
8 changes: 5 additions & 3 deletions libsweep/examples/example.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ int main(int argc, char* argv[]) try {
return EXIT_FAILURE;
}

std::cout << "Constructing sweep device..." << std::endl;
sweep::sweep device{argv[1]};

std::cout << "Motor Speed: " << device.get_motor_speed() << " Hz" << std::endl;
std::cout << "Sample Rate: " << device.get_sample_rate() << " Hz" << std::endl;
std::cout << "Motor Speed Setting: " << device.get_motor_speed() << " Hz" << std::endl;
std::cout << "Sample Rate Setting: " << device.get_sample_rate() << " Hz" << std::endl;

std::cout << "Beginning data acquisition as soon as motor speed stabilizes..." << std::endl;
device.start_scanning();

for (auto n = 0; n < 10; ++n) {
const sweep::scan scan = device.get_scan();

std::cout << "Scan #" << n << ":" << std::endl;
for (const sweep::sample& sample : scan.samples) {
std::cout << "angle " << sample.angle << " distance " << sample.distance << " strength " << sample.signal_strength << "\n";
}
}

device.stop_scanning();

} catch (const sweep::device_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
1 change: 1 addition & 0 deletions libsweep/examples/net.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void publisher(const std::string& dev) try {
pub.bind("tcp://127.0.0.1:5555");

sweep::sweep device{dev.c_str()};
// Begins data acquisition as soon as motor speed stabilizes
device.start_scanning();

std::cout << "Publishing. Each dot is a full 360 degree scan." << std::endl;
Expand Down
1 change: 1 addition & 0 deletions libsweep/examples/viewer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ int main(int argc, char* argv[]) try {

// Now start scanning in the second thread, swapping in new points for every scan
sweep::sweep device{argv[1]};
// Begins data acquisition as soon as motor is ready
device.start_scanning();

sweep::scan scan;
Expand Down
Loading

0 comments on commit fab0612

Please sign in to comment.