sandeepmistry / node-chip-io

Johnny-Five IO Plugin for the Next Thing Co. C.H.I.P.
MIT License
96 stars 28 forks source link

Feature Request: Software PWM #8

Open ericterpstra opened 8 years ago

ericterpstra commented 8 years ago

Not sure if this is possible or not, but more PWM pins would be nice. Seems like this lib has it working: https://github.com/xtacocorex/CHIP_IO

I'm not sure how to interface it with Node, though.

sandeepmistry commented 8 years ago

I think this is possible, not sure how accurate we can get with timing using node-ffi. node-webworker-threads might be of interest as well to do the threading like the CHIP_IO software PWM in JS. Otherwise we can always fallback to a native Node.js binding.

What kind of things were you think of controlling from the soft PWM pins?

This is not high on my list to work on, but would be open to merging pull requests that add support for this.

ericterpstra commented 8 years ago

Trying to build a functional sumobot jr. for a nodebots event, so two small continuous servos. I'm not sure how accurate/high freq. the timing needs to be to drive the servos (I don't know much about hardware in general, really).

I had a couple servos working with a raspberry pi and pi-blaster. The CHIP is better suited for our needs, as its smaller, cheaper, and has built in wifi and bluetooth. Happy to help where I can, but I'm only just starting to learn the hardware side of things. Webworker-threads look interesting!

ugate commented 8 years ago

@ericterpstra you might not get the resolution you'd normally expect from a hard PWM. CHIP has only one PWM pin and judging by your reference to servo_s_ I assume you want to drive more than one servo. Have you looked into something like the PCA9685 breakout board? You can pick one up from EBay/Aliexpress for about $3 and it can drive 16 PWM over I2C. I'm currently working with a few of those on CHIP myself.

ericterpstra commented 8 years ago

Thanks @ugate

Judging by the activity going on in this repo, it does seem like a PCA9685 is the best route. This is a bit off topic, but do you know the best way to power both the CHIP and PCA9685 from a single power source (battery pack or holder)?

ugate commented 8 years ago

@ericterpstra It really depends on what other peripherals that you're using, the voltage/amp hours they require, what cost versus efficiency you're looking for and how compact your project requires. If you want to use a regular lipo battery that hooks up to the CHIP's on-board JST connector you can do so, but I wouldn't recommend running any significant amount of current through the VCC-5V pin to power the servos on the PCA9685 via the terminal block connections. I could be wrong, but I think it can only handle ±100 mA. So, one option would be to get a few JST to 2-pin adapters or breakout boards with one of them leading to the JST on the CHIP and the other leading to a LM2596 DC-DC buck converter breakout which will power the 5v the terminal block on the PCA9685. If your servos are 3.3v you can simply remove the LM2596 from the mix. You can pick up a LM2596 module for about $1 on EBay/Aliexpress.

The project I'm working on now requires a 12v, 5v and 3.3v source and will be backed up by a solar panel. Below is an incomplete illustration, but basically a 5 watt solar panel is hooked up to a trickle charger that feeds into a 12v 5Ah deep cell battery. I'm using a high efficiency DC/DC converter that drops the voltage down to 5v from a 7 to 36 VDC source. I have another one that drops 12v to 3.3v. The breadboard's top 5v power rail powers the CHIP and the servos on the PCA9685 terminal block while the breadboard's bottom power rail supplies the PCA9685.

PCA9685

rwaldron commented 8 years ago

Very cool, I was going to suggest exactly that :)

@ericterpstra @ugate If you want to try the branch that I have which allows I2C bus number forwarding, install from my repo & branch:

npm install rwaldron/node-chip-io#11

Then, in your program:

var left = new five.Servo.Continuous({
  bus: 2,
  controller: "PCA9685",
  pin: 0,
});

var right = new five.Servo.Continuous({
  bus: 2,
  controller: "PCA9685",
  pin: 1,
});

(I'm just guessing on those pin numbers, adjust as needed)

sandeepmistry commented 8 years ago

@rwaldron's PR has been merged to master, I've also published v2.0.0 to npm which includes the changes.

ericterpstra commented 8 years ago

So I got a PCA9685 and am having some trouble getting it working. I ran the setup script from @ugate to enable i2c-2. Here's what my /sys/class/i2c-adapter/ looks like:

chip@chip:/sys/class/i2c-adapter/i2c-2$ ls
2-0038  delete_device  device  i2c-dev  name  new_device  of_node  power  subsystem  uevent

However, if I run the code above (with servos on pins 0 and 1), I get this error:

1471100709552 Device(s) C.H.I.P.
1471100709587 Connected C.H.I.P.
1471100709689 Repl Initialized
>> fs.js:101
      throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs
      ^

Error: ENXIO: no such device or address, write
    at Error (native)

I tried bus: 0 and bus: 1 but that didn't seem to do anything. No errors, but no movement either. Here's my actual code:

var five = require('johnny-five');
var chipio = require('chip-io');

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

board.on('ready', function() {
  var statusLed = new chipio.StatusLed();

  var left = new five.Servo.Continuous({
    bus: 2,
    controller: "PCA9685",
    address: 0x40,
    pin: 0,
  });

  var right = new five.Servo.Continuous({
    bus: 2,
    controller: "PCA9685",
    address: 0x40,
    pin: 1,
  });

  statusLed.blink(500);
  left.sweep();
  right.sweep();
});

The status LED blinks just fine. My hardware hookup is...

The power light on the PCA is on, and the servos work. I've tried 2 separate CHIP boards with the same result. Given my inability to get this working, as well as PWM0, I think I'm missing a setup step somewhere.

rwaldron commented 8 years ago

So I got a PCA9685 and am having some trouble getting it working. I ran the setup script from @ugate to enable i2c-2

According to: https://gist.github.com/ugate/392185a959737365834f54d5bf4aae5b#file-setup-sh-L231-L262, the bus being enabled is i2c-1—is that up-to-date?

A 4.8v AA battery pack attached

Alkaline or NiMH cells? (I promise I'm not trying to be dense ;)

Can you take a picture of your wiring and post it to this thread? Thanks!

nkolban commented 8 years ago

There is some strangeness with the current builds of CHIP OS. In 4.3 kernel, the I2C bus for TWI2 is "1" while in 4.4 kernel the I2C bus for TWI2 is "2"/

rwaldron commented 8 years ago

@nkolban ah—thanks for the clarification.

ugate commented 8 years ago

@rwaldron I think @ericterpstra has two issues.

His first attempt was connecting a TowerPro SG90 servo directly on PWM0 which is currently not supported in the current release due to an incompatible mode.

His second attempt was to use a PCA9685 connected to i2c-1 or i2c-2 (i2c-0 has no pins exposed on the header). i2c-1 has been disabled as of the 4.4 kernel to conform with how non-essential devices are disabled by default. The script enables i2c-1 in the DTB. I think this one is due to some inconsistencies in the libs.

There really isn't much error reporting yet. A lot of non-supported features just silently fail. I have been working on a pull request that should fix all of these issues. I have a few TowerPro SG90s and PCA9685s laying around that I'll test with before submitting.

ugate commented 8 years ago

@rwaldron As it stands there cannot be a device on two different I2C buses using the same address, correct? I was thinking of adding some additional i2cBusRead/i2cBusReadOnce/i2cBusWrite that take a bus argument to prevent breaking the API. It would be nice to be able to add a PCA9685 to i2c-1 and and another to i2c-2 without bridging/soldering the address contact points (or other I2C devices where address changes are not an option).

rwaldron commented 8 years ago

The underlying protocol doesn't support it, therefore the exposed API doesn't support it. The rationale is: if a thing can have more than one address, then one of the alternate addresses should be used.

I was thinking of adding some additional i2cBusRead/i2cBusReadOnce/i2cBusWrite that take a bus argument to prevent breaking the API.

The API here is defined by the IO-Plugin API, which presently has 15 independent implementations https://github.com/rwaldron/io-plugins. There is nothing stopping you from adding these methods, but they won't be usable with any Johnny-Five (the primary user of these implementations) component classes, as those are all expecting a uniform interface across every platform.

ericterpstra commented 8 years ago

I saw that there was a 2.0.1 release, so I thought I'd give this another go. Figured out some new things, but the servos are still not moving.

Here's my updated code:

var five = require('johnny-five');
var chipio = require('chip-io');

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

board.on('ready', function() {
  var statusLed = new chipio.StatusLed();

  var left = new five.Servo.Continuous({
    bus: 2,
    controller: "PCA9685",
    address: 0x38,
    pin: 8,
    specs: { speed: five.Servo.Continuous.speeds["@4.8V"] }
  });

  var right = new five.Servo.Continuous({
    bus: 2,
    controller: "PCA9685",
    address: 0x38,
    pin: 7,
    specs: { speed: five.Servo.Continuous.speeds["@4.8V"] }
  });

  statusLed.blink(500);
  left.sweep();
  right.sweep();
  this.repl.inject({ left:left, right:right});
});

The main differences are definitely using i2c bus 2 with 0x38 as the address, and forcing a 'speed' of 0.18, which corresponds to the 4.8V coming from my battery pack (4x AA rechargeable NiMH). I also tried non-rechargeable and 6V with the same result.

This time, there was no error, and I got the Johnny Five repl prompt. The statusLED was blinking as expected, but the servos did not respond. There were not sweeping, and when I tried left.cw() or other continuous servo methods, nothing happened.

I know the servos work, as I've tested them on an arduino. They also make a quick movement when the power pack is initially turned on.

I just unwrapped another PCA9685 and hooked it up to see if the original was broken, but get the same result.

As an additional troubleshooting step, I connected the PCA9685 to a raspberry pi (which I know works, b/c its running an i2c 1602 LCD). Using the Johnny Five PCA9685 example from the repo (with type: 'continuous' added), I got 1474625493410 Board Looking for connected device even though i2cdetect showed a device on i2c 1 address 0x40.

I feel like I'm taking crazy pills here, as everything looks fine, but is obviously not fine 😮

If it helps, here's the output from the REPL from left.cw(): https://gist.github.com/ericterpstra/2fb450eba5942871b195029f3f154ebb

Here's a (messy) picture, as well: img_2819

Please let me know if you have any other troubleshooting advice. Thanks!

sandeepmistry commented 8 years ago

Hi @ericterpstra,

Unfortunately the built-in PCF8574A IO extender is connected to I2C 2 and has address 0x38, I've added a note to the read me in https://github.com/sandeepmistry/node-chip-io/commit/669b0adc7409357b4f0e2c51de678c27d7545347.

Can you change the address of the device via jumpers?

It would be great if you can test #19 with some I2C devices (that don't use address 0x38).

sandeepmistry commented 8 years ago

@ericterpstra also you are plugging things into I2C port 1, see the diagram in the read me for which pins to use for I2C port 2.

ericterpstra commented 8 years ago

@sandeepmistry Good catch. I moved the I2C pins to the correct port. Also soldered A3, A4, and A5 to change the address of the PCA9685 to 0x38. Then pulled in your sync-io branch and tested again.

Still nothing.

Tomorrow I'll have access to an oscilloscope and logic analyzer (as well as an electrical engineer) to see if the board is working. I'll also test an I2C 16x2 LCD.

sandeepmistry commented 8 years ago

@ericterpstra thanks for the update.

Also soldered A3, A4, and A5 to change the address of the PCA9685 to 0x38.

Hopefully the address is a typo, as I mentioned in https://github.com/sandeepmistry/node-chip-io/issues/8#issuecomment-249332777, 0x38 is taken by the built-in PCF8574A IO extender.

P.S.: Maybe we can start a new issue for PCA9685 topic? This one getting a bit off topic from the original software PWM topic :)

ericterpstra commented 8 years ago

uhh... yeah. Sorry, disregard. Started a new issue: #20

rwaldron commented 8 years ago

@ericterpstra one thing to try: run a ground line between the external battery's ground and the board's ground. (That appears to be missing from our diagrams)