Table of Contents
- Graphical Serial Terminal
- Open Port
- Sending a Simple Command
- Sending a Command w/ Parameters
- Special Case (Acquiring Data)
- Understanding the Checksum
The Sweep User Manual outlines the entire Sweep Communication Protocol, seen here.
**NOTE: For those who are completely new to serial communication, it might be useful to read up on some basic info. SparkFun has a handy article that introduces major concepts of serial communication. Check it out here.
Sweep uses a very simple form of data transmission called serial communication. Serial can drastically lower the hardware requirements of other platforms that wish to communicate with the Sweep sensor. However, for Sweep to communicate effectively with other platforms, both sides must abide by Sweep's Communication Protocol. The communication protocol defines a specific format for messages that will be sent to or from the Sweep device.
From here on out, we'll refer to the Sweep device as the "sensor", and the the non-sweep platform as the "host". The host could be a computer or micro-controller such as an arduino etc. In general the host will run some application logic that makes use of the sensor. The host requires some method of querying the sensor or commanding it to do certain things. For example, the host might need to adjust the sensor's motor speed, or parse incoming LiDAR readings from an actively scanning sensor.
In general, Sweep's communication protocol can be thought of as a set of "commands" and "receipts". Commands are the term given to messages sent from the host to the sensor (host->sensor), while receipts are the term given to messages sent from the sensor to the host (sensor -> host). We adopt this naming convention because we take the view of the host, and the majority of communication (other than an active data stream) plays out as follows: the host sends a command to the sensor and the sensor sends a receipt back in response.
Some commands are instructions (such as "MS - Adjust Motor Speed" or "DX - Stop Data Acquisition"), while others are effectively a request for information (such as "VI - Version Info" or "MI - Motor Info"). Therefore, certain types of receipts serve only to acknowledge that a command was received successfully. Other receipts provide information which the command was asking for.
This article is meant to help a complete beginner, in becoming familiar with the communication protocol. As soon as you understand how it works, developing applications that make use of the Sweep will be simple. All of this will become clear in the following sections.
Graphical Serial Terminal
There are many ways to communicate over serial with Sweep. However, this article is really about the protocol, so we'll be using a simple GUI tool. For those that want to follow along (it is recommended that you do), download one of the following:
These utilities simply provides a graphical user interface to select a Com Port, communication settings and view transmitted and received data. The article will proceed assuming the use of CuteCom, and a small section at the end will demonstrate how to achieve the same with RealTerm or PuTTy.
The first step is to make sure the host is using the same serial communication settings as the sensor. The settings can be found in the Sweep User Manual, but they're included below for quick reference.
|Bit Rate||115.2 Kb/s|
- Open up CuteCom and apply the communication settings at the top of the application.
- Make sure "Hex output" is unchecked for now, and the application will display ASCII formatted data that we can read directly.
- It can be helpful to specify "LF line end" at the bottom right. This setting simply appends a line feed ('\n') to the end of a command automatically. If you don't set this, be sure to add a '\n' to the end of transmitted commands.
Other than the transmission history or log file, CuteCom should now look like this:
- Make sure the Sweep sensor is plugged into a USB port.
- Select the correct port under the "Device" dropdown at the top of the application.
- Press the "Open device" button. CuteCom should now look like this:
Sending a Simple Command
Recall from the "Background" section that certain commands allow the host to request information, while other commands provide instructions for the sensor to follow. We'll start by looking at the simpler of the two, which is a request for information.
The following commands from the communication protocol request info from the sensor, and do not include any parameters:
LI - LiDAR Info
MI - Motor Info
IV - Version Info
ID - Device Info
For example, "Motor Info" is simply a request for the current motor speed. Let's take a closer look at how the "MI - Motor Info" command works.
Look through the Communication Protocol section of the Sweep User Manual for the command in question. Under "MI - Motor Info", you should see the protocol format for two structures. The first is for the command (host -> sensor), and the second is for the receipt (sensor -> host). Let's go ahead and send a "Motor Info" command to see how the sensor responds.
**NOTE: As mentioned previously, CuteCom is just a simple graphical application for viewing serial data. The "Input" box at the bottom of the application is where you can type a command. Hitting "enter" on the keyboard will send the command over serial. Recall that, if enabled, the "LF line end" setting will append a line feed to the end of the command.
1. Note the structure of the command (host -> sensor) from the protocol listed in the Sweep User Manual. In this case, the protocol states the command structure is "MI\n". More formally, the bytes are of the form:
2. Type "MI" (without the quotes) into the input box. Again, the "LF line end" will automatically append "\n" to that input, such that the final transmission is "MI\n". If you don't have the setting enabled, then type "MI\n" directly into the input field. Before you hit "enter", CuteCom should look like this:
3. Press "Enter" on the keyboard to send the command and you should see the following response.
**NOTE: CuteCom displays the received data in the center box. Recall that we have it set to output ASCII, so you can't see the '\n' character which CuteCom interprets as a newline. If we switched to "Hex output", we could see the hex value of the '\n' character, but in ASCII output it will look like a newline.
So, as the host we sent the command "MI\n". And in response the sensor sent back a receipt of the form "MI05\n". Again we consult the communication protocol from the Sweep User Manual and see that the receipt structure (sensor -> host) for "MI - Motor Info" is:
|M||I||Speed(Hz) (2 bytes)||LF|
So the response "MI05\n" is expected. The first two bytes let the host know that the receipt is responding to a "Motor Info" command. The third and fourth bytes respond to the request for motor information. The two bytes are interpreted as an ASCII encoded motor speed in HZ. The value is ASCII encoded so that it can be read directly from a terminal. In this case, the motor speed was 5Hz, so the motor code "05" populated the third and fourth bytes of the receipt. A line feed finishes the receipt.
Sending a Command with Parameters
The previous section outlined how to send simple commands that did not involve parameters. Now we'll look at sending a command that involves parameters. Commands that involve parameters are:
MS - Adjust Motor Speed
LR - Adjust LiDAR Sample Rate
Consider the "MS - Adjust Motor Speed" command. Again, let's turn to the Sweep User Manual and take a look at the protocol for the "MS - Adjust Motor Speed" command. The protocol for the command (host -> sensor) takes the following form:
|M||S||Speed Parameter (2 bytes)||LF|
Similar to the "Motor Info" receipt from the last section, the Speed Parameter here is an ASCII encoded motor speed in HZ, with valid integer values from '00' to '10'.
In the last section, we sent a command asking for the motor speed. The sensor informed us that the speed was 5Hz. Let's try adjusting the motor speed to 2Hz.
1. Type "MS02" into the input field representing an "Adjust Motor Speed" command with a parameter value of "02". Before you hit "Enter", CuteCom should look like this:
2. Press "Enter" on the keyboard to send the command and you should see the Sweep begin to slow down to a 2Hz rotation. In CuteCom you should see the following response:
So, as the host we sent the command "MS02\n". And in response the sensor adjusted its motor speed and sent back a receipt of the form "MS02\n00P\n". Again we consult the communication protocol from the Sweep User Manual and see that the receipt structure (sensor -> host) for "MS - Adjust Motor Speed" is:
|M||S||Speed(Hz) (2 bytes)||LF||Status (2bytes)||Sum||LF|
So the response "MS02\n00P\n" is expected. The first two bytes let the host know that the receipt is responding to an "Adjust Motor Speed" command. The third and fourth bytes echo back the instructed motor speed. The next byte is a line feed, hence why the CuteCom shows the response split over two lines. The next 3 bytes, "00P", represent the status and sum of status used in performing a checksum. For now, know that "00P" means the checksum was valid. Lastly, a line feed finishes the receipt.
Special Case (Acquiring Data)
At this point we've seen how to send a simple command, as well as a command that involves parameters. However, all the examples so far involved a single command and a single receipt. In the case of data acquisition, the behavior is slightly different.
There are only two commands involved:
DS - Start data acquisition
DX - Stop data acquisition
Both of these commands elicit a receipt of the general form we have already seen. In both cases, the sensor will respond with a receipt that acknowledges the command. However, in the case of "DS - Start Data Acquisition", the sensor will begin to stream data after sending the initial receipt.
To facilitate current performance, the communication protocol for data acquisition is a 1-way data stream (sensor -> host). The sequence of initiating and terminating the stream goes as follows:
- Host sends a "DS - Start Data" command to the sensor.
- Sensor sends a "DS - Start Data" receipt back to the host, to acknowledge the command.
- Sensor begins sending a constant stream of data blocks, each containing a single sensor reading. The stream continues indefinitely.
- Host sends a "DX - Stop Data" command to the sensor.
- Sensor terminates the data stream (ending on a complete data block) and sends a "DX - Stop Data" receipt back to the host, to acknowledge the command.
In this section, we will look at the process of initializing and terminating the data stream. Because we are dealing with an active stream of data, it will be most useful to start the stream and then stop it, before looking at the received data.
**NOTE: During the time that the stream is active, incoming "Data Block" receipts will be shown by the serial tool. The "Data Block" receipt type is unique in that it is the only part of the communication protocol that is not ASCII formatted. This is because the sensor reading data is variable and must be sent in a compact form. Parsing the "Data Block" receipts is an involved process that covered in a separate article, which can be found here.
1. Consult the communication protocol from the Sweep User Manual. The command (host -> sensor) structure for "DS - Start Data Acquisition" is:
Similarly the command (host -> sensor) structure for "DX - Stop Data Acquisition" is:
2. Enter "DS" into the CuteCom input field, and press "Enter" on the keyboard to send the "DS - Start Data Acquisition" command. The terminal will start streaming data, which will look like gibberish.
3. Quickly enter "DX" into the CuteCom input field, and press "Enter" on the keyboard to send the "DX - Stop Data Acquisition" command. The terminal should stop streaming data.
Scrolling through the terminal, you'll see a lot of strange symbols. Recall that the active data stream sends data that is not formatted in ASCII, so byte values will not correspond to normal characters, and line breaks will be seemingly random.
4. Scroll to the top and you should see something like this:
Note that the "DS00P\n" receipt came through before anything else. And that "DS00P\n" matches the expected structure for a "DS - Start Data Acquisition" receipt:
|D||S||Status (2 bytes)||Sum||LF|
The gibberish that follows after the "DS - Start Data Acquisition" receipt is a stream of "Data Block" receipts.
5. Scroll down to the bottom and you'll see something like this:
Note that the very last bit of characters read "DX00P\n". This matches the expected structure of a "DX - Stop Data Acquisition" receipt:
|D||X||Status (2 bytes)||Sum||LF|
For more information on parsing the "Data Block" receipt types, check out the article here.
Understanding the Checksum
In the previous examples we saw that some receipts included 2 status bytes and a sum byte which came through as "00P". Let's take a closer look at what "00P" actually means, and why it indicates a valid receipt.
Some receipts include status bytes that should be checked against a checksum. All receipt types that involve checksums (other than "Data Block") use a standard format of 2 status bytes followed by a single checksum byte. The placement varies depending on the receipt type, but the structure looks like this:
|STATUS 1||STATUS 2||CHECKSUM|
This checksum is meant to be human readable in a terminal. For example a standard combination of status and checksum bytes might look like "00P" as we saw in the previous example. In order to maintain readable ASCII characters, the operations involved in validating the checksum are slightly abnormal and non-intuitive. It works like this:
- The status bytes are summed
- The lower 6 bits (Least Significant) of that sum are then added to 30Hex
- The resultant value is compared with the checksum byte
//statusByte#1 + statusByte#2 let sumOfStatusBytes = status1_byteValue + status2_byteValue; //grab the lower (least significant) 6 bits by performing a bit-wise AND with 0x3F (ie: 00111111) let lowerSixBits = sumOfStatusBytes & 0x3F; //add 30Hex to it let sum = lowerSixBits + 0x30; return ( sum === checkSumByteValue );
Consider the common case of '00P' (decimal -> [48, 48, 80], hex -> [0x30, 0x30, 0x50])
0x30 + 0x30 = 0x60 // sum of the status bytes
0x60 & 0x3F = 0x20 // retrieve only the lower 6 bits
0x20 + 0x30 = 0x50 // calculate the ASCII legible sum
0x50 = 'P' // translate to ASCII
**NOTE: The "Data Block" receipt type is a special case where all byte values in the packet are variable, and the checksum is performed over the entire packet. This is covered in a separate article about parsing sensor reading data block receipt types, which can be found here.
In RealTerm, apply the settings on the Port tab.
- First select your Sweep's port number. If you don't know the number, you can find it in the device manager. For example, the image below shows the Sweep as COM4 in the device manager, so Por #4 was selected in RealTerm.
- Most of the settings (Parity, Data Bits, Stop Bits, Hardware Flow Control) will probably be correct by default, but verify them with the image below.
- The Baud setting will have to be changed to 115200.
- Verify that all settings match the image below, and hit the "Change" button with the green check mark to save any changes.
- Verify that all settings match the image above and hit the "Open" button to connect to the port.
- Navigate to the "Send" tab.
- Make sure "+LF" is checked under the EOL setting to automatically append a line feed.
- Send commands from this "Send" tab, by typing the command and then hitting the "Send ASCII" button. For example, sending a "MI - Motor Information" command would look like:
And the receipt should look like:
The process in PuTTy is not as straightforward, but a few settings will yield the same basic behavior.
For starters, look up the com port number for your Sweep device using the Device Manager. In this PuTTy example, the device is COM5.
Navigate to the "Session" category in PuTTy:
- Set the "Connection Type" to Serial
- Specify your COM# in the "Serial Line" textbox. In this example, the Sweep device is COM5.
- Specify the baud rate (115200) in the "Speed" box.
Next, navigate to the "Connection -> Serial" subcategory. Here you need to specify the serial connection settings according to the protocol. These settings were outlined earlier in the article at the beginning of the "Setup" section. Verify that your settings match the image below, but do NOT hit "Open" yet.
Before we open the serial line, we need to specify a few terminal settings. By default, the PuTTy terminal will send characters as they are typed, rather than waiting until the user types a complete command and hits enter. This causes a problem. The Sweep firmware implements a safety protocol which resets the receive buffer if another character is not received within 100ms of the last received character. So, we need to change the terminal settings to send a complete command all at once.
Navigate to the "Terminal" category and find the section labeled "Line discipline options".
- Check 'Force On' for the "Local echo:" setting
- Check 'Force On' for the "Local line editing:" setting
The change to the "Local line editing" setting means the terminal will not send the command until you press enter. The "Local echo" will allow you to see what you are typing which is always helpful.
Once you've changed the Terminal settings, go ahead and hit the "Open" button.
This will open a blank terminal, which should look like:
Go ahead and type a command. For example, "MI" is typed to retrieve motor speed information.
**Note: The linefeed is automatically appended, so we only type "MI" instead of "MI\n".
Hit enter to send the command (PuTTY will send "MI\n", automatically appending the "\n" for you) and you should see the device return information about the motor speed. In this case, the device was using default motor speed of 5Hz, so we see a receipt "MI05\n" which appears as "MI05" and a new line.
Any line feeds in the receipts will be shown on the terminal as a new line, so receipts may be broken up across multiple lines. For example the terminal output below resulted from the following actions:
- Send "MI\n" to the sensor by typing "MI" and hitting enter. This requests motor info.
- Sensor responds with "MI05\n" which is shown as "MI05" and a new line.
- Send "MS02\n" to the sensor by typing "MS02" and hitting enter. This adjust motor speed to 2Hz.
- Sensor responds with "MS02\n00P\n" which is shown as "MS02", a new line, "00P", and a new line.
- Send "MI\n" to the sensor by typing "MI" and hitting enter. This requests motor info.
- Sensor responds with "MI02\n" which is shown as "MI02" and a new line.