Sign in to follow this  
Followers 0
yyrkoon

Nodejs GPIO

19 posts in this topic

SO I was just messing around today when taking a break from other programming related things. When I wrote this small bit of code to demonstrate to a few people why bonescript really isn't needed. One thing worth noting. I can export pins via the sysfs pseudo file system, but for some reason, I can not move into the sub directories, and start manipulating pin configuration files. Depending on how I try to access the file, I get either file not found, or permissions denied. Despite the fact that I'm part of the group that has access to the GPIO file structure. Just keep in mind that the code below is very simple, and to the point. Mostly meant as a demonstration for those having a hard time visualizing how this is done using Nodejs.

 

This: http://www.embeddedhobbyist.com/2016/05/beaglebone-black-gpio-permissions/ will help those understand how I'm accessing this file structure as a regulr user, and perhaps help some that would like to learn how.

 

node-gpio.js

var base_path = "/sys/class/gpio/gpio";
var pin_number = "49";
var value = base_path + pin_number + "/value"
var direction = base_path + pin_number + "/direction"

//Read the current value of the given pin. 0 -> low || 1 -> high
read(value);
//Read the current pin direction. out -> output || in -> input
read(direction);
//Change the pin to an output, and high. Valid values are high, low, in, or out. high, and low 
//also configure the given pin as an output, as well as pull the pin high, or low.
write(direction, 'high');
// Reread the pin configuration files to show the pin state has changed.
read(value);
read(direction);

function read(path){
    var fs = require('fs');
    
    var buf = fs.readFileSync(path, 'utf8');
    console.log(path + ': ' + buf);
}

function write(path, value){
    var fs = require('fs');
    fs.writeFileSync(path, value, 'utf8');
}

Output:

william@beaglebone:~/dev$ echo 49 > /sys/class/gpio/unexport
william@beaglebone:~/dev$ echo 49 > /sys/class/gpio/export
william@beaglebone:~/dev$ node node-gpio.js
/sys/class/gpio/gpio49/value: 0

/sys/class/gpio/gpio49/direction: in

/sys/class/gpio/gpio49/value: 1

/sys/class/gpio/gpio49/direction: out

Share this post


Link to post
Share on other sites

So, I went ahead and made my own "library" for Nodejs. So far I have wrappers for GPIO, I2C, the USR LEDs, and ADC. I'm working on "documetation"( readme.md), and the I'll probably put it up on github.

 

Does anyone have anything specific they'd like to see implemented in Nodejs for the beaglebone ? Keep i mind with all the above, I'm just very simply wrapping the sysfs mechanism for each peripheral. Except for I2C which actually wraps i2cget from the Debian package i2c-tools.

 

With all the above said however. I've found this very simple bit of wrapper code very useful. I even wrote an i2c example that pulls in all the data registers from the tps65217 PMIC on the i2c-0 bus. Then partially parsing the data before writing it out to a json file.

 

I must say that doing all this from javascript( Nodejs) is fairly interesting / cool. But one thing one needs to keep in mind the asynchronous nature of Javascript can make things challenging if you're not used to doing things the Nodejs way.

 

EDIT:

 

Oh, and I will probably eventually implement PWM too, but I need hardware to test the code on. So it could take a little while before I get to that.

 

EDIT2:

 

D'oh ! And of course I'll be implementing UART too. With UART though I think I'll get a bit fancy, and wrap getty, or something. So one can configure baud rate etc in code.

Share this post


Link to post
Share on other sites

So, heh I just realized I left my adc test run over night . . .

 


$ time node test.js
. . .
0:4017
1:3781
2:3981
3:2069
4:2035
5:3534
6:3645
^C

real    983m55.524s
user    4m42.960s
sys     4m20.690s

So I suppose that is a good indication that it is reasonably stable . . . ;) There's not really much to it.

 

test.js

"use strict";

(function() {
        var adc = require('./adc.js');
        
        function read_channel(channel){
                var read_adc = function(){
                        adc.read(channel, function(data){
                                var sample = (data & 0xFFF);
                                console.log(channel + ':' + sample);
                        });
                }
                setInterval(read_adc, 1000);
        }
        
        var rc0 = new read_channel(0);
        var rc1 = new read_channel(1);
        var rc2 = new read_channel(2);
        var rc3 = new read_channel(3);
        var rc4 = new read_channel(4);
        var rc5 = new read_channel(5);
        var rc6 = new read_channel(6);       
})();

 

Share this post


Link to post
Share on other sites

You know, I wonder if the BBB would be a good Edge Router for a sensor network.

 

In my mind, I am thinking of my one wire sensor launchpad that can read a tremendous amount of ds18b20 sensors. Collecting and viewing that information would be a task suitable for the BBB.

 

In node,js, you could create a user interface that would talk to the sensor network and display the essentials to the user.

 

FYI, one application of my temperature sensors is to measure enormous piles of grain to make sure that they do not spoil. Another would be monitoring the temperature of many rooms in a large building.

Share this post


Link to post
Share on other sites

You know, I wonder if the BBB would be a good Edge Router for a sensor network.

 

In my mind, I am thinking of my one wire sensor launchpad that can read a tremendous amount of ds18b20 sensors. Collecting and viewing that information would be a task suitable for the BBB.

 

In node,js, you could create a user interface that would talk to the sensor network and display the essentials to the user.

 

FYI, one application of my temperature sensors is to measure enormous piles of grain to make sure that they do not spoil. Another would be monitoring the temperature of many rooms in a large building.

A Beaglebone black would probably work great for what you're describing. However tou may want to look into the newer beaglebone green from element14. Which is supposed to have wifi and BLE built in. One thing worth noting however. The Beaglebone greens do not have an HDMI framer, but if  all you need is a headless web appliance type "thing" it should be great.

 

I'm no huge fan of the original Raspberry PI, but I do own an rPI 3, and perhaps one of those may be better ? They have 1G ram, quad cores at 1.2Ghz, ethernet, plus wifi and BLE built in for less cost than the Beaglebones.  *However* an rPI also does not have the shear amount of GPIO's / peripherals that s Beaglebone does, and the rPI also has no eMMC. The Beaglebone has a 4G eMMC.

 

@@zeke

 

Anyway give me some criteria for what you need, and I would be able to give you a better answer. For instance, how do you propose to dump all this 1wire data onto a prospect router board ? How long do you need to store data on the board ? etc . . .

Share this post


Link to post
Share on other sites

The examples I've seen from TI for edge routers on sensor networks (6LoWPAN, etc.) tend to use the BeagleBone with an appropriate USB radio.

Share this post


Link to post
Share on other sites

The examples I've seen from TI for edge routers on sensor networks (6LoWPAN, etc.) tend to use the BeagleBone with an appropriate USB radio.

The thing is, there are a number of SBC's out there that can do as good of, or even a better job - Potentially. I think the rPI 3 *could* be a better option. But again, it really depends. How many of why type of input peripherals are needed ? Board cost of the rPI3 is also less, but one does need to purchase an sdcard separately. However, the rPI3 also has 4 host USB ports, and built in wifi / bluetooth 4.x that the beaglebone does not have. There are also many aspects of the Beaglebone that trump the rPI3, but I'm not sure those aspects would come into play here. But in the capacity of operating as a computer( server, etc ), the rPI3 also is the better board.

 

So again, I think it all comes down to how much of what type of peripheral one needs . . .

 

As an example of why the Raspberry PI 3 is a better board when operating as a general purpose computer( running an OS ). I recently compiled Nodejs on both the Beaglebone black, and the Raspberry PI3. The Beaglebone took 3.5 hours to compile from source while the Raspberry PI took around 1 hour 15 minutes. So obviously the rPI3 has more computational power, as well as twice as much memory. So if you think twice as much memory is no big deal . . . think again. Thats twice as much memory that can be used as a ram disk, which can be an important factor on an embedded system. As flash media has limited write cycles where DDR does not. So one can have a read only file system for the rootfs, and use a RAM DISK overlay for changing data.

tripwire likes this

Share this post


Link to post
Share on other sites

Oh, and Windows 10( cough! ) supposedly runs on the Raspberry PI 3 too. I'm seriously not sure I see the benefit of that. But it's possible . . . Personally, I still use Windows on most of my desktop machines, but I see no place for Windows in the embedded field . . . just a personal preference . . .

Share this post


Link to post
Share on other sites

I've used Windows 10 on the Pi. It's a bit unfinished but shows some promise. I'm planning to use it for an upcoming project at work. My team is mostly C# developers and they'd definitely feel more comfortable with it. The plan is that they'll be able to contribute too.

Share this post


Link to post
Share on other sites

I've used Windows 10 on the Pi. It's a bit unfinished but shows some promise. I'm planning to use it for an upcoming project at work. My team is mostly C# developers and they'd definitely feel more comfortable with it. The plan is that they'll be able to contribute too.

Just a heads up. Mono on the Beaglebone seems to be doing pretty good now days. So C# would not, or should not be too much of a problem. I've no hands on though, but if Mono is doing well, it has to be doing well on the PI's too. At least the most recent PI's as they all use the same software ABI, as the beaglebone blacks ( armv7 hardware arch / armhf software abi ). Technically the rpi3, hardware wise is not armv7, but its either close enough, or just flat out compatible with armv7 hardware . . . *somehow*.

 

EDIT:

 

Sorry, I just realized that I did not mention that Mono for armv7( armhf) would be for Linux . . .

Share this post


Link to post
Share on other sites

As an aside . . . I used to be a .NET junkie too, dating back to 2001-2002. I even tried to get the .NET runtimes working on the beaglebones for a while. After a while I just kind of gave up as I learned more about Nodejs. Not because I think that Nodejs is necessarily better, but it is, or was much better suited for cross platform development. Now days, I've read that Microsoft has since in the last few years been trying to push cross platform .NET libraries, and runtimes . . . but I've long since  given up on Microsoft . . .except to provide me the occasional desktop OS.

Share this post


Link to post
Share on other sites

So now that I' settled in for the day to experiment with more code. I got UART working really easily, and I'm not sure I'd need to wrap this code at all.

(function() {
        var fs = require('fs');
        var readStream = fs.createReadStream('/dev/ttyO0');
        
        readStream.on('data', function(chunk){
                process.stdout.write(chunk.toString()); // console.log() without the newline injected.
        });      
})();

I mean, how does one simplify that further ? You can not really  . . . well I mean one could be "cute" and write "constants" for file paths and what not but why ? Just to seem clever ?
 Maybe one of you reading this post can come up with a good reason to wrap this code ? I'm all ears.

 

With the above said however. It might be a good thing to write a C binary that implements "BOTHER" code in order to achieve non standard baud rates, and then wrap that in Javascript. I also just happen to know that would be really simple, and minimal. As Peter Hurley from the Beaglebone.org google groups has already shared such code. 20-25 lines of C, thats it.

 

EDIT:

 

And actually there is one oddity that I was noticing. The very first time I ran the above code, every single character was sent. But after that, the first character gets chopped off. It does not matter if i restart the app, or not, the result is the same. I've been getting around this my sending a " " prior, but I'm probably missing something here . . . I've also gone about using different code, and that does not changes things either . . . on the sending end, I'm just using

william@eee-pc:~$ sudo sh -c 'echo " world" > /dev/ttyUSB0'

 As I have not gotten around to putting Nodejs on my dev support system just yet( and may never ).

Share this post


Link to post
Share on other sites

Isn't it funny that we sometimes remember things better than they are ? Peter Hurley's code is actually 66 lines, and that was actually a git that he forked, and cleaned up. I still think its great code, primarily because it's very readable, and I did not have to write it ;)

/*
 * Allows to set arbitrary speed for the serial device on Linux.
 * stty allows to set only predefined values: 9600, 19200, 38400, 57600, 115200, 230400, 460800.
 */
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <asm/termbits.h>

#define error_exit(f, args...)                                      \
    printf_exit("%s: " f ": %s (code: %d)\n", __func__, ##args,           \
                          strerror(errno), errno)

static void printf_exit(char *f, ...) {
    va_list va;

    va_start(va, f);
    vfprintf(stderr, f, va);
    va_end(va);

    exit(EXIT_FAILURE);
}

static void usage(char* argv[]) {
    printf("%s device speed\n\n"
           "Set speed for a serial device.\n"
           "For instance:\n"
           "    %s /dev/ttyUSB0 75000\n", argv[0], argv[0]);
    exit(EXIT_FAILURE);
}

int main(int argc, char* argv[]) {

    int fd, speed;
    struct termios2 tio;

    setbuf(stdout, NULL);

    if (argc != 3)
        usage(argv);

    fd = open(argv[1], O_RDONLY);
    if (fd < 0)
        error_exit("opening tty");

    speed = atoi(argv[2]);

    if (ioctl(fd, TCGETS2, &tio) < 0)
        error_exit("TCGETS2 ioctl");

    tio.c_cflag &= ~CBAUD;
    tio.c_cflag |= BOTHER;
    tio.c_ispeed = speed;
    tio.c_ospeed = speed;

    if (ioctl(fd, TCSETS2, &tio) < 0)
        error_exit("TCSETS2 ioctl");
    close(fd);

    printf("%s speed changed to %d baud\n", argv[1], speed);
    return 0;
}

Share this post


Link to post
Share on other sites

@@zeke

 

By the way, I' still interested in how you're going to do things. i.e. How do you connect sensors to a launchpad for this project you mention, and then how do you propose to connect the launchpad with a Beaglebone, or other capable SBC ?

 

I know how I'd do it, or at least I think I do, but I like to hear, or see how others do things too, and perhaps discuss the why of it all.

Share this post


Link to post
Share on other sites

@@yyrkoon

 

Yeah, I've been pondering that same question lately.

 

This is the project that will be collecting all of the data.

 

I have designed it to the boosterpack-xl pinout spec. That means it will stack onto any TI launchpad.

 

Also, it has the ability to switch personality between launchpad and boosterpack.

 

There is a support board that gives it a USB serial port so that's the prime method of communicating with the datalogger.

 

I have a BBB but it's just collecting dust at the moment. I turned it on long enough for me to prove it wasn't DOA.

 

I wonder if there is a beagle cape out there that accepts booster-xl boards?

Share this post


Link to post
Share on other sites

@@zeke

 

Ok, cool. Yes Serial <-> USB is very doable on the Beaglebone, and what more you've probably realized it is something that could be easily done using Javascript( Nodejs ). The reason why I think that Nodej is an important part, is that in my mind this is a project that should have a web front end to display data, and perhaps have some web controls perhaps as well. e.g. a web appliance sort of interface. This is something that can be done with Nodejs really easily. Yes you already talked about that in a previous post, I forgot about . . .

 

It could also be done using C with libmongoose, thats a bit more involved, but perhaps totally worth it after you get something working with Node. I've done this personally, and it does take a while to learn libmongoose as documentation is sparse. SO I did a lot of trial and error, a well as reading a lot of the 10k + lines of code that is libmongoose . . .

 

If you need help getting the beaglebone setup with a proper up to date image. Let me know on the forums here. I actually know quite a lot . . . but not everything of course.

 

EDIT:

Oh and right, my bad . . .

 

I wonder if there is a beagle cape out there that accepts booster-xl boards?

 

No, you'd have to design one yourself. It's not too hard, however . .. My buddy had some  proto-bones made if you know what those are, and if they'll work for you . . .

Share this post


Link to post
Share on other sites

I also wanted to talk some about creating a web server in C, and the pluses / minuses of it all. First, we do have libmongoose we can use and that's great, except if you need for a commercial application you're probably going to want to write your own code. Maybe even license the newer library from the same person who wrote libmongoose. Me, I'd probably want to write my own . . .

 

A web / web socket server in C is very much faster than Nodejs. Not that Node is really slow, Node just uses a lot more CPU to do the same things. But also there is definitely latency. Just doing some really simple ADC tests . . . I was able to get *maybe* 800 samples a second using Nodejs. Code that is just wrapping the sysfs ADC subsystem. In pure C similar code produces around 6500 samples a second . . . which it's self is a lot slower than the ADC. This is a huge performance difference. However if you do not need that speed. It's a lot simpler, and easier to implement a project in Nodejs. So there is a trade off between the two.

 

Additionally, the code size( on disk ) to get a web / web socket server implemented in C is considerably less. When I say this, I mean that an executable is roughly 200k Bytes in size, and then you just have the web front end stuff to serve to potential clients. With Nodejs, it would not be unheard of to have the project use more than 100M on disk . . . which again is an insane difference which may, or may not be important.

 

On the plus side for Node, everything is much easier to do, and personally, I really REALLY like the event driven asynchronous aspect to javascript. I'm also warming up to the idea of a loosely typed language. Which is probably hard for most "die hard" C programmers who are used to very strict types.

 

So those who are looking for something very R.A.D.( rapid application development ) Nodejs / Javascript is a great way to get a working prototype out there and running. Perhaps forever, or perhaps just as a proof of concept until a suitable replacement is written in C/C++.

Share this post


Link to post
Share on other sites

By the way here is some sample code for writing to a serial device using Nodejs:

"use strict";

(function() {
        var adc = require('./adc.js');
        var fs = require('fs');
        var writeStream = fs.createWriteStream('/dev/ttyO0');
        
        function read_adc(channel){
                var log_sample = function(){
                        adc.read(channel, function(data){
                                var sample = (data & 0xFFF);
                                writeStream.write(channel + ':' + sample + "\n");
                        });
                }
                setInterval(log_sample, 1000);
        }
        
        var ain0 = new read_adc(0);       
})();

This is really just a simple example of reading a single ADC channel and then sending that data out over serial. Then on the other end you just . . .

$ sudo cat /dev/ttyUSB0 /* or suitable path to a serial device  */

Of course, you could also write a nodejs app to "catch" and do something with  that data. . .

zeke likes this

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0