Another Arduino Nano based obstacle avoiding /object finding Robot

I’m building another obstacle avoider/finder based on a few components controlled by an Arduino. I’m calling it QB

QB is a cube shaped (hence the name Cubee) so far fitted with:

  • a HC-SR04 sonar distance sensor (which look like eyes),
  • two chunky 66mm dia x 25mm wide wheels driven by geared DC mini motors
  • a free spinning ball bearing which acts as a sort third wheel and keeps QB level and stable)
  • two HC-020K optical switch encoders (1 for the axle of each wheel).
  • a ZK-5AD dual DC motor driver module based on the TA6586 IC (Note ZK-5AD is the brand/model name of the module) to drive the two DC motors.
  • 2 X 9V polymer ion rechargeable batteries. One for the Arduino Nano and sensors the other to power both the motors.

QB is controlled by an Arduino Nano MCU, mounted on a UNO/Nano prototyping shield that many convenient pin out options. I am aiming for “compact cuteness”. I may add other sensors in the future, but for now I want to be able to program QB to find several objects in say a 3mx3m arena, or to manage its way through a maze.

All of this has been done before and reported severally on YouTube and other forums such as this, but you may have noticed the HC-020K and the ZK-5AD are not common choices among those that have come before me…


I had a lot of trouble with the HC-020K encoder - It turns out that as supplied, they do not provide accurate counts per turn of the motor axle (read: they need to be modified to be of any use). This article explains why Optical Motor Speed Sensors (electroschematics.com). What is more, the discrepancy is different depending on whether the Arduino is powered by USB or by battery, making me think the problem was with the quality of the battery power and this set me on a very long very frustrating chase of wild geese. There are a couple of solutions to the problem described here and there on the internet. The easiest one to implement is to solder a 100nF capacitor between G and OUT on the HC-020K module. A 0.22 micro F capacitor works fine too.


Now for something I still have not solved (seeking your help)

The ZK-5AD driver requires inputs from 4 PWM capable pins on the Arduino Nano (2 for each motor). The only ones that are available to me for this purpose as Pins 5,6,9,10. The trouble is that the two motors spin at different speed even when I send them the same PWM value using the Arduino Analog-write() command the PWM vs Speed response is quite different for each motor too. The difference is large and impossible to compensate for in software. (There is no PWM setting at which the speed of the motors is the same)

I checked the resistance for each motor and both appear to be the same. When I checked the PWM signals coming out of pins 5,6,9,10 all have the same peak to peak voltage (5V), and the same RMS voltage for a given PWM setting but the frequency and width of the pulses on pins 5 and 6 are very different to the frequency and width of the pulses coming out of pins 9 and 10.

Microsoft’s AI bot Co-Pilot says that this is expected behaviour from those pins, that its likely to be causing the speed differences, and that for optimal DC motor control I need to change the Arduino’s internal timers, Timer0 and Timer1 so that the frequency of the PWM signals match and above are above 1 kHz, warning that this will also affect any code that uses functions like delay() and millis().

There are literally dozens of YouTube videos describing similar builds, and I’ve never seen any mention of needing to change the Arduino’s timers. I am hoping that someone here has do this sort of thing before and can confirm:

1- that the differences in frequency on the PWM pulses are the likely causes of for the motor speed differences (Note the PtP and RMS Voltage are the same)

2- That changing the Timers is an appropriate solution,

It looks like that part is equivalent to the more widely-known L298N.

This part is confusing me. It’s not obvious from everything else you say.

Why can’t you put a PID controller on each motor/direction channel separately? Two DC motors aren’t normally going to be exactly in sync anyway. That is, I wouldn’t expect a robot to go straight if you do something like

analogWrite(leftForwardPin, 255);
analogWrite(rightForwardPin, 255);
analogWrite(leftBackwardPin, 0);
analogWrite(rightBackwardPin, 0);

Here’s a conversation with someone who is using the standard arduino PID library that might be a valuable read:

You would of course need a separate PID controller for each motor/encoder pair.

Here’s a library that includes a PID controller and motor controller in a single file that you can read, and has an L298N reference example of using it. It might make PID control clearer? Or maybe not.

If you care here… Why not use, say, 9 and 10 for the forward direction and 5 and 6 for reverse, if you want to match them more closely? I’m guessing that you are using 9 and 10 for one motor and 5 and 6 for the other? Shouldn’t matter, because the motors won’t be perfectly matched anyway. :smiley:

Hi Michael, thank you for your great help as usual

I think you may have gathered that I am a bit above my depth here, but hey that’s the way I roll ;-).

Why can’t you put a PID controller on each motor/direction channel separately? Two DC motors aren’t normally going to be exactly in sync anyway. That is, I wouldn’t expect a robot to go straight if you do something like

My code does have PID control of sorts. That’s what I want to use the encoders for and why I spent so much time trying to get them to give me meaningful results. The full 0-255 spectrum of PWM using analogWrite is not available to me. Below 50 the driver does not pass enough power to the motors and the motor speed maxes out at about 80, so there is no point going higher. But I’ve measured both the forward and reverse speed at several PWM values using analogWrite and these are the results:

For simplicity I did not show it here, but the result is the same for FWD, REV, and when I swap which chip in the driver is used for which motor.

For the robot to move straight forward or backward the speed of the motors need to be the same. As you can see, in my set up there is virtually no PWM setting at which the motors run at the same speed, and there is no way that I would be able to get the robot to gently turn to the right as it moves forward (not important, but nice to be able to do) - All the PID control would be doing in my case is getting the right motor to run as slow as possible and the left one as fast as possible - That’s hardly control! (Isn’t that right? Am I misinterpreting the data?).

This information caused me to explore the differences between the arrangements for the two motors, and the only thing that I’ve found so far is a difference in the frequency of the PWM signal out of ports 5/6 and 9/10. (I’ve only thought of this as I write: I have NOT yet confirmed that the voltage going to each motor is different as a result… I better do that huh?).

As I said previously MS AI advice is that the frequency of the PWM signal does affect the operation of the motors in this way and that I could alter the operating frequency of Timer0 and Timer1 on the Arduino so that the PWM pulses out of Pins 5,6,9,10 are the same and above 1 kHz. But altering Timer 0 will also alter operations like delay() and millis(). Other options were even less appealing.

That’s a very creative solution! I don’t care if forward is faster than reverse! I only care that right is faster than left! and minor mismatches can be sorted by reinstating PID control. Rock your head @mcdanlj ! That’s one suggestion that the Microsoft AI did not make!

Thanks again! I’ll report back when I’ve solved the problem.

Staying one step ahead of the AI! :smiling_face:

Hi Michael, @mcdanlj

I kept everything as it was for now, and connected an oscilloscope to the motor terminals in the motor driver, which has a separate T6586 IC for each motor. When I connect either IC to Pin 5+6 on the Arduino the voltage going to the motor terminals is saw tooth shaped, 6 V RMS (confirmed with a multi-meter) and sawtooth frequency is ~ 500 Hz. When connected to pins 9+10 the frequency is ~1kHz and the RMS voltage is 7 V (also confirmed with multi-meter).

So the MS AI is correct, Pins 5&6 are controlled by Timer0 which operates at ~500 Hz and Pins 9&10 are controlled by Timer1 which operates at ~1kHz. The difference in frequency of the PWM signal out of the pins seems to significantly affect the voltage that the ZK-5AD driver sends to the motors, even at the same analogWrite() setting. Not all motor drivers have this problem - and this might explain why I haven’t seen posts describing a similar problem

I might try changing the timer settings so that both sets of pins send PWM signals with matched frequency to see what happens. As mentioned the effective range of PWM values is only 50-80. Perhaps changing the frequencies so that they are closer to the 8 kHz suggested will improve the effective range of PWM values to something closer to the expected 0-255.

Oh well, if everything worked the first time, I would not have learnt any of this!

I didn’t doubt that those timers were used for those pins; indeed, it was the source of my suggestion to pair them differently. :grin:

I had missed your point about the TA6586 IC. Oops. I finally found a datasheet for the TA6586, which is pretty sparse compared to the L298N datasheet. Besides the TA6586 being vaguely half of an L296N, the TA6586 datasheet has nothing about the internal architecture, nor any information on how fast it acts. The L298N datasheet, by contrast, has a table that includes this information:

Also, the pinouts are nothing alike, so the two may be conceptually similar to each other, but they aren’t equivalent. I see that some places market a dual-TA6586 board as an L296N board. (:rofl:)

It’s not obvious to me that higher frequencies would be likely to help, but without any concept of how the two TA6586 ICs on the board work inside, it’s hard to guess.

To test, you could write a sketch which does soft PWM on only one pin (and nothing else!) using delayMicroseconds() and step the frequency from much lower to much higher and watch what you get on the scope driving a motor. (If I had this on the bench I’d just hook up my signal generator since it’s even easier than writing a sketch, but I don’t know that you have one.)

Hi Michael,

Wow, you went to a lot of trouble! Thanks again for all your help.

The L298N based units with the large transistor and heat sink seemed a bit large to me. This is a consideration because its a bit cramped inside the small 90x 90 x 90 space.

Then I saw this video

In the Video RoboJAX concludes that the ZK-5AD driver is AMAZING because it can run at 12V and deliver 4A without a heat sink. The small form factor and efficiency appealed to me so I decided to try it. In hindsight, maybe I should have stuck with the very popular well characterised L298N based drivers.

Anyhow, earlier today I took a punt and I changed the frequency of both Timer 0 and Timer 1 on the Arduino. It was not as complicated as I thought. Changing Timer 0 had the forewarned effect of changing the behaviour of the delay() function and the results of the millis() function but both in a predictable way so problems there.

I changed both timers to run 7.89 kHz now as was recommended, and that has some other consequences: With the Timers at this frequency, the PWM_value working range (in analogWrite(pin#, PWM_value) ) changed from ~50 - 80 to ~ 140 - 255. I have not been able to calibrate the motor speed within this range yet, its possible that the speed maxes out at PWM values well below 255.

At the higher PWM frequency the speed of the two motors is much more evenly matched in fact at PWM_Value=150 the; left motor is slightly faster at 250 the right motor is slightly faster and at 200 the two are more or less equal in speed. So the change in timer frequency has made a huge improvement.

Unfortunately I also found out that the code that I wrote to compensate for small differences in speed doesn’t work - and the speed of both motors seem a bit too fast now… So I think that I solved the original problem, but I am not completely out of the woods yet.

In the fullness of time, I’ll have to think about whether the next iteration of QB will use a different encoder module and a different motor driver. We’ll see.

Thanks again, Michael I hope you enjoyed the post.

Jorge

Are you using the standard Arduino PID library?

I’d expect you would use a separate PID controller for each wheel and keep setting each wheel’s target speed.

I… don’t know whether the PID controller would need to be re-tuned for the change in the base timer rate!

There should be L298N driver boards that use the flush PowerSO-20 packages. Then I also found a board on Aliexpress that is US$0.99 for four pieces with free shipping, though it is an MX1508 board. The MX1508 uses MOSFETs rather than BJTs. The L298N proper seems (if its datasheet block diagram is trustworthy) to use BJTs. The only MX1508 datasheet I find is mostly in chinese; while it shows skew in the diagram, it don’t have any measurements with time units. GitHub - Saeterncj/MX1508: Arduino library for MX1508 dual DC motor driver is a library for it. I know nothing about it, I only see that it exists, and see that it doesn’t implement PID internally, so you would wire it up with a general PID controller.

I also wonder why not use an MCU with a more capable architecture for PWM control?

Hi Michael

Thank you for your interest.

Well, not sure that I can give you a rational answer here. as it goes a lot like: “To a hammer everything looks like a nail” - More precisely, I have a handful of A. Nanos and other bits and pieces that I have used successfully for other projects (including a small silicone rubber tensile testing machine). And there are SO many videos and other resources that use A. Unos and Nanos to control robots and motors etc.

Now that I think of it, in most of those videos the author grabs a Uno, a driver of their choice and gets the motor to spin a few times clockwise and anticlockwise - the end. In some videos the author adds an encoder and after a flurry of activity shows that the encoder provides an RPM value… (such videos never show that the RPM value is correct). :laughing:

So now I am realising what I am doing is a little bit more complicated :thinking: I actually want the encoder values to be correct and to use them to get two cheap motors mounted facing away from each other to turn wheels at a precisely controlled speed for a precisely controlled number of rotations. I didn’t really think of it that way until now, but I am starting to think that I am pushing some capability boundaries, my own included… :wink:

BTW the approach that I have taken is not PID speed control. QB will travel a specific distance (number of pulses on the motor encoder) in a predetermined way (forward, back, turn left/right, spin left/right). To travel forward or reverse in a straight line, the left motor and the right motor need to turn a specific number of turns at exactly the same but opposite speed, but I don’t actually care what the exact speed is. The code that I wrote tries to compensate for a lower number of pulses in the left motor encoder by speeding up the left motor.

I am reluctant to implement full PID control - did you read all the posts in the links to PID control in your earlier reply?

Yes! I looked back at how the L298N works and its quite different! The L298N needs 6 pins to run 2 motors, but only 2 need to be PWM capable. The TA6586 needs only 4 pins to run 2 motors but all 4 pins need to be PWM capable. The Uno and the Nano have 6 pins that are PWM (2&11, 5&6, 9&10) but each pair is controlled by a different timer configured to a different frequency by default. Pins 2&11 are being used for other things in my project. I thought that your idea to use pins 5&9 for one motor and 6&10 for the other is ingenious, but I opted to operate all four pins at the same higher frequency instead… We’ll see how that works…

Finally, you’ve been very kind and shown a lot of interest. I thought you might like to see a couple of photos of what I am trying to build. It needs a LOT of refinement. A task that I have put off until I iron out the issues that we’ve been discussing. I am aiming for QB to have programmable behaviour and I intend to make the CAD files, STLs, and component list available in forums such as this or elsewhere. That’s if I ever iron out all of these issues and finish it.

Half the fun is working within constraints anyway. :smiling_face:

:+1:

I at least skimmed through them. The OP may not have stuck around, but others provided example working code that worked for them experimentally.

PID is the classic algorithm here. There are others.

I’d still suggest just using the standard Arduino PID library and at least trying it. To travel in a straight line, for a particular distance, you want both motors to turn at the same speed for a particular number of counts. You can do all sorts of tuning if you like. If you know the left motor is typically slower, you can bias the initial value before handing over to the PID controller by some experimentally-derived proportional amount. You can start setting the I and D terms to zero and see whether it “hunts” or “jitters”

I found this video helpful for gaining an intuition for the terms in a PID controller.

Thank you for the photos! That’s a cute robot. :smiley:

Background: I tried for a while, years ago, to make a rolling ball robot with a beaglebone blue with a 9-axis IMU (that includes magnetic field sensor) and ended up not completing it. It isn’t trivial, it turns out, and I ended up doing other things instead. But I do appreciate some of the difficulty. :smiley:

I learnt the principles of PID control at Uni (40 years ago), but that video makes it really clear what each of the PID parameters does! And now that I can trust the encoder values it will be really simple to play with the parameters and see their effects. (When using the graph I showed earlier, I used a video because I could not trust the encoders.)

Perhaps I will try PID control with the set point being the difference in count between the two encoders, LeftCount - RightCount is = 0. If the difference is negative then I could alter the difference between the speed of the motors in accordance with PID parameters. I think that this may work well when going straight forward, straight in reverse and spinning in either clock direction.

If I ever want for the robot to travel in a curve, I will have to think of something else because in that situation I actually want both the count and the speed to be different left from right… Anyway , I’ll persevere. But it may take a while because a number of other projects are calling. :slight_smile:

In the meantime I am really happy that I have solved the Encoder and Motor Speed mysteries and with how much I’ve learnt in the process.

Keep on keeping on - I’ll post again when I can.

PS: with both Timer0 and Timer1 at 7.8 kHz the two motor speeds are much closer to being the same. The PWM value vs RPM graphs actually cross, that is: there is a PWM setting at which the RPM of the motors is the same! That’s a much better starting position for fine motion control.

1 Like

Hi @mcdanlj Michael

I’m re-reading the whole thread and realised that I hadn’t taken in one of your suggestions, which is to have PID control independently on the speed of each wheel.

That may be more flexible if for some reason I actually want the speed of the wheels to be different.

I’ll keep thinking.

1 Like

Oh, it’s absolutely essential to have a separate PID controller for each wheel, yes! And if they act a little bit differently, you can provide separate PID parameters for each side until they go straight.