Code Notes - UCSD-E4E/Wolf-Tracker-2014 GitHub Wiki

Code Notes

Some important things to note is how the entire system is configured: what ports are used, file structures, scripts that startup, etc. The following topics are covered:

Nginx (web server/web proxy config)

Nginx was installed onto the BeagleBone using apt-get, the config file for the project is as follows:

Nginx config file

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  root /usr/share/nginx/html;
  index index.html index.htm;

  server_name localhost;

  location /node_eats {
    proxy_redirect      off;
    proxy_set_header    Host            $host;
    proxy_pass          http://127.0.0.1:8124;
  }

  location / {
    try_files $uri $uri/ =404;
  }
}

The Nginx config file is located at /usr/share/ngix/sites-available/default. The first part of the script:

listen 80 default_server;
listen [::]:80 default_server;

root /usr/share/nginx/html;
index index.html index.htm;

server_name localhost;

simply sets up an ordinary web server listening on port 80. The files that the web server shows up are located at /usr/share/nginx/html. This means that if we go to the website over our connection we would be seeing the webpage located at /usr/share/nginx/html/index.html which is the default webpage that Nginx starts with. Nginx is a great tool for web development and in this project in particular since AJAX data can be redirected to a server at a different subnet. Here:

location /node_eats {
  proxy_redirect      off;
  proxy_set_header    Host            $host;
  proxy_pass          http://127.0.0.1:8124;
}

We are setting up a proxy to pass through any requests for /node_eats to our local server listening on port 8124. The rest of the config file:

location / {
  try_files $uri $uri/ =404;
}

just lets us access webpages normally.

NodeJS Installation Notes

NodeJS is a wonderful tool that can be installed on the BeagleBone without much effort. One of the difficulties found was internet connectivity issues when clone large files using git or even using wget. Before starting downloading sudo su was run to properly configure node globally.

Step 1: Prerequisites

First, the pre-requisites were installed:

sudo apt-get install python
sudo apt-get install build-essential

Step 2: Download and SCP

To get around this NodeJS was downloaded locally and SCP'ed over to the BeagleBone to be properly configured and installed. NodeJS was downloaded using:

wget http://nodejs.org/dist/v0.10.5/node-v0.10.5.tar.gz
scp node-v0.10.5.tar.gz ubuntu@<address of BeagleBone>

Step 3: Configure

After SCP'ing the the Node tarball to the BeagleBone, the file was untarred and configured:

tar xzvf node-v0.10.5.tar.gz
cd node-v0.10.5
./configure --without-snapshot

Step 4: Compile

NodeJS was then compiled. It takes a long time to compile so go take a nap or watch some anime for a bit.

make

Step 5: Verify and Install

Lastly we check to make sure it is installed correctly. Run

./node -e 'console.log("It worked!");'

If this runs correctly then install it.

make install

##NodeJS Server Code

NodeJS was used as the middle man communicator between the web interface front-end and the arudino microcontroller. The following script runs at boot scheduled by crontab along with the following bash script that enables the serial port to the Arduino on boot:

Enabling Serial

#!/bin/bash
#MiddleMan.sh
#Enable UART (Serial) Communication on Boot

#wait 5 seconds to make sure everything is started on the Beagle Bone
sleep (5)

#this line enables UART1 on the the Beagle Bone and sets up the device tree automagically
echo BB-UART1 > /sys/devices/bone_capemgr.*/slots

#This sets up the speed of the serial communication to the Arduino
stty -F /dev/ttyO1 57600

NodeJS server script

//serverWSerial.js
var http = require('http');
var fs = require('fs');

//set up the serial port
var SerialPort = require("serialport").SerialPort;
var serialport = new SerialPort("/dev/ttyO1", {
    baudrate: 57600
});

//opens the serial port for us to use
serialport.on('open', function(){
});

function sendToArduino(data){
    for(var i = 0; i < data.length; i++){
        serialport.write(data.charAt(i));
    }
    serialport.write('\n');
}

//create the server
http.createServer(function(req,res){
  if(req.method == 'POST'){
    var body = '';
    req.on('data',function(data){
      body += data;
    });
    req.on('end',function(){
      var OBJ = JSON.parse(body);
      var stringData =  "L:" + OBJ.leftStick.toFixed(2) + "|" +
                        "R:" + OBJ.rightStick.toFixed(2) + ";";
      sendToArduino(stringData);

    });
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('post recieved');
  } else {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello Node.js\n');
  }
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

Including required modules

The first part of the code:

var http = require('http');
var fs = require('fs');

//set up the serial port
var SerialPort = require("serialport").SerialPort;

tells Node what modules are required to be installed and used. The modules used in this project were fs, http, and serialport. The serialport module was installed with the following using npm:

npm install serialport

Opening Serialport

The next part of the code sets up a new serial port with a baudrate of 57600 and opens it:

var serialport = new SerialPort("/dev/ttyO1", {
    baudrate: 57600
});

//opens the serial port for us to use
serialport.on('open', function(){
});

Server setup

The next part is a helper function which is describe later in this section. The helper function is followed by the nodeJS server code. The node server is setup with using the http.createServer() function. createServer() takes in a function that uses req and res (you could have them named request and response for greater readibility) where req is the HTTP request that was sent to the server. The listen(<port>,<ip address>) at the end of the createServer function specifies the port and IP the server will listen to. Here we are listening to port 8124 on our localhost.

http.createServer(function(req,res){
  ...
  //code here
  ...
}).listen(8124, "127.0.0.1");

Check for POST

The server first checks if it is a POST request and proccesses the data accordingly. If a POST request was not sent, we still send a response back acknowledging that the server did recieve some kind of request.

if(req.method == 'POST'){
  ...
  //code to send to arduino
  ...

  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('post recieved');
} else {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Node.js\n');
}

When a POST request is sent to the server the data is parsed. Sometimes when data is sent to the server it is not all sent at once and is sent incrementally which is the reason for the req.on('data', <function>);.Here we add the string data that was sent to our temporary variable body until we finish recieving the data which happens in the req.on('end',<function>).

Writing to Arduino

var body = '';
req.on('data',function(data){
  body += data;
});

req.on('end',function(){
  var OBJ = JSON.parse(body);
  var stringData =  "L:" + OBJ.leftStick.toFixed(2) + "|" +
                    "R:" + OBJ.rightStick.toFixed(2) + ";";

  sendToArduino(stringData);
});

The data is then parsed using JSON.parse and saved to local variable OBJ. By using JSON.parse(<data>), the data inside the JSON object can be accessed using the variable names sent (leftStick and rightStick). The format that is sent to the Arduino is L:<left stick value>|R:<right stick value>; where each stick value is preceeded by an 'L' or 'R', representing the individual sticks and further separated with a '|'. Lastly, the send string is finalized with a ';' which acts as the end of string delimeter. A helper function was used called sendToArduino(<data>) to send the string to the arduino.

sendToArduino()

function sendToArduino(data){
    for(var i = 0; i < data.length; i++){
        serialport.write(data.charAt(i));
    }
    serialport.write('\n');
}

The sendToArduino() function is necessary because only a single char can be sent to the Arduino for the data to be reliably sent. If the entire string is sent with serialport.write(), the data recieved is incorrect except for the first character. The sendToArduino() function simply splits up the data and sends the string char by char and finally writes out a newline character '\n'. The newline character is sent because the arduino sets up a blocking call for a newline-character terminated string before using the data.

mjpg_streamer

mjpg_streamer was used to stream the camera video to the website.

Step 1: Prerequisites

First, the pre-requisites were installed:

sudo apt-get install g++ curl pkg-config libv4l-dev libjpeg-dev build-essential libssl-dev vim cmake
sudo apt-get install imagemagick

Step 2: Download and untar

wget https://github.com/shrkey/mjpg-streamer/raw/master/mjpg-streamer.tar.gz
tar -xvf ./mjpg-streamer.tar.gz

Step 3: compile and install

cd mjpg-streamer
make
make install

Step 5: Verify and Install

Lastly we check to make sure it is installed correctly. Run

sudo ./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"

MJPG Streamer Version: svn rev:
    i: Using V4L2 device.: /dev/video0
    i: Desired Resolution: 640 x 480
    i: Frames Per Second.: 5
    i: Format............: MJPEG
    o: www-folder-path...: ./www/
    o: HTTP TCP port.....: 8080
    o: username:password.: disabled
    o: commands..........: enabled

mjpg-streamer sends the jpg images from the camera and broadcasts it at 127.0.0.1:8080, which if you configure it correctly lets video be seen at that address. (For example, if the Beagle Bone's address is 192.168.7.2 which it is automatically configured to if Network Setup instructions were followed. The video can be seen when the wolftracker page is opened up).

⚠️ **GitHub.com Fallback** ⚠️