Tag Archives: XDK

Using a Rotary Encoder on Intel Edison, XDK

Rotary Encoders are supported by the UPM library. There is already example code that can be leveraged when we want to use one.  The code was created for the Grove Rotary Encoder but in reality we can use it for any rotary encoder we choose to implement. The Grove encoder  would be a good choice if you are using Seed Studio’s Grove Starter Kit. But that could be a problem if we wanted to use the encoder on and Edison project for the mini breakout board or wanted to access the switch in the encoder (you can not access the switch in the Grove Encoder). In my case, I intend to use the encoder to drive a menu for controlling an Edison on a mini breakout board. To accomplish that I will need to have access to the encoders built in switch so I will roll my on implementation.

Since we are going to use the Grove library for the encoder we will implement ours like theirs. If we look at the schematic for the Grove encoder we can see that it is not really that complicated.

Grove Encoder Schematic

Grove Encoder Schematic. Don’t connect  4 and 5 of the switch this way.

We can also see why the switch is not available on the Grove device – not enough pins available on the connector. (Though it does look like activating the switch will pull SIGA down, which we could look for in code. But the UPM library for this doesn’t have any provision for it.) We will wire up our encoder this way but we will wire the switch a little differently.

For the switch we will wire it so the we get a high value when it is actuated. So pin 4 goes to ground via a 10k pull down resistor and to the signal in for our Edison. Pin 5 will go to VCC.

So we need:

1     Encoder — I used these: 360 Degree Rotary Encoder w Push Button

1     Ceramic Disk 100 nf Capacitor (that is 0.1 micro farads, marked 104 on the cap).

4     3.3k Resistors. I used 2% 1/4 watt.  

And for the switch:

1     10k Resistor – also 2% 1/4 watt.

Optionally:

1     Arduino stackable header.  I plugged the encoder into this so it would fit in a breadboard better.

Wiring it up on a bread board gives us something like this:

Wired to a bead board side view

Side view

IMG_20150814_175210

Overhead view

Connected to an Edison Arduino.

Connected to an Edison Arduino board.

I used my Edison Arduino Board to prototype this, so the connections are:

SIGA —> D2

SIGB —> D3

Switch ( encoder pin 4) —> D4

VCC –> 3.3 Volts.

Don’t forget the ground connection.

The code to test this is pretty simple since we are using the UPM Libraries. We will use the Grove Rotary Encoder library for, of course, the encoder. We will use the Grove Button Library for our button functionality.

We will use socket.io to monitor our encoder with a webpage. Our server code looks like this:

//Setup express 
var express = require('express');
var app = express();
app.use(express.static(__dirname));
var server = app.listen(8085);
var io = require('socket.io').listen(server);



var mraa = require('mraa'); //require mraa
console.log('MRAA Version: ' + mraa.getVersion()); //write the mraa version to the Intel XDK console

//var myOnboardLed = new mraa.Gpio(3, false, true); //LED hooked up to digital pin (or built in pin on Galileo Gen1)
var myOnboardLed = new mraa.Gpio(13); //LED hooked up to digital pin 13 (or built in pin on Intel Galileo Gen2 as well as Intel Edison)
myOnboardLed.dir(mraa.DIR_OUT); //set the gpio direction to output

//Require the encoder and button libraries. 
var rotaryEncoder = require("jsupm_rotaryencoder");
var groveSensor = require('jsupm_grove'); 
// Instantiate a Grove Rotary Encoder, using signal pins D2 and D3
var myRotaryEncoder = new rotaryEncoder.RotaryEncoder(2, 3);
//Set up a button on D4
var button = new groveSensor.GroveButton(4); 
 
//We will send data to our client with this object. 
var data = {}; 

//When we get a socket connection we will monitor the switch. 
io.sockets.on('connection', function (socket) {
 
 //Every 100 milli seconds we will send an update to the client. 
 //You won't want to monitor encoder this way for a real project
 //but it will demonstrate the encoder and switch. 
 setInterval(function () {
 //See what the switch value is.
 readButtonValue(); 
 //Sample the current position of the encoder. 
 //Since this is an incremental encoder we will
 //get increasing or decreasing int values from 
 //the encoder library. 
 data.position = myRotaryEncoder.position();
 //For the porposes of this demo, if we go lower than -40
 //or higher than 40 we will reset the encoder init to 0. 
 if(Math.abs(data.position) > 40 ) {
 myRotaryEncoder.initPosition(0);
 data.position = 0; 
 }
 //Send the position in a json encoded string. 
 socket.emit( 'position' , JSON.stringify(data));
 }, 100);

 //Toggle the on board led on or off. 
 socket.on('toggle_led', function(data){
 if(data === 'on'){
 myOnboardLed.write(0);
 } else {
 myOnboardLed.write(1); 
 }
 });
 

});

//A fuction to read our button value
function readButtonValue() {
 //If our button is pressed set the 
 //encoder init to 0. 
 if(button.value() === 1 ) {
 myRotaryEncoder.initPosition(0); 
 } 
}
 


// When exiting: clear interval and print message

process.on('SIGINT', function()

{

 clearInterval(myInterval);

 console.log("Exiting...");

 process.exit(0); 
 
});

A Github repo with working code is located here.

When you load this on your Edison and browse to the web page it will look something like this:

Or demo page contains a gauge the reads from -40 t- 40.

Or demo page contains a gauge the reads from -40 to 40.

Rotating the knob on the encoder clockwise will increase the reading on the dial. Counter clockwise will decrease it. Activating the button on the encoder will reset the dial to 0. If we go below -40 or above 40 the dial will reset to 0. This code is based on the socket.io demo I posted about previously.

So there we have it. Using a rotary encoder in our projects will give us the ability to add controls with out the need of using potentiometers and switches. With an encoder we can implement multi-level menus to enable our end users to configure and control our devices even if they are not connected to wifi or a usb port. Implementing a menu such as this will be the subject of an up coming post.

Implementing the MICS-VZ-89T gas sensor on Intel Edison i2c

On my current project I have the requirement to monitor indoor air quality. What is of interest are the levels of Volatile Organic Compounds (VOCs) and CO2.  There are specific thresholds that we are looking for that when exceeded should trigger an action. For VOCs it is when the concentration is greater that 0.9 ppm. For CO2 it is when the concentration is 1000 ppm above ambient out side C02 — which is generally around 400 ppm. The links above out line the dangers of these indoor pollutants. When the threshold is reached we want to start the ventilation system and optionally message a user.

When I need a sensor my first choice is to find one that implements i2c. In this case I found a good candidate for the job in the SGX Sensortech MICS-VZ-89T. The VZ89 product is a small board with a MICS SMD device integrated with an i2c controller. The board comes in both 5 volt (VZ89) and 3.3 volt (VZ89T) versions that are are easy to implement using a logic level shifter with the Edison on a mini breakout board. (For an example of using a logic level shifter you can see my article Intel Edison and I2C sensors with XDK.)

There was no driver that I could find for implementing the board with my setup so I had to roll my own. This wasn’t too hard, but I did have to break out the logic analyzer to get it right. If we examine the MICS-VZ-89T I2C Specification page  we see that the device only has two commands. These are Set ppmC02 and Get VZ89 Status. According to the MICS-VZ-89T Data Sheet the device comes calibrated from the factory so we don’t need to implement Set ppmC02. That leaves us Get VZ89 Status. The code that follows here is available in an XDK project on git hub.

To read the status we have to perform a two step process. First we write a command byte of 0x09 to register address 0x70. We follow this by writing two data bytes to the same register. I write 0x00 twice.

We then read 6 bytes immediately after writing the command byte. The bytes are decoded as follows:

Data byte 1 = CO2-equivalent value. 
Data byte 2 = VOC_SHORT value. 
Data byte 3 = VOC_LONG value 
Data byte 4 = Raw sensor 1st byte (LSB). 
Data byte 5 = Raw sensor 2nd byte 
Data byte 6 = Raw sensor 3rd byte (MSB).

To implement the functionality I created the following class in a node module:

//Import mraa 
var mraa = require('mraa');

//Constructor -- set defaults and populate tx_buf
function VZ89(bus , address){

 this.bus = new mraa.I2c(bus || 1); 
 this.bus.address(address || 0x70); 
 
 this.tx_buf = new Buffer(3); 
 this.tx_buf[0] = 0x09;
 this.tx_buf[1] = 0x00;
 this.tx_buf[2] = 0x00; 
 
}

//Add a function to get the device readings. 
VZ89.prototype.getReadings = function() {
 this.bus.frequency(mraa.I2C_STD);
 this.bus.write(this.tx_buf); 
 return this.bus.read(6);
 
};
//Export as a node module 
module.exports = VZ89;

The MRAA library is used to access the i2c bus, so it is imported at the top or the file. There is a constructor that optionally takes a bus number and a devices address. The VZ89 is addressed at 0x70 so we don’t really need to change that. If the Edison mini-breakout is used we have a choice of busses. I have set this to bus 6 as I am using the Edison Arduino for this example.

A class function is added to implement named getReadings to perform the measurements and return data from the device. In this case the buffer is passed back to the calling program for use.

To use the class the code in the server file would look like this:

//Import our sensor file from the file system
var Sensor = require('./VZ89.js'); 
//Create an instance of the sensor object. 
var sensor = new Sensor();
//Create a var for the receive buffer.
var rx_buf; 

//Call the readBuf function every minute. 
setInterval(readBuf , 60000); 

//A function to read the sensor data, perform data conversions and display on the console every minute.
function readBuf(){

    rx_buf = sensor.getReadings();
 
    console.log("Co2_equ: " + ((rx_buf[0] - 13) * (1600/229) + 400) + " ppm"); 
    console.log("VOC_short: " + (rx_buf[1])); 
    console.log("tVOC: " + (rx_buf[2] * (1000/229)) + " ppb"); 
    console.log("Resistor Value: " + 10 * (rx_buf[3] + (256 * rx_buf[4]) + (65536 * rx_buf[5])) + " ohms"); 
}

The details of converting the rx_buf data to usable values are in the data sheet.  The ones we are most interested in are Co2 equivalent (rx_buf[0]) and total VOC (rx_buf[2]).

As you can see, the MICS-VZ89T is a pretty easy to use device once you know how. There are only a couple of gotchas to be aware of. First, the device can only be polled once a second. I find if I try to get the readings faster than that the device will return nulls. Secondly, care must be taken when handling the device. It contains organic material that is susceptible to solvents.