rwaldron / johnny-five

JavaScript Robotics and IoT programming framework, developed at Bocoup.

Home Page:http://johnny-five.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

this.io.pingRead undefined raspberry pi (similar to #787)

sesh-kebab opened this issue · comments

Hi - a new johnny-five user. Firstly thank you for such an awesome library. I just recently got started but running into issues with Proximity using a Seeedstudio ultrasonic sensor. Documents mention that I need a special version of PingFirmata and I should use Arduino Studio to upload it. But how can I do this on a RaspberryPi? Is the below error related?

1435589004832 Device(s) RaspberryPi-IO
Nodebot - Test Harness listening at http://0.0.0.0:3000
1435589008787 Connected RaspberryPi-IO
1435589008862 Repl Initialized

/home/pi/Nodebot-TestHarness/node_modules/johnny-five/lib/proximity.js:175
this.io.pingRead(settings, function(microseconds) {
^
TypeError: undefined is not a function
at Proximity. (/home/pi/Nodebot-TestHarness/node_modules/johnny-five/lib/proximity.js:175:19)
at wrapper as _onTimeout
at Timer.listOnTimeout (timers.js:110:15)

@sesh-kebab (great handle BTW) You don't need to upload form the Pi. You can install the Arduino IDE on your laptop and then use that machine to upload the special version of Firmata. Once it's uploaded to the Arduino, it's on there for good until you upload something else. Just connect the Arduino to your Raspberry Pi once the upload is complete.

Note: It's also possible to run the Arduino IDE on your Pi, but that may be more hassle than it's worth.

Thanks @dtex for the quick reply. Sorry, I should've mentioned; I'm not using an Arduino - only a Raspberry Pi.

Hi @sesh-kebab, raspi-io author here. I haven't heard of the pingRead method before, tbh. It's not a part of the io plugin spec.

So what this means is that it's not currently possible to use the pingRead method on the Raspberry Pi.

@dtex are you familiar with pingRead? @rwaldron is this something that we should add to the io plugin spec?

pingRead is the bogus name I made up for hacked in UltraSonic Ping support in PingFirmata. If you wanted to support those devices you could add this, but it's only useful for that one type of component, so it's not really in the io plugin wheelhouse.

@rwaldron @nebrius thanks! From a newbie's perspective, it would definitely be helpful if at the very least, rasp-io could output a message describing why this method isn't available when using Johnny-Five + RaspberryPi combination, for folks who may also run into this issue in the future.

As for a workaround, I'm thinking of using a Pin class to read and write to the signal pin. Would this work? @nebrius and if so, can the workaround (with some work) be considered as a generic implementation for pingRead in raspi-io?

@sesh-kebab TBH I'm a little wary of implementing this in raspi-io. As rwaldron mentioned, this is a rather specific case that doesn't apply to non-Arduino devices, and if we were to add this to raspi-io, we would need to add it to all of the non-Arduino IO plugins too. Also, if we were to consider adding this method, we would need to consider adding in methods from all of the non-standard firmata implementations.

I'll leave the final decision up to @rwaldron though. Adding this does mean changing the IO plugin API afterall.

@nebrius I think we might as well make it available wherever possible. The thing that made me come around was being reminded of the end developer experience. If you can do support here, I will update all the IO-Plugins that I maintain. I've updated the IO-Plugin spec: https://github.com/rwaldron/io-plugins

I just published v3.3.0 of raspi-io, which includes a stub for pingRead. Currently it just throws an error stating "pingRead is not yet implemented", which is the same error all the other unimplemented methods state.

@sesh-kebab if you get some working code, would you be interested in adding that to raspi-io proper? I can help you with the integration process.

@nebrius yes, I absolutely would be interested. Will definitely need your help with the integration process. Hope to have something soon.

@sesh-kebab Fantastic, let me know when you're ready!

Hi @nebrius - sorry I took a very long vacation (recieved Splatoon on WiiU for my birthday).

Just wanted to let you know I have built a native nodejs extension raspi-sonar to support pingRead on Raspberry Pi. I need to trigger the ping on a separate thread among other things; just wanted to check in to see whether I'm on the right track.

My implementation currently allows the signal pins and trigger pins to be different. But the pingRead io plugin spec doesn't allow for this. Is this not really a valid use case? Does everyone using this sensor on a Raspberry Pi, always run both the trigger and signal of the same IO pin?

@sesh-kebab I hear Splatoon is a ton of fun!

My understanding is that the single pin is sufficient for what we do, but maybe @rwaldron can provide some more insight?

Nice work on raspi-sonar so far, I think you're mostly on the right track. I do have two recommendations for you that will make maintenance easier.

I would recommend using Native Abstractions for Node (https://github.com/nodejs/nan). This provides a wrapper around a lot of the V8 stuff and protects your C++ from breaking changes in V8, which occur with pretty much every major Node release.

NAN also provides nice threading abilities out of the box for you, so be sure to check out the async stuff. For an example using wiring pi, check out the main raspi package and the init method: https://github.com/nebrius/raspi/blob/master/src/init.cc

The other thing I would recommend changing is how you're distributing the binary. If you want to distribute pre-built binaries, I would recommend taking a look at node-pre-gyp (https://github.com/mapbox/node-pre-gyp). The other option, and the one I do right now, is to have the code built at module install time. Neither are great solutions, but it's all we have right now.

The thing with pre-built binaries is that you have to provide a lot of them to support different combinations of things. We need to support both armv6 and armv7, as well as node 0.10, node 0.12, the various io.js flavors, and soon node 4, which means you have to supply 10 binaries. Fortunately for us, we don't have to support the entire matrix that some of the other native modules do (over 60 combinations :-O).

Feel free to borrow whatever you need from the raspi package (build setup, tooling, code snippets, etc) to make your life easier.

I realize that all of this native module support stuff is a pain to work with. Native modules are a major pain point for node as a whole, and there are several initiatives underway to make all this easier down the road, but of course that doesn't help us right now :-/

Thanks for taking this on! I really appreciate the help, especially since this involves some native code. Keep up the good work, and let me know if there's any other way I can help!

My implementation currently allows the signal pins and trigger pins to be different. But the pingRead io plugin spec doesn't allow for this

These are usually the same pin and when they are not, we instruct users to jump the trigger and echo pins. Considering this is a really fringe case, no new updates are going to be made for pingRead. These sensors will soon be fully supported via I2C Backpack controllers.

having the same issue with pingRead :(

>> /root/node_modules/raspi-io/lib/index.js:765
        throw new Error("pingRead is not yet implemented");
              ^
Error: pingRead is not yet implemented
    at Raspi.pingRead (/root/node_modules/raspi-io/lib/index.js:765:15)
    at Ping.<anonymous> (/root/node_modules/johnny-five/lib/ping.js:45:13)
    at wrapper [as _onTimeout] (timers.js:274:14)
    at Timer.listOnTimeout (timers.js:119:15)
PI-~/johnyfive->

@nebrius wow thank you so much for providing all the great info. Glad to be of help - I had no idea I would be knee deep in c++ code but definitely a lot of fun to be contributing to a great library. I have started a new branch using the NAN. Will let you know once everything is working ok and promoted to master.

@rwaldron ok - thanks for the explanation. I was under the impression that jumping trigger and echo, on a RaspberryPI at least, would be a no go as the ECHO outputs 5v bit more than the 3.3v that the Pi's GPIO would ideally like?

@born2net working on getting this implemented - hopefully in a couple of weeks :)

@sesh-kebab Nobody expects the C++ inquisition! :D

You can use a voltage divider network to scale the signal from 5v down to 3.3v by putting two resistors in series. Check out the section on voltage divider network at http://www.electronics-tutorials.ws/resistor/res_3.html. In this case, Vin will be connected to ECHO (and set to 5v for calculations), and Vout will be connected to the Pi (and set to 3.3v for calculations). If you set R1 to 1k ohm, then R2 would be 2k ohm.

Seems resolved?

Can someone explain to me how to use proximity for Raspberry Pi? I also get the "not yet implemented" and I can't see any usage/help for the code @sesh-kebab has written. help. I am trying to build a lib to control a initio robot built with pirocon controller

What is the current state of raspi-sonar @sesh-kebab? Once that module is ready, it will need to be integrated into raspi-io.

So @Workshop2 the short answer is, you can't use it yet, sorry.

@nebrius the status hasn't progressed since last post as I have been able to use my native extension raspi-sonar, side-by-side with raspi-io sorry.

I'll get my test circuit up and running again tonight and work towards having it ready to be integrated this week.

Another option is to use the GrovePi shield:

var five = require("johnny-five");
var Raspi = require("raspi-io");

var board = new five.Board({
  io: new Raspi()
});

board.on("ready", function() {
  // Use an Expander to create a Virtual board:
  var virtual = new five.Board.Virtual(new five.Expander("GROVEPI"));

  var proximity = new five.Proximity({
    board: virtual,
    controller: "HCSR04",
    pin: "D7"
  });

  proximity.on("change", function() {
    console.log("%dcm", Math.round(this.cm));
  });
});

@nebrius I'm trying to figure out what needs to be exposed from the native node plugin.

Proximity class usage sample looks like this:

var proximity = new five.Proximity({
    controller: ...,
    pin: "A0",
    freq: "25ms"    //note in milliseconds
  });

  proximity.on("data", function() {
    console.log("inches: ", this.inches);
    console.log("cm: ", this.cm);
  });

  proximity.on("change", function() {
    console.log("

What needs to be supported from rasp-io according to the io-plugins spec:

pingRead(settings, handler)
//settings object
{
    pin: 0,            //plugin spec says pin number but can that also mean 'A0'?
    value: "HIGH",  //what is this value and how should I take it into account?
    pulseOut: 5  //what is this value and how should I take it into account?
}

I'm assuming pingRead is all that is need to support the abstractions provided by Proximity i.e., data and change events.

One last question (for now), if someone wanted to stop taking readings from the proximity sensor, how will that need to be supported?

@sesh-kebab here's an initial recommendation for the raspi-sonar skeleton/API:

import { Peripheral } from 'raspi-peripheral';

export class Sonar extends Peripheral {
  constructor(config) {
    // Initialize here
  }

  read(cb) {
    // Calls the callback once read. Performs a single read.
  }
}

Then we can handle the whole Create a single data event, invoking handler once per read, continuously and asynchronously reading bit in raspi-io, similar to how we do digitalRead in raspi-io.

@nebrius thanks - that makes it a lot easier to implement from my side. I have made really good progress over the weekend here raspi-sonar.

Caveat:
  • I'm using wiringpi C library in my native node extension.
  • Accessing GPIO directly which will require root privileges i.e., sudo
Next steps:
  • Need to create a build script as part of the NPM install that
    • Downloads WiringPi. builds and installs
  • Will create an NPM package
  • Once I can get raspi-sonar down as an NPM package to any project and have it building, this is when I think I can start integrating into raspi-io. I expect to add raspi-sonar as a dependency to raspi-io and use it like below, based on your skeleton implementation.
import { Peripheral } from 'raspi-peripheral';
var pingReadExtension = require('build/release/raspiSonarExtention');

export class Sonar extends Peripheral {
  constructor(config) {
    // Initialize here
    this.sonar = pingReadExtension.sonarFactory(15);

  }

  read(cb) {
    // Calls the callback once read. Performs a single read.
    this.sonar.read(function(duration) {
        console.log('sonar.read callback called: ' + duration);
    });
  }
}
Questions:
  • Am I still on the right track?
  • Is the GNU LGPG v3 license that WiringPi is released under, going to cause any issues?

Great to hear!

I'm using wiringpi C library in my native node extension.
Is the GNU LGPG v3 license that WiringPi is released under, going to cause any issues?
Need to create a build script as part of the NPM install that
Downloads WiringPi. builds and installs
Is the GNU LGPG v3 license that WiringPi is released under, going to cause any issues?

raspi-gpio, raspi-pwm, and raspi also use wiringpi, so it's not a problem as long as you follow the same mechanisms they use. Notice how raspi depends on raspi-wiringpi, which in turn dynamically downloads wiringpi. This is important because GPLv2 is explicitly concerned with distribution, which by dynamically downloading means we're not distributing and get around the GPL license.

You should make sure that the wiring pi dependencies work the same as raspi-gpio and raspi-pwm, and then you'll be fine. The actual wiring pi dependency is implicit in those two packages, because it's explicitly defined in raspi, so in practice you don't have to do anything for wiring pi!

Am I still on the right track?

Yeah I think so. I would pay attention to the build process that gets put in place for the ES6 bits (feel free to borrow https://github.com/nebrius/raspi-gpio/blob/master/gulpfile.js wholesale for this). You may need to adjust the paths to the built native module, depending on where your build system puts the build JavaScript file.

Oh, and feel free to borrow anything else from raspi-gpio, especially binding.gyp, since it's slightly more complicated with NAN

EDIT: for the record, NAN is a requirement before raspi-sonar can be considered for inclusion in raspi-io, to ensure that raspi-sonar can be compiled against Node 0.10 through Node 5 (and beyond) without requiring lots of manual work.

Ok cool 😄 - didn't realise WiringPi was already in use. That should make things simpler again. And no problem for the NAN requirement; raspi-sonar is based on the NAN boilerplate extension.