DIY video monitoring system, Node.js, Raspberry Pi

DIY video monitoring system – Part VI Servo control with WebSockets

Previously we’ve learned how to use Node.js’s pigpio and keypress modules to control a servo with keyboard. This time, we’ll reuse some of that knowledge to control our servo over the network.

This is a follow-up to Part V of my DIY video monitoring system project. Make sure you check it out first!

Being able to control a servo attached to our Raspberry Pi using keyboard is definitely cool and can lead to some cool implementations. We, however, have to keep in mind the goal of this cycle, which is creating a fully-featured monitoring system that can be accessed from anywhere AND controlled over the Internet. The last part means we need a way to communicate with our Node script from e.g. a web browser in real-time. This is where WebSockets come to the rescue!


WebSocket is a communication protocol allowing for real-time interactive communication between a client browser and a server. It uses a single TCP connection to create a full-duplex communication channel. The connection starts with a handshake over HTTP, gets upgraded to WebSocket and remains open making it possible for the server to send messages to the browser without being solicited by the client.

WebSocket is already a well established technology with support in all modern web browsers.


For this example we’ll write a simple page that lets us control the pan/tilt head from the previous post. This means our Node application will have to do the following:

  • serve a static control panel page
  • accept WebSocket connections
  • control pan/tilt servos

For the first two things we’re going to use two handy Node modules – Express and For the third one, we’ll refactor the servo.js script from the previous post.

The final code structure will look like this:


Express is a fast, fully-featured web framework for Node.js. It’s flexible, with tons of built-in HTTP utility methods it let’s you create RESTful API and can be extended middlewares.

One of built-in Express middlewares we’re going to use in this project is express.static. It allows to easily serve static assets like stylesheets, scripts or HTML files. We’ll get to that in a second.

To make use of Express in our script let’s install it using NPM:

Another Node module we’ll use for this example is Using WebSockets under the hood, it provides an event-based, bi-directional, real-time communication between your Node.js app and client browsers.

We’ll install it just like any other Node module:

Servo module

Now that we have all additional dependencies installed, let’s refactor our servo.js script.

In theprevious example we’ve used pigpio and keypress modules to implement a simple, keyboard-controlled pan/tilt head. For this example, we can remove the keyboard-related code. We’ll also turn that script into a reusable module exposing a PanTilt class that will be used in the HTTP server module later.

Our module will need to be configurable as we need to set our servos’ GPIO pins and minimum and maximum pulse widths. It also needs to expose some methods to change our servos’ positions and retrieve their current state. The latter will come in handy for the case where the client reconnects to the server and wants to update the UI to reflect the servos’ current state.

Finally, to make the use of our PanTilt class easier, its methods will accept servo positions given as percentage of their ranges – values from 0 to 100.

Here’s what my implementation looks like:

Apart from the getters and setters we talked about earlier, it contains some helper methods simplifying value conversion between pulse widths and percents.

HTTP Server

Now, let’s move to the server script. Let’s name it – you guessed it right – server.js. Here, we’re going to use the two libraries mentioned earlier in this chapter – Express and

We’ll start with loading and instantiating them. Then, we’ll attach them to the Node’s HTTP server:

Then, we’ll create and instance of our PanTilt class and define some constants for the server:

The final setup stage will be initializing Express’s static middleware to serve all the assets located in the public directory:

With all the initial setup done, we can configure our WebSockets. We’ll handle the client’s connect and disconnect events, we’ll accept its rotate requests and, finally, send him the pan/tilt head’s position once the connection gets established.

Finally, we need to start our HTTP server:

Here’s the final server script:

Client code

Now that the server side is done, we can move to the client code. We’ll create a basic control panel that will display the WebSocket connection status and provide a box with a handle that will control our servos when dragged with mouse pointer. Our simple control panel will consist of 3 parts – an HTML template, a piece of client script and a bit of CSS.

Let’s start with index.html, where we load all the styles and scripts and prepare the template for our simple UI:

A notable thing here is the second to last script that we load:

It contains the client part for and is automatically hosted by our HTTP server once we attach to it.

Time for the client script – script.js – where we’ll initialize WebSockets, configure them and implement some user interactions and UI updates:

Finally, a piece of CSS to style the UI appropriately – style.css:


Let’s try out the code we wrote. Keep in mind that in order to use PWM on Raspberry Pi GPIOs, we need to run the script with root privileges:

To move the servos, just click and drag the blue dot. Here’s a short clip showing how this works:


In this post we’ve learned:

  • How to use Express to serve static files
  • How to use along with Express
  • How to combine that with pigpio to control servos

As always, the complete code for this example is available on Github.

In the next part we’ll try to combine all we’ve learned so far and connect the pan/tilt code with our MJPEG streaming code.

Stay tuned!

by Greg

1 Comment »

One thought on “DIY video monitoring system – Part VI Servo control with WebSockets”

Leave a Reply

Your email address will not be published. Required fields are marked *

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

We are using Google Analytics

Please confirm, if you accept our Google Analytics tracking. You can also decline the tracking, so you can continue to visit our website without any data sent to Google Analytics.