Unwrapping Sensor Wrappers – Part 2: Graphs

The SIGHTS software suite is designed to be very extensible when it comes to adding new sensors to your robot. We achieve this by using special Python classes called sensor wrappers to collect sensor data, and JavaScript classes called Graphs to display it. SIGHTS is shipped with many useful sensor wrappers for a lot of common sensors, but to use some less common sensors, you may need to write your own wrappers and graphs.

In this blog post, I’ll unpack one of the bundled SIGHTS graphs to show you how you can create your own. If you want to learn how to create a sensor wrapper, check out the previous post in this series.

What is a Graph?

A graph is a JavaScript class that determines how to display sensor data on the interface retrieved from sensors by the SIGHTS host service. A graph extends the Graph class, which implements a few functions standard to all graphs and defines a few more that you need to implement yourself.

Take a look at the Graph class in graph.js (view on GitHub).

constructor(config)

The graph constructor. If there are multiple graphs with the same unique ID we warn the user so they can change one of them.

appendTo(target)

Appends the graph to the target.

update(index, data, name)

Updates the graph when new data is sent from the sensor. This needs to be implemented by the subclass since every type of graph updates differently. We’ll go through an example afterwards.

setup(index, data, name)

This function is used to set up the graph using any initialisation data sent by the sensor wrapper. It’s optional – only required if your graph uses initialisation data such as the “limit” message our Disk Usage sensor wrapper sent (see the get_initial() function definition in the previous blog).

remove()

Removes the graph from the DOM when it is disabled. This is handled completely by the Graph class unless your graph does anything unusual that will need to be removed by the subclass.

Writing a Graph

Now we can write a graph subclass that extends Graph. We’ll go through the circle graph since it’s a good match for the disk usage sensor wrapper we implemented in the last tutorial.

Create your new JavaScript file in thesights/interface/js/graphs directory.

First create the JavaScript class, making sure to extend Graph so we can use the functions it implements in our own graph.

In this class, the first thing we need to do is create the constructor. You should call the superclass’ constructor first.

Now we create the dom_object. This is the HTML we want to be appended to the interface for each instance of our new graph.

The dom_object should begin with a div class with the id attribute set to the graph uid and an extra string such as _graph so that there are no duplicate ID issues if a user gives their graph a uid that is existing. Everything else in the dom_object is up to you and will be specific to the graph you are trying to create. Any object that needs an ID should also use the uid of the graph.

Next up we implement the setup function. As you’ll recall, this is optional, but we need to use it for the circle graph. If you read the previous post in this series you’ll know that the disk usage sensor wrapper we created sends some data during initialisation – specifically, the maximum value the sensor can report (the sensor’s limit). Some graphs ignore this initialisation data because it is not useful to them, but for representing a percentage of a maximum, it is necessary. In the case of a disk usage sensor, it would be the size of the disk. All we need to do is save this data so we can use it in the future.

Finally, we implement the update function.

This is where we use the sensor’s limit we received in setup() so we can calculate the percentage. We prefer the user’s setting if it is provided, otherwise, we use the limit provided by the sensor. If neither of these is provided, we warn the user that they need to set one, since to calculate a percentage we need to know the maximum value. In the meantime, we use 100.

We can use jQuery to select the elements we created in the constructor by ID, and then update it with the new sensor data.

This is all that we require for the circle graph.

Let’s take a quick look at another graph, the thermal camera graph (view on GitHub), to see how other graph functions can be implemented.

The appendTo() function is implemented by Graph, the superclass of all graphs. This means that in most cases, you won’t need to extend this function. The thermal camera graph does this to register interaction events on sliders. You can call the appendTo() function in the superclass to do the rest of the work.

You can do the same thing with the remove() function. In this case, we need to remove any thermal camera overlay from the visible light cameras.

 

Once you’ve completed your graph class, you’ll need to add a few lines of code to sights.sensors.js in sights/interface/js to create a new instance of your graph when required. Find this forEach method:

And add a new if statement for your new graph:

 

The browser also needs to know where the file is to load it, so add it to index.html under the other graphs:

Adding a Graph to the Config Schema

Just like sensors, the configuration of each graph can be slightly different, so it’s helpful to users if you create a config schema that defines how your graph can be configured.

Locate the graphs definition (under interface) in the config schema at sights/interface/js/sights.config.schema.js. Again, like sensors, you will notice that a graph can be “any of” a list of graphs. All you need to do is add your graph with its configuration values to the list of options.

Below is an example for the circle graph we created above.

Contributing your Own Graph to SIGHTS

If you’ve created a graph that’s not included with SIGHTS, in the spirit of open source collaboration, we’d love to include it in the official SIGHTS repository! The process is simple:

  1. Fork the repository at https://github.com/SFXRescue/sights
  2. Make your changes on your fork (add your new graph and its config schema!)
  3. Submit a pull request with your additions.

It’s generally easier to focus on one feature per pull request, so if you have other unrelated changes you want to propose or you have multiple graphs to contribute, please consider making separate pull requests for each.

Further Reading

You can read the documentation about extending SIGHTS. Documentation is available offline when you install SIGHTS and is accessible through the interface. If you haven’t installed SIGHTS, you can still access this online at GitHub.

If there are major changes to the function of sensor wrappers and graphs, you may need to refer to the most up-to-date documentation at https://github.com/SFXRescue/sights/blob/master/docs/extending.md.

If the process for creating a sensor wrapper or graph changes significantly enough, we may post a new tutorial as well.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.