Please note that User Registration has been temporarily disabled due to a recent increase in automated registrations. If anyone needs an account, please request one here: RequestAccount. Thanks for your patience!--Wmat (talk)
Please email User:Wmat if you experience any issues with the Request Account form.

Difference between revisions of "SparkFun: ITG-3200,Triple-Axis Gyro Display"

From eLinux.org
Jump to: navigation, search
(Code)
(Node.js Code)
 
(15 intermediate revisions by the same user not shown)
Line 12: Line 12:
  
 
[[File:ITG3200Bone2.jpg|thumb|ITG-3200 breakout board pin-out]]
 
[[File:ITG3200Bone2.jpg|thumb|ITG-3200 breakout board pin-out]]
 +
 +
[[File:BoneGyroDemo1.png|thumb|Here's the first display screen you will see after entering the bones web address, go ahead and click on the Button Dox Demo link]]
 +
 +
[[File:BoneGyroDemo2.png|thumb|left|Once the script is up and running you will begin to see the sensor data rendered across the time axis plots with regards to each rotational direction of the gyroscope as well as its internal temperature]]
  
 
== Introduction ==
 
== Introduction ==
Line 18: Line 22:
 
; buttonBox.js, buttonBox.html
 
; buttonBox.js, buttonBox.html
 
: This is a bone-based example that reads a gpio port, analog in and an i2c device and displays the output in a web browser.These will be there two main files that will contain many of my alterations.
 
: This is a bone-based example that reads a gpio port, analog in and an i2c device and displays the output in a web browser.These will be there two main files that will contain many of my alterations.
 
  
 
== Running the code ==
 
== Running the code ==
Line 28: Line 31:
 
On the Bone:
 
On the Bone:
 
  beagle$ '''node buttonBox.js'''
 
  beagle$ '''node buttonBox.js'''
 +
 +
Simply press ‘CTRL’ + ‘C’ to quit the program.
  
 
===Connecting to the Bone===
 
===Connecting to the Bone===
  
 
Then point a browser to '''beaglebone.local:8081'''.  The default port is 8081.  You can change it if you like.
 
Then point a browser to '''beaglebone.local:8081'''.  The default port is 8081.  You can change it if you like.
 
  
 
== How it works ==
 
== How it works ==
Line 47: Line 51:
  
 
The code shown below is part sample code to demonstrate reading the registers via I2C and displaying the data with node.js. The alteration that has been made is to specify a timeout period for the server, as well as an additional function that will execute the terminal commands required to poll the gyroscopic sensor in return its register values. The code will also zero out the gyro to account for the internal bias the gyro might have just being stationary and level.
 
The code shown below is part sample code to demonstrate reading the registers via I2C and displaying the data with node.js. The alteration that has been made is to specify a timeout period for the server, as well as an additional function that will execute the terminal commands required to poll the gyroscopic sensor in return its register values. The code will also zero out the gyro to account for the internal bias the gyro might have just being stationary and level.
 +
 +
One alteration you'll need to make is to change the path the exec function with in the pushMessage function calls the custom c program to read the I2C buss. Just change the path to point to the excusable you compile with gcc using available MiniProject02.c file within the same directory as the HTML and node.js files, all the necessary header files are included as well. 
  
 
<pre>
 
<pre>
/*
+
// From Getting Started With node.js and socket.io
* MiniProject02.c
+
// http://codehenge.net/blog/2011/12/getting-started-with-node-js-and-socket-io-v0-7-part-2/
*
+
"use strict";
*  Created on: Sep 20, 2012
+
*      Author: Ruffin White
+
*/
+
  
#include "Header.h"
+
var http = require('http'),
#include <stdio.h>
+
    url = require('url'),
#include <stdlib.h>
+
    fs = require('fs'),
#include <string.h>
+
    exec = require('child_process').exec,
#include <unistd.h>
+
    server,
#include <fcntl.h>
+
    connectCount = 0; // Number of connections to server
#include <poll.h>
+
#include <signal.h>
+
#include "ITG-3200.h"
+
  
int loop=1;
+
server = http.createServer(function (req, res) {
 +
// server code
 +
    var path = url.parse(req.url).pathname;
 +
    console.log("path: " + path);
 +
    switch (path) {
 +
    case '/':
 +
        res.writeHead(200, {'Content-Type': 'text/html'});
 +
        res.write('<h1>Hello!</h1>Try<ul><li><a href="/buttonBox.html">Button Box Demo</a></li></ul>');
  
 +
        res.end();
 +
        break;
  
void signal_handler(int sig)
+
    default: // This is so all the files will be sent.
{
+
        fs.readFile(__dirname + path, function (err, data) {
printf( "Ctrl-C pressed, cleaning up and exiting..\n" );
+
            if (err) {return send404(res); }
loop = 0;
+
//            console.log("path2: " + path);
}
+
            res.write(data, 'utf8');
 +
            res.end();
 +
        });
 +
        break;
  
int main(int argc, char** argv){
+
    }
 +
});
  
//variable declarations
+
var send404 = function (res) {
struct pollfd fdset[1];
+
    res.writeHead(404);
int nfds = 1;
+
    res.write('404');
int timeout = 100;
+
    res.end();
int rc;
+
};
char* buf[MAX_BUF];
+
int gpio1, gpio2;
+
int gpio1_fd, gpio2_fd;
+
int gpio2_value = 0;
+
int pattern =0;
+
int value =0;
+
  
int freq = 10;
+
server.listen(8081);
int duty = 25;
+
  
short int gyroID, gyroTemp, gyroX, gyroY, gyroZ;
+
// socket.io, I choose you
 +
var io = require('socket.io').listen(server);
 +
io.set('log level', 2);
  
// I2C Variables
+
// on a 'connection' event
char *end;
+
io.sockets.on('connection', function (socket) {
int res, i2cbus, address, size, file;
+
    var frameCount = 0; // Counts the frames from arecord
int daddress;
+
    var lastFrame = 0; // Last frame sent to browser
 +
    console.log("Connection " + socket.id + " accepted.");
 +
//    console.log("socket: " + socket);
  
//check that at least two arguments are passed in
+
    // now that we have our connected 'socket' object, we can
if(argc < 4){
+
    // define its event handlers
printf("Usage: %s <input-gpio> <output-gpio> <i2c-bus>\n", argv[0]);
+
printf("polls input-gpio, and writes value to output-gpio\n");
+
fflush(stdout);
+
return 1;
+
}
+
  
 +
    // Make sure some needed files are there
 +
    // The path to the analog devices changed from A5 to A6.  Check both.
 +
    var ainPath = "/sys/devices/platform/omap/tsc/";
 +
//    if(!fs.existsSync(ainPath)) {
 +
//        ainPath = "/sys/devices/platform/tsc/";
 +
//        if(!fs.existsSync(ainPath)) {
 +
//            throw "Can't find " + ainPath;
 +
//        }
 +
//    }
 +
    // Make sure gpio 7 is available.
 +
    exec("echo 7 > /sys/class/gpio/export");
 +
   
  
//set signal handler for Ctrl + C
+
    // Send value every time a 'message' is received.
if (signal(SIGINT, signal_handler) == SIG_ERR)
+
    socket.on('ain', function (ainNum) {
printf("\ncan't catch SIGINT\n");
+
//        var ainPath = "/sys/devices/platform/omap/tsc/ain" + ainNum;
 +
        fs.readFile(ainPath + "ain" + ainNum, 'base64', function(err, data) {
 +
            if(err) throw err;
 +
            socket.emit('ain', data);
 +
//            console.log('emitted ain: ' + data);
 +
        });
 +
    });
  
//assign gpio values
+
    socket.on('gpio', function (gpioNum) {
gpio1 = atoi(argv[1]);
+
        var gpioPath = "/sys/class/gpio/gpio" + gpioNum + "/value";
gpio2 = atoi(argv[2]);
+
        fs.readFile(gpioPath, 'base64', function(err, data) {
 +
            if (err) throw err;
 +
            socket.emit('gpio', data);
 +
//            console.log('emitted gpio: ' + data);
 +
        });
 +
    });
  
 +
    socket.on('i2c', function (i2cNum) {
 +
//        console.log('Got i2c request:' + i2cNum);
 +
        exec('i2cget -y 3 ' + i2cNum + ' 0 w',
 +
            function (error, stdout, stderr) {
 +
// The TMP102 returns a 12 bit value with the digits swapped
 +
                stdout = '0x' + stdout.substring(4,6) + stdout.substring(2,4);
 +
//                console.log('i2cget: "' + stdout + '"');
 +
                if(error) { console.log('error: ' + error); }
 +
                if(stderr) {console.log('stderr: ' + stderr); }
 +
                socket.emit('i2c', stdout);
 +
            });
 +
    });
  
//assign I2C values
+
    socket.on('led', function (ledNum) {
i2cbus  = atoi(argv[3]);
+
        var ledPath = "/sys/class/leds/beaglebone::usr" + ledNum + "/brightness";
address  = ITG3200_I2C_ADDRESS;
+
//        console.log('LED: ' + ledPath);
file = initialize(i2cbus, address);
+
        fs.readFile(ledPath, 'utf8', function (err, data) {
zeroGyro(file);
+
            if(err) throw err;
 +
            data = data.substring(0,1) === "1" ? "0" : "1";
 +
//            console.log("LED%d: %s", ledNum, data);
 +
            fs.writeFile(ledPath, data);
 +
        });
 +
    });
  
 +
  var updateInterval = 100;
 +
  function pushMessage() {
 +
//        console.log('Got i2c request:' + 6);
 +
        exec('/home/root/ECE497/MiniProject04/node.js/realtime/./a.out 0 0 ' + 3,
 +
            function (error, stdout, stderr) {
 +
console.log('stdout:' + stdout);
 +
//console.log('stdout:' + parseFloat(stdout.substring(51,58))/100.0);
 +
                if(error) { console.log('error: ' + error); }
 +
                if(stderr) {console.log('stderr: ' + stderr); }
 +
                socket.emit('i2c', stdout);
 +
            });
 +
        setTimeout(pushMessage, updateInterval);
 +
    }
 +
    pushMessage();
  
//argument 1 will be input
 
export_gpio(gpio1);
 
set_gpio_direction(gpio1, "in");
 
set_gpio_edge(gpio1, "falling");
 
gpio1_fd = gpio_fd_open(gpio1);
 
  
//argument 2 will be output
+
    socket.on('disconnect', function () {
export_gpio(gpio2);
+
        console.log("Connection " + socket.id + " terminated.");
set_gpio_direction(gpio2, "out");
+
        connectCount--;
set_gpio_value(gpio2, gpio2_value);
+
        if(connectCount === 0) {
gpio2_fd = gpio_fd_open(gpio2);
+
        }
 +
        console.log("connectCount = " + connectCount);
 +
    });
  
set_mux_value("gpmc_a2",6);
+
    connectCount++;
 +
    console.log("connectCount = " + connectCount);
 +
});
  
 +
</pre>
  
while(loop){
+
=== HTML Code ===
memset((void*)fdset, 0, sizeof(fdset));
+
  
fdset[0].fd = gpio1_fd;
+
This file is altered from example code and contains all the necessary formatting for the user interface and data representation. A also contains the script necessary to parse the string containing the sensor data sent by the server.
fdset[0].events = POLLPRI;
+
  
rc = poll(fdset, nfds, timeout);
+
<pre>
 +
<!doctype html>
 +
<html>
 +
  <head>
 +
    <title>Gyro Demo</title>
  
if (rc < 0){
+
    <script src="/json.js"></script> <!-- for ie -->
printf("\npoll() failed!\n");
+
    <script src="/socket.io/socket.io.js"></script>
}
+
  
if (rc == 0){
+
    <link href="layout.css" rel="stylesheet" type="text/css">
printf(".");
+
    <script src="jquery.js"></script>
}
+
    <script src="jquery.flot.js"></script>
 +
    <script src="jquery.flot.navigate.js"></script>
 +
  </head>
 +
  <body>
 +
    <h1>Gyro Demo <a href="http://Rose-Hulman.edu" target="_blank">
 +
        <img src="RoseLogo96.png" width=200 style="float:right"></a></h1>
 +
    <button id="connect" onClick='connect()'/>Connect</button>
 +
    <button id="disconnect" onClick='disconnect()'>Disconnect</button>
 +
    <span style="position:relative; left:150px">
 +
    Analog: <input id="ainNum" type="text" value="" style="text-align: right; width:2em">
 +
    gpio: <input id="gpioNum" type="text" value="" style="text-align: right; width:2em">
 +
    i2c: <input id="i2cNum" type="text" value="" style="text-align: right; width:3em">
 +
    </span>
 +
<!--    <button id="send" onClick='send()'/>Send Message</button> -->
 +
<table>
 +
<tr>
 +
    <td><div id="plotTop" style="width:550px;height:300px;"></div>
 +
<center>samples</center></td>
 +
<td>
 +
    Update: <input id="updateTopInterval" type="text" value="" style="text-align: right; width:3em"> ms
 +
    <button id="zoomout" onClick='plotTop.zoomOut()'>Zoom Out</button>
 +
</td>
 +
</tr>
 +
<tr>
 +
    <td><div id="plotBot" style="width:550px;height:300px;"></div>
 +
<center>samples</center></td>
 +
<td>
 +
    Update: <input id="updateBotInterval" type="text" value="" style="text-align: right; width:3em"> ms
 +
    <button id="zoomout" onClick='plotBot.zoomOut()'>Zoom Out</button>
 +
</td>
 +
</tr>
 +
</table>
 +
<button id="led0" onClick='led(0)'/>LED 0</button>
 +
<button id="led1" onClick='led(1)'/>LED 1</button>
 +
<button id="led2" onClick='led(2)'/>LED 2</button>
 +
<button id="led3" onClick='led(3)'/>LED 3</button>
 +
<p>
  
if((fdset[0].revents & POLLPRI) == POLLPRI) {
+
<b>Button Box demo from the <a href="http://elinux.org/index.php?title=Category:ECE497" target="_blank">32-bit Embedded Linux Class</a>.</b>
read(fdset[0].fd, buf, MAX_BUF);
+
In this demo, the beagle bone pushes it sensor data to the web browser. Try moving the gyro or touching it to change its temprature. Try double-clicking to zoom and click and dragging to pan.
printf("interrupt value=%c\n", buf[0]);
+
</p>
pattern++;
+
    <a href="http://beagleboard.org" target="_blank">
if(pattern == 4){
+
        <img src="beagle-hd-logo.gif" width=200 align="right"></a>
pattern = 0;
+
    <div><p id="status">Waiting for input</p></div>
}
+
    <a href="http://www.ti.com/sitara" target="_blank">
}
+
        <img src="hdr_ti_logo.gif" width=200 align="right"></a>
 +
    <div><p id="message">message</p></div>
 +
By <i>Ruffin White</i>
 +
<br/>
  
switch(pattern){
+
    <script>
  
// blink led
+
    var socket;
case 0:
+
    var firstconnect = true,
printf("Case 0\n");
+
        fs = 8000,
value = read_ain("ain6");
+
        Ts = 1/fs*1000,
printf("Voltage: %d\n",value);
+
        samples = 100,
set_pwm("ehrpwm.1:0",10,25);
+
        plotTop,
if(gpio2_value){
+
        plotBot,
gpio2_value = 0;
+
        ainData = [],  iain = 0,
}
+
        gpioData = [], igpio = 0,
else{
+
        i2cXData = [],  ii2cX = 0,
gpio2_value = 1;
+
        i2cYData = [],  ii2cY = 0,
}
+
        i2cZData = [],  ii2cZ = 0,
set_gpio_value(gpio2, gpio2_value);
+
        i2cTData = [], ii2cT = 0,
break;
+
        gpioNum = 7,
 +
        ainNum  = 6,
 +
        i2cNum  = "0x48";
 +
    ainData[samples] = 0;
 +
    gpioData[samples] = 0;
 +
    i2cXData[samples] = 0;
 +
    i2cYData[samples] = 0;
 +
    i2cZData[samples] = 0;
 +
    i2cTData[samples] = 0;
  
//PWM output
+
    function connect() {
case 1:
+
      if(firstconnect) {
printf("Case 1\n");
+
        socket = io.connect(null);
  
gyroID = readWhoAmI(file);
+
        socket.on('message', function(data)
 +
            { status_update("Received: message");});
 +
        socket.on('connect', function()
 +
            { status_update("Connected to Server"); });
 +
        socket.on('disconnect', function()
 +
            { status_update("Disconnected from Server"); });
 +
        socket.on('reconnect', function()
 +
            { status_update("Reconnected to Server"); });
 +
        socket.on('reconnecting', function( nextRetry )
 +
            { status_update("Reconnecting in " + nextRetry/1000 + " s"); });
 +
        socket.on('reconnect_failed', function()
 +
            { message("Reconnect Failed"); });
  
printf("gyroID: %6d\n", gyroID);
+
        socket.on('ain', ain);
break;
+
        socket.on('gpio', gpio);
 +
        socket.on('i2c',  i2c);
  
//Read Gyro Temperature
+
        firstconnect = false;
case 2:
+
      }
printf("Case 2\n");
+
      else {
 +
        socket.socket.reconnect();
 +
      }
 +
    }
  
gyroTemp = readTemp(file);
+
    function disconnect() {
 +
      socket.disconnect();
 +
    }
  
printf("gyroTemp: %6d\n", gyroTemp);
+
    function led(ledNum) {
break;
+
        socket.emit('led', ledNum);
 +
    }
  
//Read Gyro XYZ
+
    // When new data arrived, convert it and plot it.
case 3:
+
    function ain(data) {
printf("Case 3\n");
+
        data = atob(data)/4096 * 1.8;
 +
        data = isNaN(data) ? 0 : data;
 +
//        status_update("ain: " + data);
 +
        ainData[iain] = [iain, data];
 +
        iain++;
 +
        if(iain >= samples) {
 +
            iain = 0;
 +
            ainData = [];
 +
        }
 +
        plotTop.setData([ ainData, gpioData ]);
 +
        plotTop.draw();
 +
    }
  
gyroX = readX(file);
+
    function gpio(data) {
gyroY = readY(file);
+
        data = atob(data);
gyroZ = readZ(file);
+
//        status_update("gpio: " + data);
 +
        gpioData[igpio] = [igpio, data];
 +
        igpio++;
 +
        if(igpio >= samples) {
 +
            igpio = 0;
 +
            gpioData = [];
 +
        }
 +
        plotTop.setData([ ainData, gpioData ]);
 +
        plotTop.draw();
 +
    }
 +
//gyroX: -00026 gyroY: -00012 gyroZ: 000073 gyroTemp: 002602
  
printf("gyroX: %6d\n", gyroX);
+
    function i2c(data) {
printf("gyroY: %6d\n", gyroY);
+
        Xdata = parseInt(data.substring(6,12));
printf("gyroZ: %6d\n", gyroZ);
+
        Ydata = parseInt(data.substring(20,26));
break;
+
        Zdata = parseInt(data.substring(34,40));
 +
        Tdata = parseInt(data.substring(51,56));
 +
        i2cXData[ii2cX] = [ii2cX, Xdata];
 +
        i2cYData[ii2cY] = [ii2cY, Ydata];
 +
        i2cZData[ii2cZ] = [ii2cZ, Zdata];
 +
        i2cTData[ii2cT] = [ii2cT, Tdata];
 +
        ii2cX++;
 +
        if(ii2cX >= samples) {
 +
            ii2cX = 0;
 +
            i2cXData = [];
 +
        }
 +
        i2cXData[ii2cY] = [ii2cY, Xdata];
 +
        ii2cY++;
 +
        if(ii2cY >= samples) {
 +
            ii2cY = 0;
 +
            i2cYData = [];
 +
        }
 +
        i2cXData[ii2cZ] = [ii2cZ, Xdata];
 +
        ii2cZ++;
 +
        if(ii2cZ >= samples) {
 +
            ii2cZ = 0;
 +
            i2cZData = [];
 +
        }
 +
        i2cXData[ii2cT] = [ii2cT, Xdata];
 +
        ii2cT++;
 +
        if(ii2cT >= samples) {
 +
            ii2cT = 0;
 +
            i2cTData = [];
 +
        }
 +
        plotBot.setData([ i2cXData, i2cYData, i2cZData]);
 +
        plotBot.draw();
 +
        plotTop.setData([ i2cTData ]);
 +
        plotTop.draw();
 +
    }
  
default:
+
    function status_update(txt){
break;
+
      document.getElementById('status').innerHTML = txt;
}
+
    }
}
+
close(file);
+
gpio_fd_close(gpio1_fd);
+
gpio_fd_close(gpio2_fd);
+
unexport_gpio(gpio1);
+
unexport_gpio(gpio2);
+
fflush(stdout);
+
return 0;
+
}
+
</pre>
+
  
=== Screen Shots ===
+
    function send(){
 +
      socket.emit("ain", "Hello Server!");   
 +
    };
  
== Features ==
+
    connect();
  
Digital-output X-, Y-, and Z-Axis angular rate sensors (gyros) on one integrated circuit
+
$(function () {
Digitally-programmable low-pass filter
+
 
Low 6.5mA operating current consumption for long battery life
+
    function initPlotData() {
Wide VDD supply voltage range of 2.1V to 3.6V
+
        // zip the generated y values with the x values
Standby current: 5μA
+
        var result = [];
Digital-output temperature sensor
+
        for (var i = 0; i <= samples; i++)
Fast Mode I2C (400kHz) serial interface
+
            result[i] = [i, 0];
Optional external clock inputs of 32.768kHz or 19.2MHz to synchronize with system clock
+
        return result;
Pins broken out to a breadboard friendly 7-pin 0.1" pitch header
+
    }
 +
 
 +
    // setup control widget
 +
    $("#ainNum").val(ainNum).change(function () {
 +
        ainNum = $(this).val();
 +
    });
 +
 
 +
    $("#gpioNum").val(gpioNum).change(function () {
 +
        gpioNum = $(this).val();
 +
    });
 +
 
 +
    $("#i2cNum").val(i2cNum).change(function () {
 +
        i2cNum = $(this).val();
 +
    });
 +
 
 +
    var updateTopInterval = 100;
 +
    $("#updateTopInterval").val(updateTopInterval).change(function () {
 +
        var v = $(this).val();
 +
        if (v && !isNaN(+v)) {
 +
            updateTopInterval = +v;
 +
            if (updateTopInterval < 25)
 +
                updateTopInterval = 25;
 +
            if (updateTopInterval > 2000)
 +
                updateTopInterval = 2000;
 +
            $(this).val("" + updateTopInterval);
 +
        }
 +
    });
 +
 
 +
    var updateBotInterval = 100;
 +
    $("#updateBotInterval").val(updateBotInterval).change(function () {
 +
        var v = $(this).val();
 +
        if (v && !isNaN(+v)) {
 +
            updateBotInterval = +v;
 +
            if (updateBotInterval < 25)
 +
                updateBotInterval = 25;
 +
            if (updateBotInterval > 2000)
 +
                updateBotInterval = 2000;
 +
            $(this).val("" + updateBotInterval);
 +
        }
 +
    });
 +
 
 +
    // setup plot
 +
    var optionsTop = {
 +
        series: {
 +
            shadowSize: 0, // drawing is faster without shadows
 +
            points: { show: false},
 +
            lines:  { show: true, lineWidth: 5},
 +
        },
 +
        yaxis: { min: 10, max: 35,
 +
                  zoomRange: [10, 256], panRange: [-128, 128] },
 +
        xaxis: { show: true,
 +
                  zoomRange: [10, 100], panRange: [0, 100] },
 +
        legend: { position: "sw" },
 +
        zoom: { interactive: true, amount: 1.1 },
 +
        pan: { interactive: true }
 +
    };
 +
    plotTop = $.plot($("#plotTop"),
 +
        [
 +
          { data:  initPlotData(),
 +
            label: "GyroTemp" }
 +
        ],
 +
            optionsTop);
 +
 
 +
    var optionsBot = {
 +
        series: {
 +
            shadowSize: 0, // drawing is faster without shadows
 +
            points: { show: false},
 +
            lines:  { show: true, lineWidth: 5},
 +
            //color: 2
 +
        },
 +
        yaxis: { min: -100, max: 100,
 +
                  zoomRange: [10, 256], panRange: [60, 100] },
 +
        xaxis: { show: true,
 +
                  zoomRange: [10, 100], panRange: [0, 100] },
 +
        legend: { position: "sw" },
 +
        zoom: { interactive: true, amount: 1.1 },
 +
        pan: { interactive: true }
 +
    };
 +
    plotBot = $.plot($("#plotBot"),
 +
        [
 +
          { data:  initPlotData(),
 +
            label: "GyroX"},
 +
          { data:  initPlotData(),
 +
            label: "GyroY"},
 +
          { data:  initPlotData(),
 +
            label: "GyroZ"}
 +
        ],
 +
            optionsBot);
 +
 
 +
    // Request data every updateInterval ms
 +
    function updateTop() {
 +
        socket.emit("ain",  ainNum);
 +
        socket.emit("gpio", gpioNum);
 +
        setTimeout(updateTop, updateTopInterval);
 +
    }
 +
    //updateTop();
 +
 
 +
    function updateBot() {
 +
        socket.emit("i2c",  i2cNum);
 +
        setTimeout(updateBot, updateBotInterval);
 +
    }
 +
    //updateBot();
 +
});
 +
</script>
 +
 
 +
  </body>
 +
</html>
 +
</pre>
  
 
== Documents ==
 
== Documents ==

Latest revision as of 16:27, 24 October 2012

thumb‎ Embedded Linux Class Ruffin White RHIT


Breakout board for InvenSense's ITG-3200

Overview

This project show how the ITG-3200, a three-axis gyro sensor, can read and displayed using the beagle bone, a web browser and node.js. This project expands upon what was documented in SparkFun:_ITG-3200,Triple-Axis_Gyro.


ITG-3200 breakout board pin-out
Here's the first display screen you will see after entering the bones web address, go ahead and click on the Button Dox Demo link
Once the script is up and running you will begin to see the sensor data rendered across the time axis plots with regards to each rotational direction of the gyroscope as well as its internal temperature

Introduction

The goal here is to add a web-based graphical display to the gyroscopic sensor. Using examples of node.js servers that display realtime data from the beagle, I have altered the example code to display specifically the three axes of rotation for the gyroscope as well as in addition the internal temperature of the sensor itself.

buttonBox.js, buttonBox.html
This is a bone-based example that reads a gpio port, analog in and an i2c device and displays the output in a web browser.These will be there two main files that will contain many of my alterations.

Running the code

First off, you'll need to download the code through the get hub repository onto a local directory within your Beagle bone. You will then need to navigate to:

beagle$ cd ~/MiniProject04/node.js/realtime
beagle$ opkg update
beagle$ opkg install nodejs  (Don't install node, it's not what you think.)

On the Bone:

beagle$ node buttonBox.js

Simply press ‘CTRL’ + ‘C’ to quit the program.

Connecting to the Bone

Then point a browser to beaglebone.local:8081. The default port is 8081. You can change it if you like.

How it works

The prior examples included the script within the HTML file that polled the server continuously for data updates. However I have altered the code within the HTML file as well as the .js file to allow the server to be so fully responsible for pushing the data to the client.

Another alteration I have made is to alter the I2C function that is called to acquisition the sensor data. Using the source code within mini project two, I have made a stripped-down version that simply returns all the relevant registers within the sensor. This is interpreted as a string within the server's .js file and is streamed to the client browser where the script parses the relevant information to each specific axis and temperature variable. This is then plotted on the grass and rendered on-screen over time.

This setup is accurate for the Sample Code up to the point about the brackeout board pinout. Just adjust the pin to the ITG-3200 accordingly to by description below. See EBC Exercise 12 I2C for more detail

Code

Node.js Code

The code shown below is part sample code to demonstrate reading the registers via I2C and displaying the data with node.js. The alteration that has been made is to specify a timeout period for the server, as well as an additional function that will execute the terminal commands required to poll the gyroscopic sensor in return its register values. The code will also zero out the gyro to account for the internal bias the gyro might have just being stationary and level.

One alteration you'll need to make is to change the path the exec function with in the pushMessage function calls the custom c program to read the I2C buss. Just change the path to point to the excusable you compile with gcc using available MiniProject02.c file within the same directory as the HTML and node.js files, all the necessary header files are included as well.

// From Getting Started With node.js and socket.io 
// http://codehenge.net/blog/2011/12/getting-started-with-node-js-and-socket-io-v0-7-part-2/
"use strict";

var http = require('http'),
    url = require('url'),
    fs = require('fs'),
    exec = require('child_process').exec,
    server,
    connectCount = 0;	// Number of connections to server

server = http.createServer(function (req, res) {
// server code
    var path = url.parse(req.url).pathname;
    console.log("path: " + path);
    switch (path) {
    case '/':
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write('<h1>Hello!</h1>Try<ul><li><a href="/buttonBox.html">Button Box Demo</a></li></ul>');

        res.end();
        break;

    default:		// This is so all the files will be sent.
        fs.readFile(__dirname + path, function (err, data) {
            if (err) {return send404(res); }
//            console.log("path2: " + path);
            res.write(data, 'utf8');
            res.end();
        });
        break;

    }
});

var send404 = function (res) {
    res.writeHead(404);
    res.write('404');
    res.end();
};

server.listen(8081);

// socket.io, I choose you
var io = require('socket.io').listen(server);
io.set('log level', 2);

// on a 'connection' event
io.sockets.on('connection', function (socket) {
    var frameCount = 0;	// Counts the frames from arecord
    var lastFrame = 0;	// Last frame sent to browser
    console.log("Connection " + socket.id + " accepted.");
//    console.log("socket: " + socket);

    // now that we have our connected 'socket' object, we can 
    // define its event handlers

    // Make sure some needed files are there
    // The path to the analog devices changed from A5 to A6.  Check both.
    var ainPath = "/sys/devices/platform/omap/tsc/";
//    if(!fs.existsSync(ainPath)) {
//        ainPath = "/sys/devices/platform/tsc/";
//        if(!fs.existsSync(ainPath)) {
//            throw "Can't find " + ainPath;
//        }
//    }
    // Make sure gpio 7 is available.
    exec("echo 7 > /sys/class/gpio/export");
    

    // Send value every time a 'message' is received.
    socket.on('ain', function (ainNum) {
//        var ainPath = "/sys/devices/platform/omap/tsc/ain" + ainNum;
        fs.readFile(ainPath + "ain" + ainNum, 'base64', function(err, data) {
            if(err) throw err;
            socket.emit('ain', data);
//            console.log('emitted ain: ' + data);
        });
    });

    socket.on('gpio', function (gpioNum) {
        var gpioPath = "/sys/class/gpio/gpio" + gpioNum + "/value";
        fs.readFile(gpioPath, 'base64', function(err, data) {
            if (err) throw err;
            socket.emit('gpio', data);
//            console.log('emitted gpio: ' + data);
        });
    });

    socket.on('i2c', function (i2cNum) {
//        console.log('Got i2c request:' + i2cNum);
        exec('i2cget -y 3 ' + i2cNum + ' 0 w',
            function (error, stdout, stderr) {
//		The TMP102 returns a 12 bit value with the digits swapped
                stdout = '0x' + stdout.substring(4,6) + stdout.substring(2,4);
//                console.log('i2cget: "' + stdout + '"');
                if(error) { console.log('error: ' + error); }
                if(stderr) {console.log('stderr: ' + stderr); }
                socket.emit('i2c', stdout);
            });
    });

    socket.on('led', function (ledNum) {
        var ledPath = "/sys/class/leds/beaglebone::usr" + ledNum + "/brightness";
//        console.log('LED: ' + ledPath);
        fs.readFile(ledPath, 'utf8', function (err, data) {
            if(err) throw err;
            data = data.substring(0,1) === "1" ? "0" : "1";
//            console.log("LED%d: %s", ledNum, data);
            fs.writeFile(ledPath, data);
        });
    });

   var updateInterval = 100;
   function pushMessage() {
//        console.log('Got i2c request:' + 6);
        exec('/home/root/ECE497/MiniProject04/node.js/realtime/./a.out 0 0 ' + 3,
            function (error, stdout, stderr) {
		console.log('stdout:' + stdout);
		//console.log('stdout:' + parseFloat(stdout.substring(51,58))/100.0);
                if(error) { console.log('error: ' + error); }
                if(stderr) {console.log('stderr: ' + stderr); }
                socket.emit('i2c', stdout);
            });
        setTimeout(pushMessage, updateInterval);
    }
    pushMessage();


    socket.on('disconnect', function () {
        console.log("Connection " + socket.id + " terminated.");
        connectCount--;
        if(connectCount === 0) {
        }
        console.log("connectCount = " + connectCount);
    });

    connectCount++;
    console.log("connectCount = " + connectCount);
});

HTML Code

This file is altered from example code and contains all the necessary formatting for the user interface and data representation. A also contains the script necessary to parse the string containing the sensor data sent by the server.

<!doctype html>
<html>
  <head>
    <title>Gyro Demo</title>

    <script src="/json.js"></script> <!-- for ie -->
    <script src="/socket.io/socket.io.js"></script>

    <link href="layout.css" rel="stylesheet" type="text/css">
    <script src="jquery.js"></script>
    <script src="jquery.flot.js"></script>
    <script src="jquery.flot.navigate.js"></script>
  </head>
  <body>
    <h1>Gyro Demo <a href="http://Rose-Hulman.edu" target="_blank">
        <img src="RoseLogo96.png" width=200 style="float:right"></a></h1>
    <button id="connect" onClick='connect()'/>Connect</button>
    <button id="disconnect" onClick='disconnect()'>Disconnect</button>
    <span style="position:relative; left:150px">
    Analog: <input id="ainNum" type="text" value="" style="text-align: right; width:2em">
    gpio: <input id="gpioNum" type="text" value="" style="text-align: right; width:2em">
    i2c: <input id="i2cNum" type="text" value="" style="text-align: right; width:3em">
    </span>
<!--    <button id="send" onClick='send()'/>Send Message</button> -->
<table>
<tr>
    <td><div id="plotTop" style="width:550px;height:300px;"></div>
<center>samples</center></td>
<td>
    Update: <input id="updateTopInterval" type="text" value="" style="text-align: right; width:3em"> ms
    <button id="zoomout" onClick='plotTop.zoomOut()'>Zoom Out</button>
</td>
</tr>
<tr>
    <td><div id="plotBot" style="width:550px;height:300px;"></div>
<center>samples</center></td>
<td>
    Update: <input id="updateBotInterval" type="text" value="" style="text-align: right; width:3em"> ms
    <button id="zoomout" onClick='plotBot.zoomOut()'>Zoom Out</button>
</td>
</tr>
</table>
<button id="led0" onClick='led(0)'/>LED 0</button>
<button id="led1" onClick='led(1)'/>LED 1</button>
<button id="led2" onClick='led(2)'/>LED 2</button>
<button id="led3" onClick='led(3)'/>LED 3</button>
<p>

<b>Button Box demo from the <a href="http://elinux.org/index.php?title=Category:ECE497" target="_blank">32-bit Embedded Linux Class</a>.</b>
In this demo, the beagle bone pushes it sensor data to the web browser. Try moving the gyro or touching it to change its temprature. Try double-clicking to zoom and click and dragging to pan.
</p>
    <a href="http://beagleboard.org" target="_blank">
        <img src="beagle-hd-logo.gif" width=200 align="right"></a>
    <div><p id="status">Waiting for input</p></div>
    <a href="http://www.ti.com/sitara" target="_blank">
        <img src="hdr_ti_logo.gif" width=200 align="right"></a>
    <div><p id="message">message</p></div> 
By <i>Ruffin White</i>
<br/>

    <script>

    var socket;
    var firstconnect = true,
        fs = 8000,
        Ts = 1/fs*1000,
        samples = 100,
        plotTop,
        plotBot,
        ainData = [],  iain = 0, 
        gpioData = [], igpio = 0,
        i2cXData = [],  ii2cX = 0,
        i2cYData = [],  ii2cY = 0,
        i2cZData = [],  ii2cZ = 0,
        i2cTData = [],  ii2cT = 0,
        gpioNum = 7,
        ainNum  = 6,
        i2cNum  = "0x48";
    ainData[samples] = 0;
    gpioData[samples] = 0;
    i2cXData[samples] = 0;
    i2cYData[samples] = 0;
    i2cZData[samples] = 0;
    i2cTData[samples] = 0;

    function connect() {
      if(firstconnect) {
        socket = io.connect(null);

        socket.on('message', function(data)
            { status_update("Received: message");});
        socket.on('connect', function()
            { status_update("Connected to Server"); });
        socket.on('disconnect', function()
            { status_update("Disconnected from Server"); });
        socket.on('reconnect', function()
            { status_update("Reconnected to Server"); });
        socket.on('reconnecting', function( nextRetry )
            { status_update("Reconnecting in " + nextRetry/1000 + " s"); });
        socket.on('reconnect_failed', function()
            { message("Reconnect Failed"); });

        socket.on('ain',  ain);
        socket.on('gpio', gpio);
        socket.on('i2c',  i2c);

        firstconnect = false;
      }
      else {
        socket.socket.reconnect();
      }
    }

    function disconnect() {
      socket.disconnect();
    }

    function led(ledNum) {
        socket.emit('led', ledNum);
    }

    // When new data arrived, convert it and plot it.
    function ain(data) {
        data = atob(data)/4096 * 1.8;
        data = isNaN(data) ? 0 : data;
//        status_update("ain: " + data);
        ainData[iain] = [iain, data];
        iain++;
        if(iain >= samples) {
            iain = 0;
            ainData = [];
        }
        plotTop.setData([ ainData, gpioData ]);
        plotTop.draw();
    }

    function gpio(data) {
        data = atob(data);
//        status_update("gpio: " + data);
        gpioData[igpio] = [igpio, data];
        igpio++;
        if(igpio >= samples) {
            igpio = 0;
            gpioData = [];
        }
        plotTop.setData([ ainData, gpioData ]);
        plotTop.draw();
    }
//gyroX: -00026 gyroY: -00012 gyroZ: 000073 gyroTemp: 002602

    function i2c(data) {
        Xdata = parseInt(data.substring(6,12));
        Ydata = parseInt(data.substring(20,26));
        Zdata = parseInt(data.substring(34,40));
        Tdata = parseInt(data.substring(51,56));
        i2cXData[ii2cX] = [ii2cX, Xdata];
        i2cYData[ii2cY] = [ii2cY, Ydata];
        i2cZData[ii2cZ] = [ii2cZ, Zdata];
        i2cTData[ii2cT] = [ii2cT, Tdata];
        ii2cX++;
        if(ii2cX >= samples) {
            ii2cX = 0;
            i2cXData = [];
        }
        i2cXData[ii2cY] = [ii2cY, Xdata];
        ii2cY++;
        if(ii2cY >= samples) {
            ii2cY = 0;
            i2cYData = [];
        }
        i2cXData[ii2cZ] = [ii2cZ, Xdata];
        ii2cZ++;
        if(ii2cZ >= samples) {
            ii2cZ = 0;
            i2cZData = [];
        }
        i2cXData[ii2cT] = [ii2cT, Xdata];
        ii2cT++;
        if(ii2cT >= samples) {
            ii2cT = 0;
            i2cTData = [];
        }
        plotBot.setData([ i2cXData, i2cYData, i2cZData]);
        plotBot.draw();
        plotTop.setData([ i2cTData ]);
        plotTop.draw();
    }

    function status_update(txt){
      document.getElementById('status').innerHTML = txt;
    }

    function send(){
      socket.emit("ain", "Hello Server!");    
    };

    connect();

$(function () {

    function initPlotData() {
        // zip the generated y values with the x values
        var result = [];
        for (var i = 0; i <= samples; i++)
            result[i] = [i, 0];
        return result;
    }

    // setup control widget
    $("#ainNum").val(ainNum).change(function () {
        ainNum = $(this).val();
    });

    $("#gpioNum").val(gpioNum).change(function () {
        gpioNum = $(this).val();
    });

    $("#i2cNum").val(i2cNum).change(function () {
        i2cNum = $(this).val();
    });

    var updateTopInterval = 100;
    $("#updateTopInterval").val(updateTopInterval).change(function () {
        var v = $(this).val();
        if (v && !isNaN(+v)) {
            updateTopInterval = +v;
            if (updateTopInterval < 25)
                updateTopInterval = 25;
            if (updateTopInterval > 2000)
                updateTopInterval = 2000;
            $(this).val("" + updateTopInterval);
        }
    });

    var updateBotInterval = 100;
    $("#updateBotInterval").val(updateBotInterval).change(function () {
        var v = $(this).val();
        if (v && !isNaN(+v)) {
            updateBotInterval = +v;
            if (updateBotInterval < 25)
                updateBotInterval = 25;
            if (updateBotInterval > 2000)
                updateBotInterval = 2000;
            $(this).val("" + updateBotInterval);
        }
    });

    // setup plot
    var optionsTop = {
        series: { 
            shadowSize: 0, // drawing is faster without shadows
            points: { show: false},
            lines:  { show: true, lineWidth: 5},
        }, 
        yaxis:	{ min: 10, max: 35, 
                  zoomRange: [10, 256], panRange: [-128, 128] },
        xaxis:	{ show: true, 
                  zoomRange: [10, 100], panRange: [0, 100] },
        legend:	{ position: "sw" },
        zoom:	{ interactive: true, amount: 1.1 },
        pan:	{ interactive: true }
    };
    plotTop = $.plot($("#plotTop"), 
        [ 
          { data:  initPlotData(), 
            label: "GyroTemp" }
        ],
            optionsTop);

    var optionsBot = {
        series: { 
            shadowSize: 0, // drawing is faster without shadows
            points: { show: false},
            lines:  { show: true, lineWidth: 5},
            //color: 2
        }, 
        yaxis:	{ min: -100, max: 100, 
                  zoomRange: [10, 256], panRange: [60, 100] },
        xaxis:	{ show: true, 
                  zoomRange: [10, 100], panRange: [0, 100] },
        legend:	{ position: "sw" },
        zoom:	{ interactive: true, amount: 1.1 },
        pan:	{ interactive: true }
    };
    plotBot = $.plot($("#plotBot"), 
        [ 
          { data:  initPlotData(),
            label: "GyroX"},
          { data:  initPlotData(),
            label: "GyroY"},
          { data:  initPlotData(),
            label: "GyroZ"}
        ],
            optionsBot);

    // Request data every updateInterval ms
    function updateTop() {
        socket.emit("ain",  ainNum);
        socket.emit("gpio", gpioNum);
        setTimeout(updateTop, updateTopInterval);
    }
    //updateTop();

    function updateBot() {
        socket.emit("i2c",  i2cNum);
        setTimeout(updateBot, updateBotInterval);
    }
    //updateBot();
});
</script>

  </body>
</html>

Documents

SparkFun:_ITG-3200,Triple-Axis_Gyro

Schematic

Eagle Files

Quickstart Guide

ITG-3200 Datasheet

Code (ATmega328)

Example

Sparkfun

Github Repo




thumb‎ Embedded Linux Class Ruffin White RHIT