-
Notifications
You must be signed in to change notification settings - Fork 1
Creating your first telemetry gathering program!
Now that you've installed ArduCOSMOS its time to get started gathering telemetry. In this small project we'll be covering how to set up both the arduino side as well as the COSMOS side for a simple circuit that has an LDR as a sensor we want to get data about. You can replace the LDR with any other data source (like an Inertial Measurement Unit or rotary encoder) you like when you get to your own projects. Our goal will be to analogRead() the value of the LDR and send it off to COSMOS for analysis and graphing.
The first step in almost any arduino project will be setting up the hardware (AKA creating a circuit). We'll keep it simple for now. I'll be using an Arduino Uno, a 10k-Ohm LDR (photoresistor), and a "regular" 10k-Ohm resistor. I'll be wiring them up like this:
Click here to go to the board view (instead of the schematic)
If you want to test whether this works or not you could run the following basic program in an arduino sketch:
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.println(analogRead(0));
delay(100);
}
and moving your hand over your LDR, observing the value lowering when the sensor is in the shade of your hand, and rising when it isn't.
If you already have experience using cosmos, then set up a simple telemetry packet (little endian) with a length, pktid of 0, and a 16 bit UINT variable. Then skip to the interface setup section. For the people who are new to COSMOS, please read this section carefully. COSMOS is a REALLY difficult program, and its configuration can be a huge pain. Anyway, ensure you've downloaded and installed COSMOS using the instructions on the cosmos website.
Now that you've obtained COSMOS, we can create a directory somewhere for this COSMOS project. I personally keep mine in ~/Documents/cosmos_projects
so I can easily find them back at a later point in time, but feel free to use any directory (you have full access to).
Now in this directory, create/initialize a new COSMOS project. I'll be calling my project "light". To do this, first cd into your cosmos projects directory, cd ~/Documents/cosmos_projects
in my case, and then create the project using cosmos install light
. Now we'll want to move into this directory, so lets execute cd light
.
If you are experiencing issues due to the cosmos command not being found, please reboot your computer and/or use the default terminal (in my case on Mac OS X El Capitan the default terminal works fine, but my ZSH iTerm setup doesn't :(. Continue on using this terminal if you experience any further issues).
On Windows you'll likely need to run cosmosenv.bat
in your command prompt first if you're experiencing any issues. This was located in C:\COSMOS\cosmosenv.bat
for me. Please note that I, the author of this project, primarily use Linux and Mac OS. So please feel free to contribute any windows-specific instructions
I'm afraid I won't be covering COSMOS in any real depth, since I consider that outside the scope of this wiki (page). If you at any point in time wish to know more, please refer to COSMOS's official documentation. Furthermore, please don't let COSMOS scare you away, yes....to say it's complex and a pain to get used to would be an understatement, but once you pull through you have a great tool at your fingertips!
Now that that is out of the way, we can get to actually setting up our telemetry packet. To do this, create a new folder in config/targets named LIGHT (must be in ALL-CAPS), and move into this directory ( mkdir config/targets/LIGHT && cd config/targets/LIGHT
). Now we'll need to create a directory in which we store the file containing all of our telemetry and the file containing all of our commands (NOTE: We won't be covering commands yet). The directory in which these files reside is generally called cmd_tlm, and the telemetry file is called tlm.txt. In short, executemkdir cmd_tlm && vim cmd_tlm/tlm.txt
to create the directory and edit the telemetry file (using vim).
In this telemetry file, we can define multiple telemetry entries. A basic telemetry entry will look a lot like this:
TELEMETRY target name LITTLE_ENDIAN "Description Here!"
APPEND_ITEM length 8 UINT "Packet length"
APPEND_ID_ITEM pktid 8 UINT <packetID> "The packet's ID (packetID)"
APPEND_ITEM <someName> <numBits> <type> <description>
...
Now let's dive a little more into this, the first few words, TELEMETRY target name
, let COSMOS know it's dealing with a telemetry packet for the target (directory we created, so that'd be light
in our case) with a given name (can be anything you want that complies with the standard). The line continues on with LITTLE_ENDIAN
, which means that it's expecting the lowest/little
est bytes first. The Arduino is a platform that uses a little endian, and you won't generally need to care about this too much.
The next few lines (that are indented) define a few basic parameters cosmos needs and start defining telemetry variables/parameters. If we look at the last line in our above example, we can see we define parameters by starting with APPEND_ITEM
followed by a name. The name you choose doesn't (generally) tend to matter, however, the order in which these variables are placed needs to EXCACTLY match the order in which you declare them in your arduino. We'll cover this again later in this wiki entry. Moving on to the <numBits> <type>
part we can specify any of the following data types for type:
- INT (Integer)
- UINT (Unsigned Integer)
- FLOAT (Floating Point Value)
- STRING (String / sequence of ASCII characters; NOT IMPLEMENTED BY ArduCOSMOS YET!)
- A few others we won't cover here
And for the numBits we specify the size for these values. The size is in bits, so this means that the Arduino variable uint16_t
, which is 16 bits and has the type of an unsigned integer would be turned in to 16 UINT
. You can find a list of the sizes (in bits) of a few of the more common data types below:
- bool, byte, uint8_t, char, unsigned char (8)
- word, int, unsigned int, uint16_t (16)
- long, float, double (32)
The final part is the description which can be (almost) anything your heart desires.....please make them descriptive though. Also note the special usage of APPEND_ID_PARAMETER
with an extra number added after the type. This is how we set the ID of the packet, and tell COSMOS which ID the packet has (value from 0-255; seen as <packetID>
in the example)
Create a telemetry definition for our example program. You may assume that the value we're storing our LDR sensor's value in is of type uint16_t
, and the packet's ID should be 0. Stuck or want to check your answer? Find my solution at the end of this wiki!
Now that we've declared our telemetry packet, we need to set up our interface. I won't go too in-depth with this, but will outline the more important parts. To define our interface, go back into our config/targets/LIGHT
folder and create/edit the cmd_tlm_server.txt
file.
An interface definition will generally look a lot like the following:
INTERFACE <name>INT serial_interface.rb <targetPort> <targetPort> <baudrate> NONE 1 10.0 nil LENGTH 0 8 0 1
TARGET <name>
In here substitute <name>
with your target's name / what you called your folder (in ALL-CAPS), replace <targetPort>
with the port your arduino is connected to. This will likely be something like /dev/ttyUSB0
on Linux, /dev/cu.usbmodemFD431
on Mac, and COM4
on Windows. This should match up with the Port you selected for your arduino inside of the Arduino IDE. You can also specify the baudrate here. There are more things that can be configured here, but we won't cover those in this wiki entry.
Create an interface definition for our example program. You may assume that we're using a Baud Rate of 9600bps (9600
). If you're feeling stuck or want to compare your solution to mine (that was written for Mac), scroll to the end of the Wiki.
Now that we have the interface set up, we can test our configuration. In order to do this, head into our base project directory (~/Documents/cosmos_projects/light
in my case), and run the Launcher file (./Launcher
in a terminal on Linux/Mac, and Launcher.bat
on Windows). You may need to edit the permissions of the Launcher file on Mac/Linux if you can't launch it or it gives you an error. In order to mark the file as executable, run chmod +x ./Launcher
inside of the directory. If it's complaining about not finding COSMOS, then please check you're using the default terminal/shell (the same as in which you ran cosmos install light
).
You should now be greeted by the COSMOS Launcher screen. This contains a dozen utilities, but for now we'll only open the Command and Telemetry Server
by clicking on it, and pressing OK for the prompt that follows. If all of your configuration files are correct, it shouldn't pop up with any errors. If there are any error windows that pop up, you should compare your configuration files to the ones I have at the bottom of this wiki page.
Now that setting up COSMOS is out of the way, we can move on to setting up the arduino side. Ensure you have installed the ArduCOSMOS library, and (in a new sketch), go to Sketch
> Import Library
> ArduCOSMOS
. This should add #include <arducosmos.h>
to the start of your sketch.
The first thing we'll want to do is declare the packet that we just defined in COSMOS. ArduCOSMOS has an easy macro for doing this. Since we only have one parameter, we'll want to use that version, which results in us wanting to use the DECLARE_TELEMETRY_OneParam
macro.
The first argument that this expects is the name, this is what we'll use to refer to it later. The second argument is the ID of the packet, which needs to match the ID we set up in COSMOS (0 in our case). Next are the variables, these should be in the same order as we set up in COSMOS, but do not need to have the same name. Variables are defined by first passing the type, and then name. An example telemetry packet with an ID of 1 and a single parameter of the type float named testVariable:
DECLARE_TELEMETRY_OneParam(myTelemetry, 1, float, testVariable);
This piece of code is placed before your void Setup()
function. There are also macros for more variables (up to 10), DECLARE_TELEMETRY_TwoParams
to DECLARE_TELEMETRY_TenParams
, which simply add more Type
and Name
parameters.
Declare the telemetry packet for our light telemetry. You may again assume that the ID of the packet is 0
, and the value read from the LDR is stored as a uint16_t
. Feel free to use any name for the telemetry packet and variable you wish. Stuck or want to compare your solution to my solution? Scroll down to the end of the wiki to find my solution.
Now that we've declared the telemetry packet, we need to register it with ArduCOSMOS, and start ArduCOSMOS. First we'll want to decide how often our telemetry packet should be replicated, this needs to be a multiple of 5 (i.e. 5/10/15/20/etc.
) and is a value in milliseconds. There isn't a right answer to what value you should opt for here, but in my case I'll choose 100
which results in a sample rate of approx 10hz (10 samples per second). In order to register telemetry, we use the REGISTER_TELEMETRY
macro, and putting all of this together (substituting <name>
with what you named your telemetry packet), we get:
REGISTER_TELEMETRY(<name>, 100);
Now all that is left is starting COSMOS. This is done by executing ArduCOSMOS::StartCosmos();
. If you haven't started a serial connection (using Serial.begin(baudrate);
) yet, it will automatically start one at 9600
bps. There is also an overloaded version, ArduCOSMOS::StartCosmos(bool bShouldUseCommands);
that, when called with true
passed in, will result in the command module not starting (and thus handling all incoming serial data). We will be using the default one like this:
ArduCOSMOS::StartCosmos();
With that out of the way, all that is left to do is make sure we're reading the value, and ensuring ArduCOSMOS gets to tick. To get the reading we'll be using the standard arduino analogRead(int)
function, but will then also set the value inside of the telemetry packet. To do this, use the below code (substituting <name>
with the name of your telemetry packet, and <variableName>
with the name of the variable you used):
uint16_t sensorValue = analogRead(0);
<name>.<variableName> = sensorValue;
And now to tick ArduCOSMOS, we tick the state system ArduCOSMOS is built upon:
States::Tick();
You should now be ready to test! Ensure your COSMOS Command and Telemetry Server
is closed, or your interface has been disconnected, and upload your sketch to your Arduino.
Once it has uploaded, you can open back up the Command and Telemetry Server
/reconnect, and head to the Tlm Packets
section. You should see the count for the packet you defined go up. If it is (and not the UNKNOWN PACKET
), it means you have successfully set up your telemetry! The next section which covers basic usage of the packet viewer and grapher is optional, but highly recommended if you're new to using COSMOS.
This section will follow soon!
My solution to the telemetry definition exercise:
TELEMETRY light light_status LITTLE_ENDIAN "Telemetry for tracking the brightness of light over time"
APPEND_PARAMETER length 8 UINT "The packet's length"
APPEND_ID_PARAMETER pktid 8 UINT 0 "The packet's ID (0)"
APPEND_PARAMETER value 16 UINT "The value we read from the LDR"
My solution to the interface definition exercise (with my Arduino Uno connected to /dev/cu.usbmodem.FD431
):
INTERFACE LIGHTINT serial_interface.rb /dev/cu.usbmodemFD431 /dev/cu.usbmodemFD431 9600 NONE 1 10.0 nil LENGTH 0 8 0 1
TARGET LIGHT
My solution to the telemetry declaration exercise:
DECLARE_TELEMETRY_OneParam(lightTelemetry, 0, uint16_t, value);
TODO: Test all code!