Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DC motor and Servo #309

Closed
leyenda opened this issue Mar 3, 2014 · 54 comments
Closed

DC motor and Servo #309

leyenda opened this issue Mar 3, 2014 · 54 comments

Comments

@leyenda
Copy link

leyenda commented Mar 3, 2014

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

@dtex
Copy link
Collaborator

dtex commented Mar 3, 2014

Leyenda,

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

@leyenda
Copy link
Author

leyenda commented Mar 3, 2014

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);
    }
});
});
});

@dtex
Copy link
Collaborator

dtex commented Mar 3, 2014

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?

@leyenda
Copy link
Author

leyenda commented Mar 3, 2014

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.

@dtex
Copy link
Collaborator

dtex commented Mar 3, 2014

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?
  4. Can I try it with your HTML/client side JS too?

-D

@leyenda
Copy link
Author

leyenda commented Mar 3, 2014

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.

@dtex
Copy link
Collaborator

dtex commented Mar 3, 2014

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

@leyenda
Copy link
Author

leyenda commented Mar 4, 2014

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

@dtex
Copy link
Collaborator

dtex commented Mar 4, 2014

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.

@leyenda
Copy link
Author

leyenda commented Mar 5, 2014

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.

@dtex
Copy link
Collaborator

dtex commented Mar 7, 2014

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.

@dtex
Copy link
Collaborator

dtex commented Mar 7, 2014

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.

@soundanalogous
Copy link

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.

@dtex
Copy link
Collaborator

dtex commented Mar 7, 2014

@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?

@leyenda
Copy link
Author

leyenda commented Mar 8, 2014

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

@leyenda leyenda closed this as completed Mar 8, 2014
@leyenda leyenda reopened this Mar 8, 2014
@leyenda leyenda closed this as completed Mar 8, 2014
@markwest1972
Copy link

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

@rwaldron
Copy link
Owner

rwaldron commented Mar 6, 2015

@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?

@markwest1972
Copy link

@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.

@rwaldron
Copy link
Owner

rwaldron commented Mar 6, 2015

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.

@markwest1972
Copy link

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?

@rwaldron
Copy link
Owner

rwaldron commented Mar 6, 2015

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.

@markwest1972
Copy link

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!

@rwaldron
Copy link
Owner

rwaldron commented Mar 6, 2015

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.

@dtex
Copy link
Collaborator

dtex commented Mar 6, 2015

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.

@rwaldron
Copy link
Owner

rwaldron commented Mar 6, 2015

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

@soundanalogous
Copy link

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

@markwest1972
Copy link

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! 👍

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.

@markwest1972
Copy link

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

@rwaldron
Copy link
Owner

rwaldron commented Mar 7, 2015

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 notifications@github.com 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
#309 (comment)
.

@rwaldron
Copy link
Owner

rwaldron commented Mar 7, 2015

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.rick@gmail.com 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 notifications@github.com 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
#309 (comment)
.

@markwest1972
Copy link

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!

@soundanalogous
Copy link

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

@markwest1972
Copy link

@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.

@markwest1972
Copy link

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

@soundanalogous
Copy link

@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.

@markwest1972
Copy link

@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

@markwest1972
Copy link

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 👯

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

@rwaldron
Copy link
Owner

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

@markwest1972
Copy link

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.

@Resseguie
Copy link
Collaborator

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

@markwest1972
Copy link

The older version.

@rwaldron
Copy link
Owner

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

@markwest1972
Copy link

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

@rwaldron
Copy link
Owner

@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.

@markwest1972
Copy link

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.

@Resseguie
Copy link
Collaborator

@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/

@markwest1972
Copy link

@Resseguie Thanks :)

@markwest1972
Copy link

@Resseguie
Copy link
Collaborator

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". :)

@markwest1972
Copy link

@Resseguie Good catch. Me fix.

@Resseguie
Copy link
Collaborator

@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.

@rwaldron
Copy link
Owner

@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

@markwest1972
Copy link

@Resseguie @rwaldron Thanks!

@alexcroox
Copy link

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!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants