Lab #12 and #13 Acoustic Communications and Networking 2.S998 Unmanned Marine Vehicle Autonomy, Sensing and Communications Mar 20, 2012 and Mar 22, 2012 Guest lecturer: Toby Schneider Michael Benjamin, Henrik Schmidt Department of Mechanical Engineering MIT, Cambridge MA 02139 Contents 1 Overview and Objectives 1.1 Structure of Today’s Lab and Goals 1.2 Preliminaries - Pre-lab assignment . 1.3 Preliminaries - Start of lab . . . . . 1.4 What you will hand in . . . . . . . . 1.5 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 4 5 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Using Goby (pAcommsHandler) with MOOS-IvP 2.1 Launch a one-way point-to-point network . . . . . . 2.2 pAcommsHandler terminal output . . . . . . . . . . 2.3 pAcommsHandler MOOS API . . . . . . . . . . . . . 2.4 Comparing encoding representations . . . . . . . . . 2.5 DCCL Message: AcommsExampleMessage . . . . . . 2.6 Examine a special purpose encoder: VarIntCodec . . 2.7 Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 . 6 . 6 . 8 . 9 . 9 . 10 . 11 3 Using an acoustic modem to deploy an underwater vehicle 12 3.1 The WHOI Micro-Modem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1 3.2 3.3 Sending a Mini-Packet command using pAcommsHandler . . . . . . . . . . . . . . . 15 Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4 Encoding a sample from 4.1 Your Task . . . . . . . 4.2 Approach . . . . . . . 4.3 Questions . . . . . . . a . . . Conductivity-Temperature-Depth (CTD) sensor 17 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2 1 Overview and Objectives 1.1 Structure of Today’s Lab and Goals Today’s and Thursday’s labs are combined into a single longer lab focused on acoustic communi­ cations and networking. By the end, you will have a good understanding of the difficulties AUV researchers face when attempting to communicate over the very low throughput / high latency acoustic link. In this lab, we will make use of the Goby Underwater Autonomy Project to provide us with the backbone networking software. We will be both simulating the acoustic link using the uField Toolbox and using real acoustic modems connected via coaxial cables instead of electro-acoustic transducers (No, I’m not bringing a bathtub or the ocean into the classroom). There are three parts to this lab: 1. Understand the process of creating a message suitable for sending on an acoustic modem using Goby and MOOS-IvP. (Section 2). 2. Deploy your lab partner’s surface vehicle using an acoustic minipacket using the Micro-Modem hardware. (Section 3). 3. Design an basic arithmetic coder suitable for encoding temperature data generated by a simulated AUV’s sensor. (Section 4). Important: The second task can be done at any point before or after the other parts of the lab. I only have enough hardware for three lab groups to work at one time, so budget your time to do this task (1/2 hour or so) during lab time when one of the Micro-Modem boxes are free. Find a partner and sign up on the blackboard for your turn. While the other sections are primarily individual assignments, you are welcome to troubleshoot and ask questions of your fellow students for all parts of this lab. 1.2 Preliminaries - Pre-lab assignment In addition to the working MOOS-IvP setup required for every lab, we have a few more preliminaries for this lab. In order to maximize useful lab time this week, and hopefully remove the need for any work to be done over Spring Break, we ask you to complete the following setup and background pre-lab assignment and hand it on (on Stellar) prior to lab start on Tuesday March 20, 2012: 1. Download and compile Goby (version 2.0) per the instructions listed here: http://gobysoft. com/wiki/InstallFor2S998. 2. Read the first two sections (Data Compression and Arithmetic Coding and Tutorial on Arithmetic Coding) from the paper Practical Implementations of Arithmetic Coding by P. Howard and J. Vitter [1], available at http://www.gvu.gatech.edu/~jarek/courses/7491/ Arithmetic2.pdf. Please answer the following questions: (a) State the primary advantage(s) of arithmetic source encoding. (b) State the primary disadvantage(s) of arithmetic coding. (c) Why might this type of coding make sense for marine vehicle communications? 3 3. We will be using Google Protocol Buffers (“protobuf”) as the definition language for our acoustic datagrams (though we will not be using their encoding - it’s not efficient enough!). Read through these pages to get a sense of what Google Protocol Buffers is and how it works with C++, and answer these quick questions: (a) Overview: http://code.google.com/apis/protocolbuffers/docs/overview.html (b) C++ Tutorial: http://code.google.com/apis/protocolbuffers/docs/cpptutorial. html i. What is the relationship between a Protobuf “Message” and a C++ “class”? ii. Given this .proto file, how would I (in C++) set the value of the “temperature” field to 21.435? message CTDSample { optional double temperature = 1; optional double salinity = 2; } 1.3 Preliminaries - Start of lab 1. Update and compile any changes to Goby since you did the pre-lab checkout: cd goby bzr up ./build.sh 2. You will need to check out a branch of moos-ivp-extend that contains the code and missions for today’s lab. The structure of the repository should be familiar from previous labs. Use bzr co lp:~tes/junk/moos-ivp-extend-acomms Build the repository using the include script: cd moos-ivp-extend-acomms ./build.sh Add moos-ivp-extend-acomms/bin to your shell path. Open a new terminal window and check that you have correctly set your path using which ctd_tester which should give something like /home/toby/moos-ivp-extend-acomms/bin/ctd_tester 3. If you’re using a Mac (OS X Lion), you’ll need to install the PL2303 driver as explained on this blog post http://xbsd.nl/2011/07/pl2303-serial-usb-on-osx-lion.html Use ”sudo bash” or ”sudo tcsh” to get a root shell before following their instructions. 4 1.4 What you will hand in By the end of lab Thursday Mar 22, 2012, you will hand in answers to the questions of sections 2 and 3. The arithmetic coder (Section 4) and related questions will be due Thursday April 5, but you should be able to complete most or all of it in the lab time provided. Please produce a PDF document with the answer to your questions, and hand in your source code as usual by zip’ing or tar’ing the moos-ivp-extend-acomms tree, renamed to moos-ivp-yourname. All of these should be uploaded to Stellar. 1.5 Glossary We’ll be doing some bit math and such, and since you all have a varieties of backgrounds, we’ve made a quick glossary to try to address as many foreign terms / code snippets as possible: • Binary (base 2): A number system where there are only two numerals: 0 and 1. It works just like base 10 (decimal) in other regards, just use 2 instead of 10. Binary numbers are generally easy to identify as they only contain 0 and 1. Where ambiguous, I will use a prefix letter ’d’ to mean decimal, and ’b’ for binary. ’0x’ is the prefix commonly used for hexadecimal (this works in C++). You may find a calculator that can do binary to decimal conversions useful for this lab. The default Ubuntu calculator in Programming Mode will do that for you. You can also use Python: $ python >>> bin(200)[2:] ’11001000’ >>> int(’11001000’, 2) 200 • Bit shifting (operator<< and operator>>): Moves the bits to the left or right by the number of places on the right side of the operator. This effectively multiples or divides the number by 2 to the number of bits shifted. For example: int i = 5; // binary 101 int j = i << 2; // binary 10100 assert(j == 20); // true • Codec (coder/decoder), coder, and encoder/decoder are all used interchangeable in this lab to mean a program that takes a high-level uncompressed input, produces a set of bits suitable for transmission across a medium (encode), and can reproduce the input on the other end (decode). This process is somewhat synonymous with “data marshalling.” In certain contexts this is referred to as “source coding” to disambiguate it from “channel coding,” which is interested in making the best use of a particular communications channel (and provides error correction). 5 2 Using Goby (pAcommsHandler) with MOOS-IvP 2.1 Launch a one-way point-to-point network We’re going to start with a basic two community network that is a simple version of a common underwater scenario - a “sender” community (often a subsea node collecting data), and a “receiver” (typically a topside on a ship). In reality, communications are bi-directional as we want to command the vehicle from the topside as well, but typically the data flow is lopsided, weighted heavily towards the data-collecting node. Find the mission named “acomms1”: cd moos-ivp-extend-acomms/missions/acomms1 Launch it: ./launch.sh You will see two communities launch: the sender on the left side of the screen and the receiver on the right side. Both communities have a window for pAcommsHandler (the MOOS interface to the goby_acomms library) in show_gui: true mode that provides a large amount of diagnostic information. The other applications include: • pAcommsExample: This application, running on the sender community, is continuously pub­ lishing a message containing an index, a random number (placeholder for real data), and the sender of the message (currently my MIT id, tes). • uXMS: You are familiar with this application. On the sender community, it is showing the output of pAcommsExample (MOOS variable ACOMMS_EXAMPLE_OUT). On the receiver community, shows the equivalent received variable after sending through the (simulated) acoustic link. • pCoroner: Similar to uProcessWatch, shows if any applications known to pAntler are not currently running. Some things to note before we continue: • Vehicles are identified by an unsigned integer (or “modem id”) that is much like a MAC address on your computer’s network card. String names like “gilda” are too costly in message space to use. We can use lookup tables, however, to tie modem ids to names. The modem id “0” is reserved to indicate “broadcast” in Goby. All vehicles will decode messages sent to “0”. 2.2 pAcommsHandler terminal output pAcommsHandler is the focus here, so watch the text in the terminal window to get a sense of what is going on. Maximize it as needed. From the top left, going to the bottom left, and over to the right column, the diagnostic displays indicate the modules of goby_acomms in order from application layer to link layer (see Fig. 1): • Ungrouped messages: messages that don’t have a clear home. 6 goby-acomms user «file» DCCL Protobuf (.proto) «executable» Acomms Application goby-acomms Presentation «module» dccl DCCLCodec Transport «module» queue QueueManager «module» amac MACManager Data Link MMDriver «module» modemdriver DriverBase Modem Hardware Physical «executable» Modem Firmware Figure 1: The software structure of Goby, showing the approximate OSI network layer on the left. In this lab, we will focus mostly on the DCCL and ModemDriver components. • pAcommsHandler: messages specific to the interaction between Goby and MOOS. In this window you will basically see a copy of what pAcommsExample is publishing. • goby::acomms::dccl::encode: shows the Dynamic Compact Control Language (DCCL) encoder output. When a message is encoded for sending, a line is printed here indicating that. • goby::acomms::dccl::decode: shows the Dynamic Compact Control Language (DCCL) decoder output. When a message is decoded after receiving, a line is printed here indicating that. • goby::acomms::queue::push: shows when a message is pushed (added) to the Goby dy­ namic priority queue. • goby::acomms::queue::pop: shows when a message is popped (removed) from the Goby dynamic priority queue. • goby::acomms::priority: shows the results of the priority contest that is held between all queues when it is time to send a message. Since there is only one message loaded (Acomm­ sExampleMessage), it always wins. • goby::acomms::queue::out: Messages showing the output of the queue data to the ModemDriver (link layer). 7 • goby::acomms::queue::in: Messages showing the input of the ModemDriver to the queuing layers. Messages are not queued upon receipt, but are rather immediately decoded. • goby::acomms::queue::amac: Acoustic Medium Access Control (MAC) unit. This governs the time schedule when a given node is allowed to send. In this example, we have a single slot: vehicle 1 sends to the destination of the next message. • goby::acomms:modemdriver::out: Raw outgoing messages to the modem hardware. In this case of this example, we are using a driver that passes messages through MOOS (using the uField NODE_MESSAGE variables). Switching to a real modem such as the WHOI Micro-Modem is only a matter of changing a few configuration variables. • goby::acomms:modemdriver::in: Raw incoming messages from the modem hardware. 2.3 pAcommsHandler MOOS API pAcommsHandler writes a variety of messages to MOOS variables that by default begin with ACOMMS_. The contents of all these messages are human-readable representations of Protobuf mes­ sages. Open uMS or uXMS and take a look at these variables (these are the default names, all of which can be configured in the MOOS file if desired). Some will only be published on one community or the other: • ACOMMS_RAW_INCOMING: Shows the serial or TCP feed to the current acoustic modem. The uField Driver uses a hexadecimal representation of the Protobuf encoding of goby::acomms::protobuf::ModemTransmission. The WHOI Micro-Modem uses an NMEA­ 0183 interface as you’ll see in the next section. • ACOMMS_RAW_OUTGOING: Shows the serial or TCP feed from the current acoustic modem. • ACOMMS_MODEM_RECEIVE: Abstracted message from the Modem driver. This message will look the same regardless of which low-level driver is being used. The frame field contains a DCCL encoded message. • ACOMMS_MODEM_TRANSMIT: Abstracted message to the Modem driver. This message will look the same regardless of which low-level driver is being used. The frame field contains a DCCL encoded message. • ACOMMS_QUEUE_RECEIVE: Decoded received message. This should look very much like the final published message. • ACOMMS_QUEUE_TRANSMIT: Unencoded sent message. • ACOMMS_QSIZE: Indicates whenever a queue changes size (due to a message being pushed or popped). • ACOMMS_MAC_INITIATE_TRANSMISSION: Indicates the beginning of a transmission. The uField Driver also uses a few more MOOS variables to do its work: 8 • NODE_MESSAGE_LOCAL: posted to allow the uField tools to route the message via the shoreside to another vehicle. This gives us some rudimentary network simulation capabilities (primarily range-dependent packet dropping). • ACOMMS_UFIELD_DRIVER_OUT: copy of the string_val field of the message posted NODE_MESSAGE_LOCAL in the same encoded format as will be published to ACOMMS_UFIELD_DRIVER_IN on the re­ ceiving end. • ACOMMS_UFIELD_DRIVER_IN: posted by uFieldMessageHandler after routing the message orig­ inally posted to NODE_MESSAGE_LOCAL. This is subscribed to by the Goby uField Driver. 2.4 Comparing encoding representations Look at the terminal output of pAcommsExample. After each message, the size is written if the mes­ sage were encoded using a std::string (“TextFormat”), the built-in Protobuf encoder, and DCCL. It should be clear from this that DCCL offers the smallest packet size. The drawback is the extra work precisely defining the origin of our messages’ data. We will look at this briefly in the next subsection (2.5), and substantially more using a probabilistic framework in Section 4. We’re done with running the acomms1 example, but before killing MOOS (mykill), answer the first question below in Section 2.7. 2.5 DCCL Message: AcommsExampleMessage The message AcommsExampleMessage is a Google Protocol Buffers message that is defined in moos-ivp-extend-acomms/src/protobuf/acomms_example.proto To allow DCCL to encode this message, some custom message (goby.msg) and field extensions (goby.field) are defined to allow us to attach further meta-data to the message definition. This ad­ ditional information is used to produce an even smaller encoded message than the default Protobuf technique. Only a subset of the extensions are used here. The full set is given in http://gobysoft. org/doc/2.0/index.html., and the requirements of the various built-in encoders/decoders (“codecs”) is given on this page: http://gobysoft.org/doc/2.0/acomms_dccl.html#dccl_options . Normally, integers are stored in 32 or 64 bits, but most of the time we’re actually sending messages from a small subset of the available 232 or 264 integers. Thus, the built-in DCCL codecs use arbitrarily bounded integers to send data1 . For example, if you set (goby.field).dccl.max = 99, (goby.field).dccl.min = 0 the default DCCL codec for int32 creates a 7-bit integer2 to store it, a savings of 25 bits or 78% over using a 32-bit integer. This is how the field named random in AcommsExampleMessage is being encoded. 1 While slightly out of date, this paper gives the algorithms for the built-in codecs: http://gobysoft.com/dl/ dccl_oceans10.pdf 2 ceil(log 2(99 − 0 + 1)) = 7 9 2.6 Examine a special purpose encoder: VarIntCodec While this simple technique for reducing the size of our messages is a useful first attempt to send tightly compressed data, we can often do better than this. The key to this improvement is to understand the underlying probability distribution of the data (or “symbols”) to be sent. Let’s assume that the small numbers (say 0-127) are sent much more frequently than large numbers, but we still want to be able to handle larger numbers as the need arises. One way to do this is with a variable integer (“varint”) encoder3 , which uses one byte for the values 0-127 and two bytes for 128-32768. The final bit is used for indicating the size of the range (large or small). For example, the small number 50 would be encoded as: 0110010 ^ | d50 0 ^ | 0 means short form (1 byte = 8 bits) On the other hand, the large number 500 would be 000000111110100 ^ | d500 1 ^ | 1 means long form (2 bytes = 16 bits) Such a codec can be written outside the Goby project and imported as a plugin. To do so, we define some name for our codec and write it into the Protobuf message: (goby.field).dccl.codec="lab12_varint" To write our codec, we subclass DCCLTypedFieldCodec4 for singular fields (optional or required in Protobuf parlance) or DCCLRepeatedTypedFieldCodec5 for repeated fields (which are basically vectors). This is done for the varint codec in moos-ivp-extend-acomms/src/codecs/varint.h moos-ivp-extend-acomms/src/codecs/varint.cpp You will want to look at this code to get an idea of how a simple variable-length codec looks in advance of writing a slightly more complicated one in section 4. Finally, we must load our codecs using the code given in moos-ivp-extend-acomms/src/codecs/codec_load.cpp All this code is compiled into a dynamic library (lab12codecs.so/dylib) that is loaded by pA­ commsHandler6 , which in turn loads the codecs into the Goby DCCL module. This extensibility allows for tailoring acoustic messaging to specific mission needs, without needing to modify the Goby source code. However, this level of effort isn’t required, as the built-in codecs provide useful functionality for deployments with slightly less rigorous data compression requirements. 3 as an interesting side note, variable integer encoding is how Google Protocol buffers default encoding works: see http://code.google.com/apis/protocolbuffers/docs/encoding.html 4 http://gobysoft.org/doc/2.0/classgoby_1_1acomms_1_1DCCLTypedFieldCodec.html 5 http://gobysoft.com/doc/2.0/classgoby_1_1acomms_1_1DCCLRepeatedTypedFieldCodec.html 6 using dlopen 10 2.7 Questions Some quick questions for you to consider and hand in by the end of the lab on Thursday. 1. When you examine the output of pAcommsExample, you will notice that more messages are being sent then are able to make it through the simulated acoustic link (which has the bitrate of 32 bytes/10 seconds = 25.6 bps). The reality here is that total throughput is usually unattainable on acoustic links. This is a foreign concept to us on terrestrial links (e.g. my emails will be sent faster than I create them). List two ways you could deal with this buffer overflow problem. 2. If we were using the varint codec given in section 2.6 and our numbers were almost always large, we would use 16 bits to encode symbols that only require 15 bits to encode (because we use 1 bit to indicate the size domain). Thus, there is some probability, p0 , where P (small) >= p0 that makes use of the varint codec worthwhile (i.e. it will use fewer bits on average). What is that value p0 ? As before, large is defined as values [128, 32768) and small is [0, 128). 11 3 Using an acoustic modem to deploy an underwater vehicle This section is done on limited modem hardware (up to three teams of two at one time). Sign up on the blackboard and we’ll go in that order. 3.1 The WHOI Micro-Modem The WHOI Micro-Modem is one of only a few commercially available acoustic modems. It uses two types of modulation (Frequency-Hopping Frequency Shift Keying (FH-FSK) and Phase Shift Keying (PSK)) to achieve a range of packet sizes from 32 bytes / packet to 2048 bytes / packet. Higher rates are more susceptible to bit errors and thus packet loss. Realistically, a single packet can be sent about once every 10-15 seconds after accounting for signal length (3.5 seconds), time of flight (100 to 10000 meters range over 1500 m/s nominal speed of sound), and potentially an acoustic acknowledgment. Thus, realistic data rates range from 20 bps to to 200 bps before accounting for packet loss (which can be easily greater than fifty percent). This is why we spend so much time in the rest of this lab focusing on data compression for very small packets. 3.1.1 Serial Data Protocol The WHOI Micro-Modem connects over a serial line (RS-232) at a default 19200 baud rate. It uses a data protocol roughly based on the NMEA 0183 standard, which is widely used in marine electronics (e.g. GPS units)7 . Two primary “talker” ids are employed: $CC for messages from the computer and $CA for messages from the modem. A full PSK transaction including acknowledgment from modem 1 to modem 2 looks like this and is rather complicated: {goby::acomms::modemdriver::out::1}: $CCCYC,0,1,2,2,1,3*5A {goby::acomms::modemdriver::out::1}: ^ Network Cycle Initialization Command {goby::acomms::modemdriver::in::1}: $CACYC,0,1,2,2,1,3*58 {goby::acomms::modemdriver::in::1}: ^ Echo of Network Cycle Initialization command {goby::acomms::modemdriver::in::1}: $CADRQ,025728,1,2,1,64,1*4E {goby::acomms::modemdriver::in::1}: ^ Data request message, modem to host {goby::acomms::modemdriver::out::1}: $CCTXD,1,2,1,31313131313131313131313131313131... {goby::acomms::modemdriver::out::1}: ^ Transmit binary data message, host to modem {goby::acomms::modemdriver::in::1}: $CATXD,1,2,1,64*7A {goby::acomms::modemdriver::in::1}: ^ Echo back of transmit binary data message {goby::acomms::modemdriver::in::1}: $CADRQ,025729,1,2,1,64,2*4C {goby::acomms::modemdriver::in::1}: ^ Data request message, modem to host {goby::acomms::modemdriver::out::1}: $CCTXD,1,2,1,32323232323232323232323232323232... {goby::acomms::modemdriver::out::1}: ^ Transmit binary data message, host to modem {goby::acomms::modemdriver::in::1}: $CATXD,1,2,1,64*7A {goby::acomms::modemdriver::in::1}: ^ Echo back of transmit binary data message {goby::acomms::modemdriver::in::1}: $CADRQ,025729,1,2,1,64,3*4D {goby::acomms::modemdriver::in::1}: ^ Data request message, modem to host {goby::acomms::modemdriver::out::1}: $CCTXD,1,2,1,*7A {goby::acomms::modemdriver::out::1}: ^ Transmit binary data message, host to modem {goby::acomms::modemdriver::in::1}: $CATXD,1,2,1,0*48 {goby::acomms::modemdriver::in::1}: ^ Echo back of transmit binary data message {goby::acomms::modemdriver::in::1}: $CATXP,128*49 7 The entire protocol is posted at http://acomms.whoi.edu/umodem/documentation.html under “Micro-Modem Software Interface Guide” 12 {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::2}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: {goby::acomms::modemdriver::in::1}: ^ Start of packet transmission, modem to host $CARXP,1*45 ^ Incoming packet detected, modem to host $CATXF,128*5F ^ End of packet transmission, modem to host $CAREV,025733,AUV,0.94.0.00*0E ^ Software revision message, modem to host $CAREV,025733,COPROC,0.10.0.46*40 ^ Software revision message, modem to host $CACYC,1,1,2,2,1,3*59 ^ Echo of Network Cycle Initialization command $CARXD,1,2,1,1,3131313131313131313131313131313... ^ Received binary message, modem to host $CARXD,1,2,1,2,3232323232323232323232323232323... ^ Received binary message, modem to host $CARXD,1,2,1,3,*61 ^ Received binary message, modem to host $CACST,0,025729.0000,1,1903,20,0410,0167,00,01,... ^ Communication cycle receive statistics $CAREV,025733,AUV,0.94.0.00*0E ^ Software revision message, modem to host $CAREV,025733,COPROC,0.10.0.46*40 ^ Software revision message, modem to host $CARXP,1*45 ^ Incoming packet detected, modem to host $CATXP,0*42 ^ Start of packet transmission, modem to host $CAACK,2,1,1,1*48 ^ Acknowledgment of a transmitted packet $CAACK,2,1,2,1*4B ^ Acknowledgment of a transmitted packet $CAACK,2,1,3,1*4A ^ Acknowledgment of a transmitted packet $CACST,0,025734.0000,1,1608,20,0295,0165,00,01,01,... The Micro-Modem also has several other features, one of which is the handy ability to send 13 bits in the mini-packet (normally used for control messages such as the acknowledgment). This is pretty much the acoustic modem equivalent of the SMS. While very small in size, the packet is received with high reliability, and the transaction is simpler (see also Fig. 2) (sending hexadecimal data 0x1234): {goby::acomms::modemdriver::out::1}: $CCMUC,1,2,1234 {goby::acomms::modemdriver::in::1}: $CAMUC,1,2,1234*72 {goby::acomms::modemdriver::in::1}: $CATXP,0*42 {goby::acomms::modemdriver::in::1}: $CATXF,0*54 {goby::acomms::modemdriver::in::2}: $CARXP,1*45 {goby::acomms::modemdriver::in::2}: $CAMUA,1,2,1234*70 You should try this now. Connect one modem to each of you and your lab partner’s machines. Both of you should identify the serial port created by the connection. Use ls /dev/tty* to see what device is added when you plug in the USB-serial dongle. On Linux it’s probably /dev/ttyUSB0; on Mac OS X it’s probably /dev/tty.usbserial or /dev/tty.PL2303...). Replace all usages of /dev/ttyUSB0 below with the correct device name for your machine. Open picocom 13 Application or other Goby Modules WHOI Micro-Modem Firmware 1 modemdriver1 WHOI Micro-Modem Firmware 2 modemdriver2 Application or other Goby Modules initiate_transmission [[ModemTransmission]] src: 1 dest: 2 type: MICROMODEM_MINI_DATA signal_modify_transmission modified transmission signal_data_request if ModemTransmission::frame_size() < 1 [[ModemTransmission]] src: 1 dest: 2 type: MICROMODEM_MINI_DATA max_num_frames: 1 max_frame_bytes: 2 frame: "\001#" requested data $CCMUC $CAMUC $CATXP FSK-Mini (User) CAXST [[ModemTransmission]] src: 1 dest: 2 type: MICROMODEM_MINI_DATA [micromodem.protobuf.transmit_stat] { ... packet_type: FSK_MINI ... } $CARXP $CAMUA signal_transmit_result $CACST type == MICROMODEM_MINI_DATA: signal_receive [[ModemTransmission]] src: 1 dest: 2 time: 1316033108000000 time_source: MODEM_TIME type: MICROMODEM_MINI_DATA frame: "\001#" [micromodem.protobuf.receive_stat] { mode: RECEIVE_GOOD ... data_quality_factor: 250 doppler: 0 stddev_noise: -1 carrier_freq: 25120 bandwidth: 4000 version: 0 } Key: Always present (required usage) Often present (typical usage) Occasionally present (advanced or special usage) Figure 2: WHOI Micro-Modem User mini-packet 13 bit data transmission using Goby. You should see something like the far right ModemTransmission message if you open uXMS on ACOMMS MODEM RECEIVE on the receiving end (vehicle). The actual acoustic transmission occurs where it says “FSK-Mini” in the center. picocom /dev/ttyUSB0 -b 19200 and examine the output $CAREV,025733,AUV,0.94.0.00*0E $CAREV,025733,COPROC,0.10.0.46*40 $CAREV is the software revision number and serves as a heartbeat. Configure one modem to be modem id 1 (the modem id is called SRC on the WHOI Micro-Modem) printf ’$CCCFG,SRC,1\r\n’ > /dev/ttyUSB0 and the other 2 printf ’$CCCFG,SRC,2\r\n’ > /dev/ttyUSB0 Try sending each other minipackets. For the person connected to modem 1: printf ’$CCMUC,1,2,1234\r\n’ > /dev/ttyUSB0 or for the person on modem 2: printf ’$CCMUC,2,1,1234\r\n’ > /dev/ttyUSB0 On the receiving end you will see the received data $CAMUC,1,2,1234*72 Feel free to replace 1234 with any 13-bit hex number (0000 to 1fff). Close picocom (CTRL-A CTRL-X) on both machines in preparation for the next section. 14 3.2 Sending a Mini-Packet command using pAcommsHandler One of you will act the role of the shoreside, the other the vehicle. It doesn’t matter which person was id 1 last time, pAcommsHandler will change it to the correct value. Find the mission named “acomms2”: cd moos-ivp-extend-acomms/missions/acomms2 If you are using a Linux machine, change the line in goby_liaison.pb.cfg load_shared_library: "../../lib/liblab12messages.dylib" to load_shared_library: "../../lib/liblab12messages.so" Change the MICROMODEM_PORT definition in meta_shoreside.moos to correspond to the correct serial port and launch the shoreside on one machine: ./launch_shoreside.sh Similarly, change the MICROMODEM_PORT definition in meta_vehicle.moos and launch the vehicle on the other machine: ./launch_vehicle.sh Open a web browser of your choice and point it to http://localhost:50001/#/commander. Choose the MiniCommand message and fill in the fields (e.g. destination: 2, state: DEPLOY, man­ ual override: false, speed: 3). Click “Send” and the vehicle will receive the message and publish the variables specified under the translator_entry { publish {} } in plug_pAcommsHandler.moos. Once you have this working properly, kill the vehicle community and open picocom again picocom /dev/ttyUSB0 -b 19200 Examine the raw modem feed when you send the MiniCommand message. Note the $CAMUA when the shoreside pushes “Send” on Goby Liaison Commander. Now, restart the vehicle. Examine the MOOS variables ACOMMS_RAW_INCOMING and ACOMMS_MODEM_RECEIVE. In addition to the src, dest, type, frame fields you saw when you looked at ACOMMS_MODEM_RECEIVE in section 2.3, you’ll also notice a large amount of diagnostic information about the transmission. This is extracted from the $CACST message from the WHOI Micro-Modem. The interaction with the Goby ModemDriver and the rest of Goby (and MOOS via pA­ commsHandler) is diagrammed in Fig. 2. 3.3 Questions Please hand these in with the questions from the other sections by the end of lab Thursday. 1. What is the raw mini-packet NMEA-0183 message received by the “vehicle” computer when you send “destination: 2 state: DEPLOY manual override: false”? 2. Besides sending small commands from a shoreside computer as we did in this section, what is another possible use for a 13-bit packet? 15 Extra credit Once you are able to command the vehicle successfully, disconnect both the coaxial cables from either the top or bottom modem. Now try to send a RETURN command to the vehicle. What happens? Why is this happening? 16 4 Encoding a sample from a Conductivity-Temperature-Depth (CTD) sensor In section 2.6, we explored a variable integer encoder for encoding single integer (int32) fields. In this section, your goal will be to write an entropy encoder (specifically, an arithmetic encoder) for encoding temperature data from a Conductivity-Temperature-Depth (CTD) sensor (pictured in Fig. 3), which measures salinity (from conductivity), temperature, and depth (from pressure). CTD data are useful for vehicles performing collaborative environmental missions. They can also used to calculate the speed of sound using various empirical formulas [2], so they are also invaluable for acoustic modeling in sonar-based applications. Figure 3: A typical vehicle CTD: the Sea-Bird SBE49 [3] depth (meters) A traditional ship-based use of a CTD involves casting the instrument to a certain depth at a fixed location in the ocean (a “station”). When the cast is complete, the ship can move to another station, and another CTD cast is made. In this way, one can gather (and interpolate) a threedimensional picture of the salinity and temperature of the ocean. Since typically AUVs do not move directly vertically, a CTD profile is often made by “yoyoing” the vehicle; that is, the vehicle performs a series of periodic oscillations in depth while still covering ground. 0 50 100 100 200 300 400 500 600 range (meters) 700 800 900 1000 Figure 4: The path of a vehicle performing a sinusoidal yoyo for the purpose of collecting CTD data. In this section, we will be assuming the vehicle is continuously sampling the ocean between 0 and 100 meters as illustrated in Fig. 4. A priori (perhaps from an earlier data set or simulation), 17 we expect the temperature profile (in depth) to be that given in Fig. 5, which is defined by t(d) = ⎧ ⎪ ⎨ 20 0 <= d < 10 10 + 302−d 10 <= d < 30 ⎪ ⎩ 10 d >= 30 (1) where t is the current temperature in ◦ C, and d is depth in m. Given this information, it is possible for us to determine a probability mass function of the measured temperature. This will provide us with the ability to predict the samples we will obtain and thus improve the performance of the encoder used to prepare them for transmission. 0 Depth (m) 20 40 60 80 100 10 11 12 13 14 15 16 17 18 19 20 Temperature (° C) Figure 5: Assumed temperature profile (based off a typical Mediterranean summer profile) 4.1 Your Task Your goal in this section is to finish an arithmetic coder that will encode nearly optimally [1] the CTD samples coming from this hypothetical AUV sampling the profile given in Fig. 5. Specifically, we will make some simplifying assumptions to make your task manageable in the time allotted: • We will use arithmetic encoding only for the temperature; we will send depth and salinity values using the default DCCL codecs (bounded real numbers). • We will send the temperature values (in ◦ C) rounded to the nearest integer. This means we will be transmitting from a set of eleven symbols: {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}. • We will send exactly five samples per transmission (which means encoding five samples at a time). This means you will not run into trouble using the double precision floating point type (double) to hold the entire encoded answer range. For this assignment you do not need to worry about a variable number of samples per transmission (though in general you would want to consider this using an end-of-file or EOF symbol). This all means you can use the basic approach diagrammed in the table at the top of page 4 in Howard and Vitter’s paper, and not worry about using integer arithmetic or interval expansion. Also, to avoid spending all the time you have working out the necessary software “plumbing”, we’ve provided you with a partially implemented codec: 18 moos-ivp-extend-acomms/src/codecs/arithmetic.cpp moos-ivp-extend-acomms/src/codecs/arithmetic.h The DCCL message CTDMessage you will be sending is defined in moos-ivp-extend-acomms/src/protobuf/ctd.proto A very similar message CTDMessage using the DCCL default codecs is defined in moos-ivp-extend-acomms/src/protobuf/ctd_default.proto and will form the basis of comparison with the arithmetic coder. Finally, we have provided a unit test ctd tester in moos-ivp-extend-acomms/src/ctd_tester/main.cpp that runs a number of encode/decode tests on your arithmetic coder. It checks two deterministic cases: the “best case” (temperature = {10, 10, 10, 10, 10}), and a “worst case” (temperature = {19, 19, 18, 17, 17}). Then it checks ten random sets of temperatures sampled by uniformly placing the vehicle in [0, 100] meters in depth, then reading the value off Fig. 5. Obviously a real vehicle couldn’t do this, but it serves to check our coder’s functionality and performance. To run this unit test: cd moos-ivp-extend-acomms ./build.sh ctd_tester Until you finish the ArithmeticCoder class, ctd tester will assert-fail8 with a message like: ctd_tester: /home/toby/moos-ivp-extend-acomms/src/ctd_tester/main.cpp:97: void run_test(const std::vector<double>&): Assertion ‘msg_in1.SerializeAsString() == msg_out1.SerializeAsString()’ failed. 4.2 Approach This section outlines a step-by-step approach to this problem: 1. Ensure you understand the basics of arithmetic encoding by reading the first two sections of Practical Implementations of Arithmetic Coding by P. Howard and J. Vitter [1]. This was the pre-lab assignment, but it may be helpful to have the paper handy. 2. Given that the vehicle is assumed be uniformly distributed between 0 and 100 meters, as given by 0.01 0 <= d < 100 (2) pD (d) = 0 otherwise where D is the random variable indicating the vehicle’s depth (in meters) below the sea surface. Combining this with the (assumed) deterministic model for temperature over depth 8 Assertions are debugging / testing tool that cause the program to exit with an error message if the contents of the assert macro is false. 19 Table 1: Probability mass function of sampled temperature. Symbol t (temperature) 10 11 12 13 14 15 16 17 18 19 20 pT (t) given in Fig. 5 and Eq. 1 you should fill in Table 1 for the probability mass function for the temperature symbols (random variable T ). Make sure your probabilities sum to one: 20 2 pT (t) = 1 (3) t=10 You may wish to check your values with me before implementing any code. 3. Implement the remaining virtual methods in arithmetic.cpp to finish defining our custom codec ArithmeticCodec: Bitset encode_repeated(const std::vector<goby::int32>& wire_values); std::vector<goby::int32> decode_repeated(const Bitset& bits); unsigned max_size_repeated(); unsigned min_size_repeated(); These functions should be relatively well explained in arithmetic.h. If you are interested, the Doxygen documentation for DCCLRepeatedTypedFieldCodec, giving all the member func­ tions and some brief explanation, is available at http://gobysoft.com/doc/2.0/classgoby_ 1_1acomms_1_1DCCLRepeatedTypedFieldCodec.html. A few notes to avoid unnecessary dif­ ficulty or confusion: • The type goby::int32 is used to make all the behind-the-scenes templating work cor­ rectly (it’s a typedef for google::protobuf::int32 which corresponds to the int32 type in the protobuf file). You can use it like a normal int, which it probably is on your system anyway. • All sizes are in bits (e.g. return value in unsigned max_size_repeated();). There are eight bits to a byte. 20 • unsigned max_size_repeated(); must return an upper bound U (in bits) for the worst case number of bits the encoder will use. In this implementation of the arithmetic encoder, 1 U= + 1 (4) log2 (N pmin ) where N is the number of symbols (five in this case), pmin is the minimum probability of any of the symbols. You may notice that this is almost the number of bits given by the entropy (in an information content sense) of this probability distribution. The lower bound case, unsigned min_size_repeated();, is very similar, except of course it is governed by the most likely outcome. • The type goby::acomms::Bitset is a typedef9 for boost::dynamic_bitset<unsigned char>. The documentation is listed here: http://www.boost.org/doc/libs/1_49_0/libs/ dynamic_bitset/dynamic_bitset.html. To avoid some of the nuisance of learning dynamic_bitset, we’ve provided two helper functions: range_to_bits for encoding the decimal range you will provide and bits_to_range for decoding. • range_to_bits, which is provided for you, converts a double precision std::pair deci­ mal range that is a subset of [0, 1) such as [0.25,0.265625) into the shortest binary frac­ tion that uniquely identifies the range, e.g. 000010. The Bitset output (e.g. 000010) has the least significant bit as the largest fraction (2−1 ) and the most significant bit as the smallest fraction (2−6 ). In regular mathematical notation, this would be written as 0.01000, and means in decimal: 000010 ||||||->0*2^-1 + |||||->1*2^-2 + ||||->0*2^-3 + |||->0*2^-4 + ||->0*2^-5 + |->0*2^-6 --------------0.25 • bits_to_range takes a Bitset generated by range_to_bits and returns the range uniquely identified by that Bitset. Since we are forced to work in whole bits, the returned range from bits_to_range is generally a proper subset (a smaller range) of the original range passed to range_to_bits. For example, if we write the code Bitset bits = range_to_bits(std::make_pair(lower, upper)); std::pair<double, double> result = bits_to_range(bits); std::cout << << << << i << ": " << std::setprecision(15) "in: [" << lower ", " << upper "), out: [" 9 for those new to C++, a typedef is essentially an alias for a type. typedef LongNameType L allows me to use L in place of LongNameType 21 << result.first << "," << result.second << ")" << ", bits: " << bits << std::endl; and run it ten times with random inputs to double lower and double upper, the result looks like: 1: in: [0.224450518947304, 0.272736707829282), out: [0.25,0.265625), bits: 000010 2: in: [0.343518942754492, 0.498916563810276), out: [0.375,0.4375), bits: 0110 3: in: [0.181075460361818, 0.735460476826625), out: [0.25,0.5), bits: 10 4: in: [0.169450353444298, 0.263964024960978), out: [0.1875,0.25), bits: 1100 5: in: [0.478094624578066, 0.73305528551948), out: [0.5,0.625), bits: 001 6: in: [0.796269196922085, 0.977315562766658), out: [0.875,0.9375), bits: 0111 7: in: [0.139742564009383, 0.416557414651177), out: [0.25,0.375), bits: 010 8: in: [0.219583303769856, 0.34400233828649), out: [0.25,0.3125), bits: 0010 9: in: [0.415195364698393, 0.418356456988657), out: [0.416015625,0.41796875), bits: 101010110 10: in: [0.350675355340669, 0.812326993705857), out: [0.5,0.75), bits: 01 Not surprisingly, tighter ranges take more bits to represent. More probable results lead a larger range to encode. Thus, more probable events have smaller encoded sizes, leading to the desired result. • When your method std::vector<goby::int32> decode_repeated(const Bitset& bits); is called, bits only contains the Nmin number of least significant bits required to decode, where Nmin is the value returned by unsigned min_size_repeated();. To get more bits from your parent class (which you will need in all but the best case situation), call the function get_more_bits(unsigned n), where n is the number of bits requested. The requested bits are placed at the most significant end of bits. You must request exactly the number of bits you provided at encode repeated or you will break the encoding and probably throw a std::bad_alloc exception as DCCL tries to pro­ vide more bits than are available. The shell version of ArithmeticCodec provided to you gives an example of how to request the remaining bits and where they are placed. In your final design, you will probably be requesting one bit at a time until you have reached the necessary precision to fully determine the five symbols you encoded. 4. Test your codec using the ctd_tester unit test previously described. The result should look something like: = Begin CTDMessage = Actual maximum size of message: ?? bytes / ??? bits [dccl.id head: 8, user head: 0, ... Allowed maximum size of message: 32 bytes / 256 bits == Begin Header == == End Header == == Begin Body == CTDMessage repeated int32 depth = 1; :: size = 50 bit(s) repeated int32 temperature = 2; :: min size = ?? bit(s) :: max size = ?? bit(s) repeated double salinity = 3; :: size = 55 bit(s) :: min size = ??? bit(s) 22 :: max size = ??? bit(s) == End Body == = End CTDMessage = ****************** BEGIN TEST 0 ******************* In: depth: [12, 13, 14, 13, 13] temperature: [19, 19, 18, 17, 17] salinity: [30.09, 30.1,... Try encode ... Encoded (hex): 660d38f080030e1c94154bfffc0740011210 Size (bytes): ?? Default codec size (bytes): 17 Try decode... Out: depth: [12, 13, 14, 13, 13] temperature: [19, 19, 18, 17, 17] salinity: [30.09, 30.1, ... ***************** PASSED TEST 0 ****************** ****************** BEGIN TEST 1 ******************* In: depth: [12, 13, 14, 13, 13] temperature: [10, 10, 10, 10, 10] salinity: [30.09, 30.1, ... Try encode ... Encoded (hex): 660d38f080030ec03fff0150800404 Size (bytes): ?? Default codec size (bytes): 17 Try decode... Out: depth: [12, 13, 14, 13, 13] temperature: [10, 10, 10, 10, 10] salinity: [30.09, 30.1, ... ***************** PASSED TEST 1 ****************** (... and similar through TEST 11 ...) all tests passed (we’ve added ?? to some places which will be actual numbers in your output). 4.3 Questions Some quick questions for you to consider and hand in with your completed ArithmeticCodec by Thursday April 5. 1. If you run analyze_dccl on ctd_default.proto, you find repeated int32 temperature = 2; :: size = 20 bit(s) How does the size of the encoded message from your arithmetic coder compare to that of the default DCCL encoder? (hint: if the return value from encode_repeated is called data_bits, use std::cout << data_bits.size() << std::endl; to show how many bits your arithmetic encoding takes) Does it always outperform or underperform the default encoder? If not, in which cases does it underperform and in which cases does it overperform? 2. How could you improve the performance of the arithmetic coder even more in this situation (hint: think about the sensor’s sampling process and the AUV’s realistic motion through the water)? 23 References [1] P. Howard and J. Vitter, “Practical implementations of arithmetic coding,” Image and Text compression, pp. 85–112, 1992. [Online]. Available: http://www.gvu.gatech.edu/∼jarek/ courses/7491/Arithmetic2.pdf [2] “Technical guides - speed of sound in sea-water.” [Online]. Available: http://resource.npl.co. uk/acoustics/techguides/soundseawater/ [3] “FastCAT CTD Sensor SBE 49.” [Online]. Available: http://www.seabird.com/products/ spec sheets/49data.htm 24 MIT OpenCourseWare http://ocw.mit.edu 2.S998 Marine Autonomy, Sensing and Communications Spring 2012 For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms.