Johnny-five: DC motor and Servo

Created on 3 Mar 2014  Â·  54Comments  Â·  Source: rwaldron/johnny-five

Hello everyone, Im using an L298n to control one dc-motor and Im setting the arduino UNO pin 9 as PWM just how the documentation indicates.

this.pinMode(9, five.Pin.PWM);

Everything works great until I declare a servo

servo = new five.Servo(11);

After that the pin9 doesnt seems to be working as PWM and only enable the motor at 255 value.

Any help would be apreciate.
Thanks

Most helpful comment

This is why (see this link for a full explanation):

_The Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega. On boards other than the Mega, use of the library disables analogWrite() (PWM) functionality on pins 9 and 10, whether or not there is a Servo on those pins. On the Mega, up to 12 servos can be used without interfering with PWM functionality; use of 12 to 23 motors will disable PWM on pins 11 and 12._

The is because an Arduino board only has so many timers. One timer is dedicated to the Servo. This means there is one less timer available for PWM and on an Arduino Uno (or other ATMega328p - based board) you cannot use pins 9 and 10 for PWM when using a Servo. However you can still use a Servo on pins 9 and 10. Therefore in your case, attaching the Servo to pin 9 and the DC Motor to pin 11 should 'theoretically' solve your issue.

All 54 comments

Leyenda,

I might be able to help. Can you post your code so I can see these calls in context?

Thank you dtex this is the code:

var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
five = require('johnny-five');
io.set('log level', 1);
app.listen(3000);

function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}

res.writeHead(200);
res.end(data);
});
}

board = new five.Board();

board.on("ready", function() {

    servo = new five.Servo(11);
    servo.center();
    this.pinMode(12, five.Pin.OUTPUT);
    this.pinMode(13, five.Pin.OUTPUT);
    this.pinMode(9, five.Pin.PWM);
    board.digitalWrite(12, 1);
    board.digitalWrite(13, 0);


//board.repl.inject({
//     servo: servo
//   });

io.sockets.on('connection', function (socket) {
socket.on('cambio', function (data) {
    board.analogWrite(9, data.datos);
    console.log(data.datos);
});
socket.on('giro', function (data) {
    if(data.datos == 0){
        board.digitalWrite(12, 0);
        board.digitalWrite(13, 1);
        console.log(data.datos);
    }else{
        board.digitalWrite(12, 1);
        board.digitalWrite(13, 0);
        console.log(data.datos);
    }
});
});
});

Okay, I fired up your code and everything worked for me so I suspect this might be a power supply issue. Are you running your DC motor and servo straight off the Arduino power or are you using external power?

Im using a 12V DC source power for the L298n operational voltage with the motor(12V) and the arduino 5V for the servo and the L298n logic input, all grounds connected together.

That all looks good so I'm still scratching my head. I'm sure I'm asking things you've already considered but to make sure I'm covering the bases I'm going to ask anyways:

1) How you are checking the output value on pin 9?
2) Are you using the latest version of Johnny-Five (0.7.18)?
3) Could this be an implicit type conversion issue? What type is the value passed to data.datos on the 'cambio' event?
5) Can I try it with your HTML/client side JS too?

-D

Here is the client side:

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
$(document).ready(function() {
var socket = io.connect('localhost:3000');
$('#rango').change(function(e){
socket.emit('cambio',{datos: $('#rango').val()});
console.log($('#rango').val());
e.preventDefault();
});
$('#giro').change(function(e){
socket.emit('giro',{datos: $('#giro').val()});
console.log($('#giro').val());
e.preventDefault();
});
});
</script>
</head>
<body>
<h1>Por favor elija un rango de velocidad</h1>
<input type="range" id="rango" min="0" max="255" value="0">
<h1>Giro</h1>
<select id="giro">
  <option value="1">Horario</option>
  <option value="0">Antihorario</option>
</body>
</html>

Im gonna make a video to show you my connections and what is exactly happening.

That will be great. I'll keep any eye out this evening for the video.

Hello dtex thanks again, here is the video:
http://www.youtube.com/watch?v=5Ori4-tp0nk

Wow, great video. The soundtrack really puts it over the top. After work I'm going to try testing on hardware again. I want to make sure I didn't just set high on 9 and declare it working.

Thanks dtex, I'll be waiting for your testing results, maybe on friday Im going to try controlling the servo through a pin.PWM and not with the library, because I notice even without creating a new servo, just declaring

this.pinMode(6, five.Pin.SERVO);

Keeps the same result.

Leyenda,

I haven't solved it but I have been able to recreate it. Confirmed that it is nothing in your wiring or your H-Bridge. I can make it happen with nothing but the Arduino and some LED's.

It really looks like Johnny-Five is sending that correct mode and values for the pins to Firmata so I _think_ this is a Firmata or Node-Serialport issue. Honestly once it gets past Johnny-Five it's all magic elves and faerie dust to me, but I'll keep trying to figure it out.

This is why (see this link for a full explanation):

_The Servo library supports up to 12 motors on most Arduino boards and 48 on the Arduino Mega. On boards other than the Mega, use of the library disables analogWrite() (PWM) functionality on pins 9 and 10, whether or not there is a Servo on those pins. On the Mega, up to 12 servos can be used without interfering with PWM functionality; use of 12 to 23 motors will disable PWM on pins 11 and 12._

The is because an Arduino board only has so many timers. One timer is dedicated to the Servo. This means there is one less timer available for PWM and on an Arduino Uno (or other ATMega328p - based board) you cannot use pins 9 and 10 for PWM when using a Servo. However you can still use a Servo on pins 9 and 10. Therefore in your case, attaching the Servo to pin 9 and the DC Motor to pin 11 should 'theoretically' solve your issue.

@soundanalogous , I can confirm that this solved the issue on my test set up. Thank you for chiming in as I'm not sure how much sleep I would have lost trying to figure that out.

@leyenda , Did it work for you too?

Thank you guys for all your help!, That solves it.

Hello!

I just came across this issue while trying to solve a problem with my robot, which is based on an Pololu Zumo Chassis. I'm having the same problem, as the chassis motors are connected to pins 9 & 10.

When adding servos to my robot the net effect that I can no longer control the speed of these motors.

Unfortunately the robot is a bit tricky to dismantle, so I just wondered if you could think of any possible workarounds (alternative Firmata libraries)?

Thanks in advance for any help you can give me!

Mark

@markwest1972

Unfortunately the robot is a bit tricky to dismantle, so I just wondered if you could think of any possible workarounds (alternative Firmata libraries)?

Well, there is actually no software for any platform that can fix this because the Zumo is hard wired to use pin 9 and 10 for PWM speed control of the two motors. https://www.pololu.com/docs/0J57/5

When adding servos to my robot the net effect that I can no longer control the speed of these motors.

Are they connected to 9 and 10? What about using other PWM capable pins?

@rwaldron thanks for a quick reply!

Unfortunately, according to @soundanalogous, the servo library disables analogWrite() (PWM) functionality on pins 9 and 10. As the Zumo is hard wired to use pin 9 and 10 I guess I'm pretty stuck, no matter which pins I connect the servos to.

I see that this is a problem whether I use Johnny-Five or native Arduino :(

Anyway, I've posted a question on the Pololu forums, asking about the possibilities of requiring the Zumo. I guess I'll have to wait and see what they say.

Unfortunately, according to @soundanalogous, the servo library disables analogWrite() (PWM) functionality on pins 9 and 10.

It disables the literal call to analogWrite on those pins, but doesn't flat out disable them. Those two pins can still be controlled with a board.servoWrite(pin, 0-180) call (which results in a call to servo.write(pin, 0-180) on the board). All you'd need to do is five.Fn.map(speed, 0, 255, 0, 180) to map the speed value.

Ok, I just need to think about how that would work....

At the moment I used the following commands to set up and control the motors on the Zumo chassis.

var leftMotor = new five.Motor([10, 8]);
var rightMotor = new five.Motor([9, 7]);
....
leftMotor.fwd( 100 );
rightMotor.fwd( 100 );

How would I add the board.servoWrite(pin, 0-180) calls to this code?

Let's ask @dtex

I think it might make sense for the Motor class to use servoWrite internally, instead of analogWrite, but Donovan will know if there are issues with that.

In the meantime, give this a try:

five.Motor.prototype.setPWM = function(pin, value) {
  if (this.io.pins[pin].mode !== this.io.MODES.SERVO) {
    this.io.pinMode(pin, this.io.MODES.SERVO);
  }
  this.io.servoWrite(pin, five.Fn.map(value, 0, 255, 0, 180));
};

var leftMotor = new five.Motor([10, 8]);
var rightMotor = new five.Motor([9, 7]);

leftMotor.fwd( 100 );
rightMotor.fwd( 100 );

This just overrides the present definition of setPWM. I have no idea if it will work, but it seems like it should. If it does, then that buys time for Johnny-Five to implement proper support for the Zumo shield.

Thanks a lot! I'll give that a try tomorrow (it's wine o'clock here in Oslo and time to put the robot to bed for the night).

As always, thanks for your help! I really appreciate it!

Enjoy your evening!

As always, thanks for your help! I really appreciate it!

No problem :)

I will see about assembling my zumo as well and we'll get to the bottom of this together.

I had it in my head that servoWrite handled the value differently, but I found this in firmata.js:

https://github.com/jgautier/firmata/blob/master/lib/firmata.js#L657-L661

Board.prototype.servoWrite = function(pin, value) {
  // Values less than 544 will be treated as angles in degrees
  // (valid values in microseconds are handled as microseconds)
  this.analogWrite.apply(this, arguments);
};

So I don't see what difference it would make.

I had it in my head that servoWrite handled the value differently, but I found this in firmata.js:

Ah, yes. It's the pin's _mode_ that matters: https://github.com/firmata/arduino/blob/master/examples/StandardFirmata/StandardFirmata.ino#L299-L315

So you _could_ set the pinMode to 4 (servo) and still call analogWrite

So you can use board.servoWrite to drive a regular DC motor? Hummm, never thought of trying that.

Ok, just got up and done a test.

The good news is that it works! I am now able to control the speed of the motors! :+1:

The bad news is that the motors are now constantly buzzing / shaking. Another side effect is that the motors are now a lot slower / have a lot less power - to the point that the Robot isn't really moving.

These symptoms happens whether or not the additional servos are connected / declared in the code.

In case it helps, heres a link to my question on the Pololu Forum, where they suggested using different timers to control the servos and the motors.

http://forum.pololu.com/viewtopic.php?f=29&t=9622&sid=488bde4bb7bfaa341329eafcd3bfcc10

Slowdown and jitter is likely caused by the pwm range disparity between
servo.write and analogWrite (in the C program running on the board). I had
forgotten about that, and this is probably not the right solution.
On Sat, Mar 7, 2015 at 2:55 AM Mark West [email protected] wrote:

In case it helps, heres a link to my question on the Pololu Forum, where
they suggested using different timers to control the servos and the motors.

http://forum.pololu.com/viewtopic.php?f=29&t=9622&sid=488bde4bb7bfaa341329eafcd3bfcc10

—
Reply to this email directly or view it on GitHub
https://github.com/rwaldron/johnny-five/issues/309#issuecomment-77678432
.

For some extra dollars, you could add an adafruit pca9685 and get 16 servos
controlled via I2C :)
On Sat, Mar 7, 2015 at 10:25 AM Rick Waldron waldron.[email protected] wrote:

Slowdown and jitter is likely caused by the pwm range disparity between
servo.write and analogWrite (in the C program running on the board). I had
forgotten about that, and this is probably not the right solution.
On Sat, Mar 7, 2015 at 2:55 AM Mark West [email protected] wrote:

In case it helps, heres a link to my question on the Pololu Forum, where
they suggested using different timers to control the servos and the motors.

http://forum.pololu.com/viewtopic.php?f=29&t=9622&sid=
488bde4bb7bfaa341329eafcd3bfcc10

—
Reply to this email directly or view it on GitHub
https://github.com/rwaldron/johnny-five/issues/309#issuecomment-77678432
.

That's certainly one option! I'm also looking into remapping the 9 & 10 Pins on the Zumo Shield.

In the mean time let me know if you've got any other ideas you'd like me to try out. I have a test rig ready to go at a moments notice!

You could use an Arduino Mega, but it would overhang so that may not be ideal.

@soundanalogous I'm actually using a RaspberryPI, connected to the Zumo via an Arduberry. I'd like to keep all of this if possible, so the remapping option is currently my favourite. But I'll keep the Mega in mind.

@soundanalogous @rwaldron Just out of interest, does Johnny-Five / Firmata do anything specific with the various timers on the ATmega chip?

@markwest1972 StandardFirmata already uses all of the timers of an ATmega328p. The number of timers available depends on the specific microcontroller. An Arduino Mega more timers than an Arduino Uno even though both are in the ATmega chip family.

I don't think direct timer access via the Firmata protocol would be useful since you could not return any data when the timer interrupt fires (sending stream data is too big of a task to handle in an interrupt handler). It could be possible however to define higher level functions such as measuring pulse width but there would be a number of constraints. The pulse width would be calculated on timer interrupt, but it would only store the value. The value would be reported on the next iteration of the loop. While the value is being sent, interrupts should be disabled (to avoid breaking the stream transmission). This would prevent reliably reading a continuous pulse since you could miss an edge of the pulse when interrupts are disabled during data transmission.

If HW timers are exposed (via JavaScript somehow) on Linux-based boards (Edison, Galileo, etc) that would be a better approach for accessing timers than using Firmata. It's just too low level of a feature not to handle reliably without major tradeoffs.

@soundanalogous Thanks for your answer! I now have a better understanding of the challenges here.

If anyone else reading this thread is interested, I found this article to be informative : http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts

I just resolved this issue remapping the pins so that 9 and 10 are no longer used. For more information on how to do this visit this thread : http://forum.pololu.com/viewtopic.php?f=29&t=9622.

Really happy now, My PI Controlled Zumo now has a pan and tilt camera :dancers:

Thanks for all your help and answers to my queries! I can't say enough positive things about the J5 community!

So awesome! Can you do a write up for the wiki (and forth coming website :D)?

See the how tos here: https://github.com/rwaldron/johnny-five/wiki#how-to-guides

Can do. Got a lot on over the next week, but will get something down before Easter. Heres the Robot BTW.

markawest_2015-mar-12

She may not look like much, but she's got it where it counts, kid. I've made a lot of special modifications myself.

@markwest1972 Looks cool! Maybe I missed it earlier, but are you using the Zumo 32U4 or the older "Zumo for Arduino" version? Just curious.

The older version.

Oh wow—that looks like a bot I've been building this week :D

@rwaldron Nice! Do you have video of it in action?

@markwest1972 This project has become my albatross...

  • When using wall power, the board and code work perfectly. Once I switched to LiPo power, strange things started happening.
  • With a 4C, 2.25A LiPo, regulated by a 12V 3A (max) BEC:
  • The board failed to initialize the GPIOs necessary for the compiled bindings lib to detect which kind of breakout it was attached to: Arduino or Mini? It was detecting Mini, so therefore had all the pin capabilities wrong.
  • While refactoring the power source to use a BEC that regulated to 2A (max), I accidentally plugged in the power source backwards... So that Edison was toast.
  • Once I got my second Edison mounted to the board, I had to reflash, update and all that.
  • I installed all the camera drivers, just as I had before, but this time, they simply would not detect the camera. This lasted for two days, at which point I gave up and started from scratch.
  • I learned that the drivers come installed on the latest edison image, so I re-flashed following the directions given by Intel.
  • Oddly, this re-flash did not delete all of my own files in the home dir on the board (it should've).
  • BUT! The camera started detecting.
  • So then I spent time tooling around with the frame rate and kb/s of the video feed. For some reason, the code that worked on the previous Edison would just crash the new one.
  • Every change I make has a 50/50 chance of crashing the board, which means I have to reboot and all that shit and it's time consuming :(

And that's where I'm at so far.

Ouch! That sounds like hard work. It'll be worth it when you are done though!

If you fancy a break have a look at this : https://vimeo.com/122570460. My robot has come on a bit since Christmas, but I think it's now time to put the Zumo away and start with a new project.

@markwest1972 that's cool!

For completeness sake, here is a link to one of Mark's posts about this project. Others may also find it interesting:
https://utbrudd.bouvet.no/2015/02/20/unleash-the-potential-of-your-internet-of-things-project-by-combining-arduino-and-raspberry-pi/

@Resseguie Thanks :)

Seems straightforward enough to me. Thanks for the writeup!

My only minor comment is regarding "Doing this will permanently damage your Pololu Zumo!"

I'd maybe soften that to "may" instead of "will". Depends on your definition of "damage". :)

@Resseguie Good catch. Me fix.

@markwest1972 I added one more clarification that PWM is disabled on 9 & 10. It could have been read as "all PWM is disabled" with the previous wording.

@markwest1972 that's fantastic—thanks!

I made a couple minor edits:

  1. I saved your images to my public dropbox and updated the guide to display the images inline
  2. Set the syntax highlighter to "js" for the code at the end

@Resseguie @rwaldron Thanks!

I know this is closed, but just wanted to say you saved me hours (unfortunately after already spending hours!) debugging this problem with my motor driver + servo. Switching the servos to 9/10 instead of the motors fixed it instantly. Thank you!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

teuteuguy picture teuteuguy  Â·  4Comments

overflowz picture overflowz  Â·  9Comments

lezabour picture lezabour  Â·  12Comments

Spy474 picture Spy474  Â·  10Comments

peetj picture peetj  Â·  7Comments