scanse / sweep-sdk Goto Github PK
View Code? Open in Web Editor NEWSweep SDK
License: MIT License
Sweep SDK
License: MIT License
At the moment get_scan
waits for the sync bit then records responses until the next sync bit. This makes sure we gather and report only full 360 degree scans:
Lines 177 to 231 in 853f113
But it's also wasteful since we're throwing away the data before the first sync bit, limiting our throughput.
To keep the low-level library simple I don't want to go the route of a worker thread, accumulating behind the scenes. Instead, we should be able to check for the angle we start recording at and stop recording as soon as we reach it again.
We don't guarantee for the first sample to start at angle 0 degree after all. If the user needs this, she can accumulate herself.
We just discovered a bug in the current firmware (v1.3
) that occurs when a device is reset while stationary (motor speed setting 0Hz
)
Example:
RR
commandgetScan()
hangsAny other device interactions work as expected, yielding normal responses. Additionally, the data stream actually initiates just fine, and the individual scan packets are received without error.
getScan()
hangs because accumulate_scans()
never encounters a sync reading. Instead, all the incoming data packets contain an azimuth value of 0°. ie: each 7 byte scan packet looks like [0,0,0,x,x,x,x]
where x is a non-zero value.
Because the azimuth values do not increase, a sync reading is never encountered and a new scan is never produced. But neither is an error. The reason an error is never produced is because all the incoming scan packets pass their checksum. Its possible libsweep would break from this after receiving more than SWEEP_MAX_SAMPLES
data packet responses. But my applications were timing out before that anyhow.
This is a firmware bug. We are working on a fix which will be released ASAP.
However, we may still want to implement a check in accumulate_scans()
for successive packets that have the exact same azimuth, and throw an error.
The serial sub-system provides it's own error types to be fully encapsulated and to not go near circular dependencies. The translation to sweep's error types happens manually all over the place in sweep.c (e.g.
Lines 69 to 73 in f7fbfbd
Refactor this translation into a helper function.
from sweep datasheet:
Angle measurement Sweep uses an optical encoder to measure the angle of the rotating sensor head. The angle that is recorded for a range data point is the angle the sensor is at when the measurement is completed.The beginning of the scan, and zero degrees is located where the status LED projects out of the base of the sensor
could we get provided with a formula to convert from the encoder "counter-ticks" to degrees?
or at least the encoder model, so that we can see the manufacturer information (ticks per degree or so).
kind regards!
I've discovered an issue but not entirely sure what is causing it.
Code to reproduce:
sweep::sweep device{argv[1]};
device.set_sample_rate(500); // errors here, description below
The expected behavior should be as follows:
sweep_device_stop_scanning()
is called internally... which performs the following:
DX\n
command to stop any potential active data streamDX00P\n
) to come inDX\n
commandDX00P\n
) that should be responding to the 2nd commandsweep_device_set_sample_rate()
sends LR01\n
command to set the sample rate and then reads LR response (LR01\n00P\n
)The issue is a checksum error when attempting to read the LR response. Instead of LR01\n00P\n
, the response that is read from the serial buffer is DX00P\nLR0
. It appears that a DX - Stop Scanning
response (DX00P\n
) is being left in the serial buffer, and is therefore being interpreted as the beginning of the LR response.
Using a protocol analyzer I have confirmed that the timing of the commands and responses, as well as their byte content, is as expected:
Here is a zoomed out timeline:
From this I can tell that the communication over the wire is fine. No extra "DX" response (DX00P\n
) is coming in, and no response is delayed. The bytes from the "LR" response (LR01\n00P\n
) are valid as well.
It seems then that somehow the buffer isn't being flushed properly. @daniel-j-h Any idea what could be causing this?
Edit: it appears the flush is NOT the issue. See below.
At the moment we accumulate a full 360 degree scan and return this scan to the user.
Many use-cases need high-resolution synchronization which is currently not possible on a per-sample basis to do for the user (could be estimated using motor speed and timestamp on a scan, though).
For usability reasons it would be great to have a timestamp per angle, distance sample.
Tasks:
Something appears to be persisting after using the sweepjs bindings. Attempting to use an alternate method of interfacing with the device (ie: the sweep-visualizer) after running the sweepjs example requires that the device be reset. This is not the case with the sweeppy python bindings. My best guess is that the python bindings properly cleanup and and destroy the device on exit, while perhaps the sweepjs bindings do not?
From #70 (comment), quoting @dcyoung:
Correct, the SDK will no longer work with firmware v 1.0 which did not include the "MZ" command, among other things.
We should provide a way for the user to check if the sweep-sdk is compatible with the hardware device.
Or at least note it down in the readme and tag releases (i.e. git tag `vx.y.z)) and then provide changelog'ish summaries.
I finally have some time and thought about tackeling the question of what should happen when an error occures in the worker thread (currently the thread will simply stop). But before I create a PR I wanted to discuss my ideas first:
First of all I think we need to distinguish between faults from which the thread should try to recover (e.g. crc errors) and error from which recovery is infeasible (device got disconnected).
In case of recoverable errors I'd just try to find the next valid packet and give up after a few iterations.
In case of non-recoverable errors, the loop would exit and the error would be propagated through the queue to sweep_device_get_scan
.
The question is what the user or the library is supposed to to to bring the system back into a defined state (we could for example automatically call sweep_device_stop_scanning
or require this from the user)
For the scan respone packet's checksum the spec. says:
adding the six bytes of data
isn't this endianness-dependant for the two-byte uint16_t
types? That is, the current way of sliding over the chunk of memory is little-endian specific. Should this at least be documented in the spec?
We've discussed the need to introduce a worker thread for IO. However, the implementation must consider cross-platform compatibility. The debate is whether to...
Shift the libsweep
library's implementation to C++, while still maintaining the C interface. The C++ implementation would allow for all threading to handled by C++11 standard thread library, and avoid the need for thread abstraction. This would both consolidate the code. @daniel-j-h You mentioned that this requires us to link in libstdc++/libc++ which is a pain for abi stability and shipping portable binaries. Could you elaborate on those two points a bit? Isn't shipping platform specific binaries pretty standard?
Abstract the threading into a shared interface that is platform agnostic, and then provide platform specific implementations.
For option 2 (abstraction), we could do this in a similar fashion to serial.h
+ (serial_unix.c
or serial_win.c
). In this case, we'd have something like sweep_threading.h
+ (sweep_threading_unix.c
or sweep_threading_win.c
). This interface would define an abstracted thread, mutex, conditional var, and single producer single consumer queue. Then the methods from the serial
and sweep
files would make use of the threads and queues via this abstracted interface. The unix implementation could use pthreads. I'm still open to suggestions for the win implementation but it could use WINAPI. Using WINAPI would require the inclusion of <windows.h>. Any complications with the build process or bindings there? @daniel-j-h
What do we think about the pros/cons of both?
Given that the current style of sweepSDK is to avoid global state...
No global state: _s context objects (_s since POSIX reserves _t) hold state and have to be passed explicitly.
how should we store and reference the working queue? I spent a while today trying to implement a queue and a worker thread that conformed to the limitations of no global state and the Pimpl idiom, but I didn't get very far.... I'm still getting the hang of the Pimpl idom :/ @daniel-j-h if you've got a plan for how to accomplish this I'm happy to collaborate however I can.
At the moment we return angle, distance samples. Many use-cases need to convert from Polar to Cartesian coordinates anyway (see our examples).
It would be great to provide convenience helpers already in the C++, Python and Javascript bindings.
libsweep
should not expose this as it's strictly not needed. We don't want to clutter the low-level API.
*latest at this moment (20160510- just cloned and installed from git repository)
*working with sweeppy
Linux raspberrypi 4.4.50-v7+ #970
Raspberry pi 3
Traceback (most recent call last):
File "lidar360.py", line 196, in <module>
main()
File "lidar360.py", line 154, in main
sweep.start_scanning()
File "build/bdist.linux-armv7l/egg/sweeppy/__init__.py", line 136, in start_scanning
RuntimeError: unable to start scanning. could not verify motor speed.
In the viewer
example, any sensor reading with a distance > 5m are drawn with a distance of 5m.
see here
This can misrepresent the data that is being reported. For example, using the viewer from a sensor placed in our relatively small office space shows large arcs of inaccurate readings where the distance is being clipped.
Zooming in to a small 5x5 meter area is fine. And not drawing values beyond a certain distance threshold seems like an understandable design choice. But we should avoid augmenting the distance value as it looks like the sensor is not reporting accurate distances. A new user might think their sensor is malfunctioning.
When calling sweep_serial_device_read
and potentially elsewhere, sizeof() is used to specify a number of bytes.
Ex:
Line 188 in f2cb07e
Something like sizeof(sweep_protocol_response_scan_packet_s)
ends up being compiler dependent, for example its returning 7 bytes on linux and 8 bytes on windows (via gcc on MinGW).
I'm confused why this is happening, as it looks like the __attribute__((packed))
is being applied to all those struct definitions via SWEEP_PACKED
. However, the input (len
) to sweep_serial_device_read
really shouldn't depend on the size of sweep_protocol_response_scan_packet_s
. It should be based on the communication protocol spec and we should probably define this explicitly.
Perhaps we should create a mapping of receipt types to expected byte length and pull len
from there. This could be easily achieved by adding a len
field to each struct that outlines a command or response.
Edit: I thought it might be possible that MinGW compiler (gcc v5.3) was not passing this condition...
Line 11 in f2cb07e
but I've verified that it is passing the condition and the definitions are being set. I'm very confused then why the structs are producing different sizeof()
Running the examples ./example-c
, ./example-c++
or ./example-viewer
works the first time, but unless the sensor is reset between each run, the example will error on subsequent attempts in an alternating pattern. Ie: the 2nd attempt will fail, but the 3rd will succeed, 4th will fail, etc
In the case of ./example-c
the stated error is:
Error: unable to receive motor speed command response
In the case of ./example-c++
the stated error is:
Error: unable to receive stop scanning command response
And in the case of ./example-viewer
the stated error is:
Error: unable to receive start scanning command response
Has this always been the behavior or is it a new issue? I don't believe any changes were made to the protocol for DS
or DX
receipts. I haven't started tracking down the origin of the issue yet, but I'm assuming the device is not being shutdown properly. Whether its a logical error in the example itself, or an error with libsweep
is unclear.
Edit: Looking at the example code, I don't see where we send a DX
stop command to the sensor. However, after the example runs the device does stop transmitting serial data (judging from the TX led on the USB Serial adapter which stops blinking). It was my understanding that the device would continue to transmit data regardless of the state of the host port.... so somehow the device is getting that stop command. Is it hidden somewhere I might have overlooked?
If the example does trigger the host to send a DX
stop data command before or during the process of shutting down, are the still incoming Data Block
receipts handled properly? Recall that after sending a DX
command, the host should still expect to receive Data Block
receipts until the DX
receipt is received, which indicates no further Data Block
receipts are coming. Is it possible that the host sends the DX
and then immediately shuts down? This might be leaving incoming bytes in the serial buffer that are misinterpreted at the beginning of the example's next execution... producing the observed alternating errors.
Build against the dummy libsweep. Needs sfml2 for viewer.
Add to https://github.com/scanse/sweep-sdk/blob/master/.travis.yml.
(We already test sweeppy and sweepjs bindings there)
I started documenting libsweep
here. Needs some serious polishing.
Other sub-projects are sparse in documentation, too.
This might be specific to my particular needs but I'd find it more intuitive and useful if things like the examples and docs would be put into a separate folder under the root directory, keeping the library directories clean:
-sweep-sdk
|-libsweep
| |-include
| \-src
|
|-sweepjs
|-sweeppy
|-docs
| \-serial_protocol_spec.md
|
|-examples
| |-c
| |-cpp
| |-js
| \-python
|
\-CMakeLists.txt <-- master CMakeFile
Also, I mentioned this in a PR but I'd also prefer it, if the examples could be compiled without having to install the liibsweep library first.
E.g. on windows it is not clear cut, where such a library should be installed and in partucular if one just wants to have a quick look, I think it is preferable not to require any changes to the system. Pretty much the same might hold true for many embedded systems for which you need to use a crosscompiler.
We're currently using a Makefile
+ config.mk
for the build system. Now with the implementation switching to C++11 and @dcyoung polishing up the Windows branch we should re-visit this decision.
The examples are using CMake, too, and we provide a FindSweep.cmake
CMake module already.
Here is how users can then include libsweep
into their CMake based build system.
Related issue: install FindSweep.cmake on the user's system.
Should probably land before merging the Windows support branch to eliminate the need for Visual Studio specific project files, if we decide on going this route.
Extra requirements for a CMake based build system:
libsweep.so
+sweep/sweep.h
+sweep/sweep.hpp
We really should have some sort of sweep-ctl
binary to get set and reset the device state.
With an interface similar to
$ sweep-ctl /dev/ttyUSB0 get motor_speed
3
$ sweep-ctl /dev/ttyUSB0 set motor_speed 5
5
$ sweep-ctl /dev/ttyUSB0 set motor_speed
3
Otherwise users have to modify the examples and build their own binaries for these kind of interactions.
Should get installed in combination with a man page (generated by pandoc).
Motor Speed and Sample Rate handling are missing from the current selected features.
Scanse will start shipping devices shortly. The latest firmware that will come installed on the devices is using an updated communication protocol. The updated protocol is outlined in the docs on the motor-ready branch.
The relevant additions for this issue are...
Data Start - DS
will NOT trigger data acquisition unless the motor is spinning ( > 0Hz) and the speed has stabilized.
DS
command with a normal header ('DS00P\n'
... ie: status bytes == '00'
) and data acquisition will commence.DS
command with a modified header and data acquisition will NOT commence. This modified header will use the status bytes to indicate the type of failure. For example 'DS12S\n'
(status bytes == '12'
) indicates that the motor speed has not yet stabilized, while 'DS13T\n'
(status bytes == '13'
) indicates that the motor is stationary/0Hz. In either case the data acquisition will not commence.Adjust Motor Speed - MS
will not trigger an adjustment if the motor speed has not yet stabilized. Similar to above, the response message will use status bytes to indicate the failure.
'00'
indicate normal processing (ie: not issue)'11'
indicate the original command was sent with an invalid parameter'12'
indicate that the motor speed has not yet stabilizedWe need a way to communicate these failures to the user without exiting or destroying the sweep. At the very least, the high level functions in sweep.cc need to be able to handle these conditions. I'm wondering about the following options. @daniel-j-h I am very open to suggestions, but need to get this going ASAP.
sweep_device_start_scanning()
could return false or an int capable of representing success + multiple failure conditions).Ie:
if(start scanning produces error){
check the error type
if (error type indicates the motor is stationary) {
adjust the motor speed
wait for motor speed to stabilize
try to start scanning again
}
}
Internal functions could opt to handle some of this logic. For example: sweep_device_set_motor_speed()
might encounter an error because the motor speed is still adjusting from a previous command. The function could witness the error, wait for the motor speed to stabilize and then try again. All of this could happen without requiring any user code. However, some conditions like invalid parameters or a stationary motor will require user handling.
While using the C code SDK, My code uses the following libsweep.lib functions in this specific order:
sweep_device_construct(port, 115200, &error)
sweep_device_set_motor_speed(sweep, hz, &error)
sweep_device_set_sample_rate(sweep, sampleRate, &error)
sweep_device_get_motor_ready(sweep, &error)
int32_t speed = sweep_device_get_motor_speed(sweep, &error);
int32_t rate = sweep_device_get_sample_rate(sweep, &error);
sweep_device_start_scanning(sweep, &error);
check(error);
scan = sweep_device_get_scan(sweep, &error);
This is a similar setup to what is seen in example.c.
There are two issues that I run into.
The first, when I use the settings of hz = 5 and sampleRate =1000, the scanse gets locked up within sweep_device_get_scan(). Following the callstack, I noticed that within scanse.cc -> class ScanQueue is where the lock up occurs while "the_queue" is empty. Is there a way to reset the scanse after a certain amount of time of it being locked up? It seem that the scanse will wait indefinitely, and at some point I would like the scanse to reset.
The second issue occurs in the same place, however, when I use the setting hz = 5 and sampleRate = 500, the scans works as expected until a rotational acceleration is applied to the sweep. The motor monetarily stops, and seems to reset. However, the code gets locked up in the same place as described above. There are also cases where the sweep is running normally, and without any external disturbance, the code gets locked up in the same place. I would like for it to continue scanning similar to what the visualizer does. When I perform the same rotational acceleration to the sweep while it is running in the visualizer, the motor resets and the visualizer continues to receive data after a momentary pause. Any advice what to do in order to achieve that using the SDK?
I am using the version 1.3 of the sweep firmware, and the lastest version of libsweep.lib as of 5/8.
I am running Windows 7 x64
Similar to the ticket about Python Wheels we should build and distribute pre-built binaries.
This would allow users to do
npm install sweep
and get everything pre-built, packaged and set up for their platform. For now users have to compile, link, and install libsweep.so
themselves before being able to install and use the Node bindings.
The common way to do this is to hook into the Node binding build system via node-re-gyp
and store binaries on S3 or Github releases. Here's documentation and a skeleton repository:
Note: this is on the wish-list but certainly not prioritized right now. Feel free to jump in and help out here.
Similar to the .travis.yml here we want CI integration.
Compiling libsweep
is be a good start, properly testing all sub-projects would be even better.
Tasks:
libsweep.so
libsweep.so
(make dummy
) and test projects againstCurrently I only tested libsweep
, SweepPy
and SweepJs
on my Linux Ubuntu machine.
For platform specifics we can dispatch in config.mk. I assume we have to change some specifics such as the installation paths, maybe some cflags/ldflags. The _unix
implementations are POSIX-conforming and should Just Work (tm).
i'm running libsweep/examples/example.cc
to get some calibration data and often find that after a quick stop/start i get Error: unable to receive stop scanning command response
or Error: unable to receive start scanning command response
3 or 4 times before getting connectivity again. Unplugging the device and replugging it back in always seems to clear the problem (i.e. I don't get this error the first time I run the example).
Is this expected? Is there additionally debugging I can provide?
The protocol description file e.g. says
Azimuth: Angle that ranging was recorded at (in degrees). Azimuth is a float value, transmitted as a 16 bit int. This needs to be converted from 16bit int to float. Use instructions in the Appendix. Note: the lower order byte is received first, higher order byte is received second.
I'm not sure if this is just confusing or even wrong, but in any case wouldn't it be simpler to say something like:
Azimuth: Angle that ranging was recorded at (in degrees). Azimuth is transmitted as a 16 bit fixed point value with a scaling factor of 16 (4bit after radix) in little endian format (first byte is low order).
Also the conversion from wire format to storage format seems to be unnecessarily complicated. Wouldn't a simple
static_cast<int>(angle/16.0 * 1000.0)
do the trick?
Or have I overlooked something?
@daniel-j-h I noticed that you still have MA and MX in the protocol. Instead of having a separate command for start, stop, and adjusting speed, we decided to just use MS and have 00 be motor stop and anything positive start the motor.
I'll work on getting the protocol spec in this repo soon.
There should be a nice looking landing page with notes on what this project is about, use-cases and short explanations for the bindings.
Currently the sweeppy setup.py
file only defines MAJOR.MINOR version scheme (eg: version='1.1'
). Can this be changed to include full semantic version MAJOR.MINOR.PATCH? This would allow us to synchronize the sweepjs, sweeppy and libsweep versions.
I was following along with the quickstart guide, as I'm sure most users will do:
https://github.com/scanse/sweep-sdk/blob/a33032a5626d43e1d72b3457dda8f6ebb6bc86ca/libsweep/examples/README.md
The cmake ..
command in the following docs will error.
mkdir build
cmake ..
cmake --build .
I believe it should be changed to...
mkdir build
cd build
cmake ..
cmake --build .
This is probably more a firmware issue, so please tell me if I should post this somewhere else.
I was wondering, why it isn't possible to scan when motor speed is zero? Together with a command to turn the head forward it would be a nice feature, if the lidar could also be used as a range finder.
Also, I don't know if this is related, but I think it would be preferable if the head wouldn't automatically start turning after a powercycle.
We should provide means for the user to configure the allocator. The user should be able to plug in e.g. a efficient stack-allocator if she wants to. This needs to go hand in hand with the C++ abstractions.
When we connect the sweep to our usb port it opens on /dev/ttyUSB0. The visualizer program works flawless with the sweep. So we took the example.cc file and succesfully compiled the project. But when we run the example with "./Lidar /dev/ttyUSB0" it prints "Constructing sweep device..." and then just hangs. It doesn't throw any error, but it's not proceeding. Looking at your code I would expect it to output its motor speed, but it doesn't do that. So it doesn't get past following line:
https://github.com/scanse/sweep-sdk/blob/master/libsweep/examples/example.cc#L16
If we disconnect the sweep it throws the "Error: opening serial port failed", so we know "/dev/ttyUSB0" is the right port.
Thanks in advance.
At the moment I only started to play with the point-cloud 3d map idea, but we don't have much examples that are more beautiful than "just" printing some numbers on the screen.
I understand having library + bindings is a great first step, but users want fancy examples and use-cases.
Currently, we only use major and minor version scheme. Any reason we shouldn't add support for full semantic version scheme... ie: Major.Minor.Patch ?
Sending a DX
command (host->sensor) to a streaming sensor stops data acquisition. However, this doesn't happen instantaneously. Once the DX
command is sent out, the host will still receive a few Data Block
receipts before seeing the DX
receipt.
Currently the sweep_device_stop_scanning
uses the following technique:
DX
command (host -> sensor)Data Block
receipts and the DX
receipt to arrive (sensor -> host).DX
command (host -> sensor)DX
receipt (sensor -> host) that returns as a response to step 4This was really a temporary workaround and should be replaced by an actual check for the DX
receipt among the incoming Data Block
receipts. The initial reaction might be to assume we cannot reliably check for a DX
receipt among incoming Data Block
receipts because the bytes of a Data Block
are variable. The fear is that they could theoretically take the appearance of a DX
receipt. However, we can still reliably discern the two because:
Data Block
bytes 1-6 can take any form, byte 0 (sync/error byte) is limited to very specific error codes and is therefore controllable. We can guarantee that byte 0 will never look like the first byte of a DX
receipt.Data Block
receipts before sending a DX
receipt. That is to say that a DX
receipt will never come mid-Data Block
.Data Block
receipts are transmitted after the DX
receipt is transmitted.Obviously we can't protect against data corruption with 100% reliability, but we can certainly protect against valid Data Block
receipts being misinterpreted as a DX
receipt.
In sweep_device_stop_scanning
, we should do something along the lines of:
DX
command (host -> sensor)Data Block
receipt or a DX
receipt.Data Block
receipt, handle it... (as we would during scanning, or simply trash it). In the case of a DX
receipt, we proceed as if we picked up from step 5 above.At the moment there is libsweep
the low-level ABI and API stable C library. There is a convenient C++11 header on top of that, Python2/3 and NodeJS FFI bindings.
Which of those do we actually want to support? The beauty of having a ABI and API compatible library is that FFI bindings are very lean and elegant to write. The downside is, someone still has to build and maintain not only the abstractions needed for the bindings, but also e.g. the build system, how to package and ship bindings etc.
If we decided on languages to support, we need a plan for packing library + bindings up to make the user's life as easy as possible.
Several applications are going to require communicating with sweep over IP. What layer of the SDK would be most appropriate to introduce this functionality?
libsweep 1.1.1
Arch Linux
The make file for the c code installs the libraries into '/usr/local/lib'. The python wrapper 'sweppy' uses those libraries, but looks only in '/usr/lib'.
I fixed it by running
sudo ln -s /usr/local/lib/libsweep.so /usr/lib/libsweep.so
sudo ln -s /usr/local/lib/libsweep.so.1 /usr/lib/libsweep.so.1
Would be nice if this could work out of the box. Or did I just understand something wrong?
I can't help you much there. If we want this, we have to adapt the build system (config.mk, Makefile for libsweep
, maybe gyp for SweepJs). Then provide implementations along the _unix
ones conforming to our interfaces.
At the moment we provide a basic installation target in libsweep
's Makefile. It would be great to improve this by also installing a pkg-config / our FindSweep.cmake
file.
Until then users have to manually -lsweep
which works fine, too.
Splitting off from @kenzierocks' initial Python packaging pull request #51 (please read for context).
At the moment we require users to compile, link, and install libsweep.so
before they can install the Python bindings. It would be great if we no longer require these steps. Instead users should only have to
pip install sweep
and get everything pre-built, packaged and set up for their platform.
This requires us to build Python Wheels for Linux, macOS and Windows (if we want to support pre-built binaries for all of them). Which can be done but is a bit cumbersome.
I can think of a solution where we (at least for Linux) spawn up a Docker container and let Travis build and publish binaries for master
automatically.
Please read the initial Python packaging pull request summarizes what needs to be done: #51.
Note: this is on the wish-list but certainly not prioritized right now. Feel free to jump in and help out here.
It looks like the sample rate commit broke the c++ example by placing the calls to get_motor_speed and get_sample_rate AFTER start_scanning
...
sweep-sdk/libsweep/examples/example.cc
Line 11 in 4c12c07
This probably works with the dummy library because it sends back information regardless of whether or not its scanning. However, the actual sweep device cannot receive or respond to commands other than DX\n
while it is scanning. The calls to get_motor_speed
and get_sample_rate
need to be placed before start_scanning
.
Additionally, in those functions we should probably check if the device is scanning and simply error or report it somehow before trying to message a device... which will only cause more errors. We can do this easily, as we already set a is_scanning
bool in the sweep_device
struct
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.