Controlling speed of 2 motors using encoder

what does it control to do that?

how is what @DaveX different from how i summarized what @UKHeliBob in post #5?

i think is a case where the I term is needed to maintain a non-zero output when the error is zero

bear in mind that the error is the absolute differnce in error (encoder count)

Thinking about my comments more, it may be matter of a distinction without difference. I think what both @UKHeliBob and I are saying is that you could use the encoder pulses to drive an up / down count. Say Right Encoder counts up and Left Encoder counts down. So, the counter’s value is always the difference in pulse count. I was hung up thinking that the suggestion was to count pulses from both encoders then subtract them. No need for that, up / down is fine. The PID then works to drive that delta to zero:

Exactly, the (I)ntegral term allows the controller to have a non-zero output even when the error input is zero.

1 Like

Don't use absolute error -- it will induce a discontinuity at error=0.

I think you might want to control the base-rate of encoder rotating/clicking separately, and calculate a bias one-way or the other depending on a rudder/steering wheel position. Zero might be an ideal target, but with real world wheels, surfaces, and manufacturing, you may need a bias of an extra few PWM counts of difference to go straight in physical space.

For example, maybe with a 20-hole wheel like this Adafruit disk, you get 80 counts/rotation, and at 60RPM or 1RPS you get a base rate of 80 counts/sec per side. Which suppose just happens to be about analogWrite(motorPinXX,127) with your drivers and power, but with the cross-grain of the carpet, you need +82cps and +127 PWM on the right and +78cps and +125 PWM to go actually straight.

One input to the whole control system is the +80CPS throttle from somewhere, another is the steering bias of +2/-2cps to the right coming from somewhere, and then the system need to read the encoders to feed the PID(s) so they add up to +126PWMs base with a +1/-1 bias PWMs to get to the final pair of pwms.

meant to say the error is the difference in absolute distance (not speed)

not following. 20 holes == 20 counts/rotation, right?

If you are using the Encoder.h, it counts 4 edges/hole.

wasn't. Don't most encoders have 2 outputs so that they can determin direction.

so was thinking just counting edges (or +/- edges from 2 wheels)

Yes, if you have two sensors you can determine direction from which sensor sees the hole first. 2sensors * 2 edges = 4 edges/hole.

Here's a Wokwi simulation of some DC motors (implemented by a custom chip acting as an ESC commutating the steppers) that can also give you encoder-like A+B quadrature information if you tap into the middle two pins of the steppers.

As far as the Arduino knows, they are DC motors controlled by PWM.

...And here's a hack of that simulation with Encoder.h encoders tapped into the steppers' quadrature signals:

Keep the rightmost column constant to go "straight":

@DaveX

i'd have to see simulation that monitors wheel speed and distance traveled to determine the course of the platform to see how well the algorithm works

that simulation would need to include different inertias and corresponding speed/Volt of the motors provided as parameters.

i'm curious if the algorithm could correct for short term deviations and put the platform back on the original target path

Is distance traveled to a platform is also an input to your controller?

The simulation I posted has the two pots as a throttle and steering/trim inputs, and produces PWMs signal to (simulated) DC motors. The simulated motors have an inertia-like feature in the ESC's Tau/timeConstant parameters, and the arduino monitors wheel position with (simulated) encoders. Using the average of the two encoder counts gives you a measure of (expected) distance travelled, and the difference between the counts gives you a measure of (expected) course. Differencing the "avg" and "diff" columns would give you a speed and yaw rate. Those measurements are enough information to give you open-loop control of course and speed. You could repurpose the simulation's pots to provide setpoints for speed and yaw rate (changes in "avg" and "diff" per unit time in the above simulation) and add PIDs to produce the throttle and trim signals they currently provide. throttle = PID(speed_setpoint,delta_average), and trim = PID(yaw-rate_setpoint,delta_diff).

If you want control systems with more inputs and external feedback beyond what the motor encoders can provide, draw up a block diagram of the system.

Once you know what the inputs and outputs are, you can begin to design the control system.

not the distance of the platform , the distance of both wheels in order to know position. The goal isn't to just travel straight, evenutally, it's to put the platform on a line and see it travel along the line.

this means if it iitially moves away from the line, it needs to move back to the line and then straighten out

I'm thinking the control system concept I showed in Post #22 should attempt to do that. It seeks to drive the difference in encoder counts between the two wheels to zero. Thus driving the number of turns (and distance traveled) by each wheel to become equal. How that works in the transient case depends on the loop's dynamics.

But, as already mentioned nothing you can do with the wheels alone will make up non-ideal behavior caused by wheel slippage or terrain.

i think this is challenging without worrying about slip

And there's nothing you can do about it anyway, without without more inputs ... Inertial Navigation, GPS, Line-Follower ....

If you think of driving the difference to a setpoint instead of zero, you can use the same control system for steering by adjusting the setpoint. Consider doing a 360° turn and then going straight--the difference in count (phase difference from #14) could be multiple rotations away from zero, and many more depending on how many turns the car needs to do.

Here's some data from the encoders in the #28 sim under manual control as the car drives forward, takes a turn, straightens out, and does other turns and pivots, etc.:

Encoder Positions
left, right, ave, diff
0 0 0 0
13 13 13 0
43 43 43 0
79 79 79 0
117 117 117 0
156 156 156 0
195 195 195 0
234 234 234 0
273 273 273 0
312 312 312 0
349 354 351 -2
364 416 390 -26
362 495 428 -66
355 579 467 -112
347 666 506 -159
337 753 545 -208
328 841 584 -256
318 928 623 -305
308 1016 662 -354
298 1104 701 -403
296 1185 740 -444
316 1243 779 -463
351 1288 819 -468
392 1325 858 -466
435 1360 897 -462
481 1392 936 -455
529 1422 975 -446
576 1452 1014 -438
624 1481 1052 -428
671 1511 1091 -420
718 1540 1129 -411
764 1570 1167 -403
810 1601 1205 -395
854 1633 1243 -389
898 1668 1283 -385
941 1704 1322 -381
984 1741 1362 -378
1027 1778 1402 -375
1068 1816 1442 -374
1108 1856 1482 -374
1147 1897 1522 -375
1184 1938 1561 -377
1223 1979 1601 -378
1261 2020 1640 -379
1300 2060 1680 -380
1340 2100 1720 -380
1379 2139 1759 -380
1418 2178 1798 -380
1457 2217 1837 -380
1496 2257 1876 -380
1535 2296 1915 -380
1574 2335 1954 -380
1614 2374 1994 -380
1653 2413 2033 -380
1692 2453 2072 -380
1731 2492 2111 -380
1771 2531 2151 -380
1810 2570 2190 -380
1849 2609 2229 -380
1888 2649 2268 -380
1927 2688 2307 -380
1967 2727 2347 -380
2007 2765 2386 -379
2070 2781 2425 -355
2149 2779 2464 -315
2236 2772 2504 -268
2324 2764 2544 -220
2413 2755 2584 -171
2503 2745 2624 -121
2593 2735 2664 -71
2683 2725 2704 -21
2773 2716 2744 28
2863 2706 2784 78
2953 2696 2824 128
3043 2686 2864 178
3133 2676 2904 228
3223 2667 2945 278
3313 2657 2985 328
3402 2649 3025 376
3472 2660 3066 406
3526 2685 3105 420
3574 2715 3144 429
3620 2746 3183 437
3672 2771 3221 450
3734 2787 3260 473
3814 2785 3299 514
3895 2774 3334 560
3942 2723 3332 609
3911 2599 3255 656
3819 2428 3123 695
3701 2240 2970 730
3574 2046 2810 764
3455 1850 2652 802
3343 1654 2498 844
3251 1468 2359 891
3156 1285 2220 935
3045 1092 2068 976
2928 896 1912 1016
2808 699 1753 1054
2699 510 1604 1094
2670 386 1528 1142
2694 313 1503 1190
2738 257 1497 1240
2790 209 1499 1290
2842 168 1505 1337
2878 144 1511 1367
2904 132 1518 1386
2924 127 1525 1398
2943 123 1533 1410
2961 121 1541 1420
2980 117 1548 1431
2998 113 1555 1442
3013 113 1563 1450
3025 115 1570 1455
3037 116 1576 1460
3049 118 1583 1465
3061 121 1591 1470
3070 125 1597 1472
3079 130 1604 1474
3087 136 1611 1475
3095 142 1618 1476
3103 148 1625 1477
3110 153 1631 1478
3118 159 1638 1479
3126 165 1645 1480
3134 171 1652 1481
3141 178 1659 1481
3148 185 1666 1481
3154 193 1673 1480
3160 200 1680 1480
3165 208 1686 1478
3171 216 1693 1477
3177 224 1700 1476
3183 232 1707 1475
3189 239 1714 1475
3196 246 1721 1475
3204 252 1728 1476
3212 258 1735 1477
3219 264 1741 1477
3227 270 1748 1478
3235 276 1755 1479
3243 282 1762 1480
3251 288 1769 1481
3259 294 1776 1482
3266 299 1782 1483
3274 305 1789 1484
3282 311 1796 1485
3290 317 1803 1486
3298 323 1810 1487
3306 329 1817 1488
3313 335 1824 1489
3321 341 1831 1490
3328 349 1838 1489
3333 358 1845 1487
3338 367 1852 1485
3344 377 1860 1483
3350 386 1868 1482
3356 395 1875 1480
3362 403 1882 1479
3368 411 1889 1478
3373 419 1896 1477
3379 427 1903 1476
3385 435 1910 1475
3391 442 1916 1474
3397 451 1924 1473
3403 460 1931 1471
3407 469 1938 1469
3412 479 1945 1466
3415 490 1952 1462
3417 502 1959 1457
3418 515 1966 1451
3418 529 1973 1444
3418 542 1980 1438
3419 556 1987 1431
3423 567 1995 1428
3429 575 2002 1427
3436 581 2008 1427
3443 587 2015 1428
3451 593 2022 1429
3459 599 2029 1430
3467 605 2036 1431
3474 611 2042 1431
3481 619 2050 1431
3488 625 2056 1431
3496 632 2064 1432
3504 638 2071 1433
3512 643 2077 1434
3520 649 2084 1435
3527 655 2091 1436
3535 661 2098 1437
3543 667 2105 1438
3550 674 2112 1438
3557 682 2119 1437
3563 692 2127 1435
3569 701 2135 1434
3575 710 2142 1432
3582 717 2149 1432
3590 724 2157 1433
3598 730 2164 1434
3605 736 2170 1434
3613 742 2177 1435
3621 748 2184 1436
3629 753 2191 1438
3637 759 2198 1439
3645 765 2205 1440
3652 771 2211 1440
3660 777 2218 1441
3668 783 2225 1442
3676 789 2232 1443
3684 795 2239 1444
3692 801 2246 1445
3700 806 2253 1447
3707 812 2259 1447
3715 818 2266 1448
3723 824 2273 1449
3731 830 2280 1450
3739 836 2287 1451
3747 842 2294 1452
3754 848 2301 1453
3762 853 2307 1454
3770 859 2314 1455
3778 865 2321 1456
3786 871 2328 1457
3794 877 2335 1458
3801 883 2342 1459
3809 889 2349 1460
3817 895 2356 1461
3825 901 2363 1462
3833 906 2369 1463
3841 912 2376 1464
3849 918 2383 1465
3856 924 2390 1466
3864 930 2397 1467
3872 936 2404 1468
3878 943 2410 1467
3885 951 2418 1467
3890 959 2424 1465
3896 966 2431 1465
3902 974 2438 1464
3908 982 2445 1463
3914 990 2452 1462
3920 998 2459 1461
3926 1006 2466 1460
3932 1013 2472 1459
3938 1021 2479 1458
3944 1028 2486 1458
3952 1035 2493 1458
3959 1041 2500 1459
3967 1047 2507 1460
3975 1052 2513 1461
3983 1058 2520 1462
3991 1064 2527 1463
3999 1070 2534 1464
4006 1076 2541 1465
4014 1082 2548 1466
4021 1089 2555 1466
4027 1097 2562 1465
4033 1104 2568 1464
4039 1112 2575 1463
4045 1120 2582 1462
4051 1128 2589 1461
4057 1136 2596 1460
4062 1143 2602 1459
4068 1151 2609 1458
4074 1159 2616 1457
4080 1167 2623 1456
4086 1175 2630 1455
4092 1183 2637 1454
4098 1190 2644 1454
4104 1198 2651 1453
4109 1206 2657 1451
4115 1214 2664 1450
4121 1222 2671 1449
4127 1230 2678 1448
4140 1245 2692 1447
4169 1275 2722 1447
4204 1312 2758 1446
4242 1352 2797 1445
4280 1393 2836 1443
4319 1434 2876 1442
4358 1475 2916 1441
4398 1516 2957 1441
4437 1557 2997 1440
4476 1598 3037 1439
4515 1639 3077 1438
4554 1680 3117 1437
4593 1721 3157 1436
4633 1762 3197 1435
4672 1803 3237 1434
4711 1845 3278 1433

Unless there are other inputs, these are the only sort of feedback data that a speed controller would have available.

Here's another data set with the deltas: 2-wheel average speed in counts/sec, and yaw rate in counts/sec:

Encoder Positions
left, right, ave, diff, d_avg, d_diff
0 0 0 0 0 0
17 17 17 0 17 0
57 57 57 0 40 0
103 103 103 0 46 0
152 152 152 0 49 0
203 203 203 0 51 0
250 250 250 0 47 0
287 289 288 -1 38 -1
314 318 316 -2 28 -1
333 338 335 -2 19 0
346 353 349 -3 14 -1
352 361 356 -4 7 -1
348 359 353 -5 -3 -1
341 353 347 -6 -6 -1
335 350 342 -7 -5 -1
335 352 343 -8 1 -1
337 355 346 -9 3 -1
338 359 348 -10 2 -1
340 362 351 -11 3 -1
342 366 354 -12 3 -1
344 370 357 -13 3 -1
346 374 360 -14 3 -1
348 378 363 -15 3 -1
350 382 366 -16 3 -1
352 386 369 -17 3 -1
360 396 378 -18 9 -1
445 482 463 -18 85 0
601 638 619 -18 156 0
784 821 802 -18 183 0
976 1013 994 -18 192 0
1172 1209 1190 -18 196 0
1368 1405 1386 -18 196 0
1564 1601 1582 -18 196 0
1760 1797 1778 -18 196 0
1956 1993 1974 -18 196 0
2152 2189 2170 -18 196 0
2349 2386 2367 -18 197 0
2545 2582 2563 -18 196 0
2741 2778 2759 -18 196 0
2937 2974 2955 -18 196 0
3133 3170 3151 -18 196 0
3329 3366 3347 -18 196 0
3525 3562 3543 -18 196 0
3721 3758 3739 -18 196 0
3917 3954 3935 -18 196 0
4113 4150 4131 -18 196 0
4309 4346 4327 -18 196 0
4505 4542 4523 -18 196 0
4701 4738 4719 -18 196 0
4898 4935 4916 -18 197 0
5094 5131 5112 -18 196 0
5283 5327 5305 -22 193 -4
5448 5523 5485 -37 180 -15
5604 5719 5661 -57 176 -20
5756 5915 5835 -79 174 -22
5907 6111 6009 -102 174 -23
6056 6307 6181 -125 172 -23
6206 6503 6354 -148 173 -23
6356 6699 6527 -171 173 -23
6517 6895 6706 -189 179 -18
6690 7091 6890 -200 184 -11
6869 7288 7078 -209 188 -9
7052 7484 7268 -216 190 -7
7238 7680 7459 -221 191 -5
7423 7876 7649 -226 190 -5
7609 8072 7840 -231 191 -5
7797 8268 8032 -235 192 -4
7986 8464 8225 -239 193 -4
8175 8660 8417 -242 192 -3
8363 8856 8609 -246 192 -4
8553 9052 8802 -249 193 -3
8745 9248 8996 -251 194 -2
8938 9444 9191 -253 195 -2
9130 9641 9385 -255 194 -2
9324 9837 9580 -256 195 -1
9520 10033 9776 -256 196 0
9716 10229 9972 -256 196 0
9912 10425 10168 -256 196 0
10108 10621 10364 -256 196 0
10305 10817 10561 -256 197 0
10500 11013 10756 -256 195 0
10697 11209 10953 -256 197 0
10893 11405 11149 -256 196 0
11089 11601 11345 -256 196 0
11285 11797 11541 -256 196 0
11481 11993 11737 -256 196 0
11677 12190 11933 -256 196 0
11873 12385 12129 -256 196 0
12067 12581 12324 -257 195 -1
12238 12755 12496 -258 172 -1
12360 12882 12621 -261 125 -3
12427 12955 12691 -264 70 -3
12445 12978 12711 -266 20 -2
12426 12963 12694 -268 -17 -2
12346 12887 12616 -270 -78 -2
12205 12750 12477 -272 -139 -2
12029 12578 12303 -274 -174 -2
11839 12392 12115 -276 -188 -2
11644 12201 11922 -278 -193 -2
11448 12008 11728 -280 -194 -2
11252 11816 11534 -282 -194 -2
11056 11624 11340 -284 -194 -2
10860 11431 11145 -285 -195 -1
10664 11238 10951 -287 -194 -2
10500 11078 10789 -289 -162 -2
10406 10988 10697 -291 -92 -2
10367 10952 10659 -292 -38 -1
10350 10940 10645 -295 -14 -3
10340 10933 10636 -296 -9 -1
10331 10928 10629 -298 -7 -2
10323 10924 10623 -300 -6 -2
10315 10921 10618 -303 -5 -3
10309 10920 10614 -305 -4 -2
10305 10920 10612 -307 -2 -2
10302 10922 10612 -310 0 -3
10302 10924 10613 -311 1 -1
10302 10928 10615 -313 2 -2
10302 10932 10617 -315 2 -2
10302 10936 10619 -317 2 -2
10303 10939 10621 -318 2 -1
10306 10939 10622 -316 1 2
10310 10940 10625 -315 3 1
10313 10943 10628 -315 3 0
10317 10947 10632 -315 4 0
10321 10951 10636 -315 4 0
10325 10954 10639 -314 3 1
10329 10958 10643 -314 4 0
10333 10962 10647 -314 4 0

started building a simulation.
the problem is it goes straight but not is the right direction

2wd

if you need to know


awk '
function line (x0, y0, x1, y1, col)  {
    printf "color=%s\nnext\n", col
    printf " %8.4f %8.4f\n", x0, y0
    printf " %8.4f %8.4f\n", x1, y1
}

# --------------------------------------
function mark (x0, y0, dx, dy, col)  {
    line(x0 - dx, y0,      x0 + dx, y0,      col)
    line(x0,      y0 - dy, x0,      y0 + dy, col)
}

# ----------------------------------------------------------
function disp (n)  {
    if (! (n % 10))  {
        printf "#"
        printf " %6s", "sec"
        printf " %6s", "vL"
        printf " %6s", "vR"
        printf " %6s", "rL"
        printf " %6s", "r"
        printf " %6s", "v"
        printf " %6s", "d"
        printf " %6s", "dA"
        printf " %6s", "ang"
        printf " %6s", "x"
        printf " %6s", "y"
        printf "\n"
    }

    printf "#"
    printf " %6.1f", sec
    printf " %6.2f", vL
    printf " %6.2f", vR
    printf " %6.2f", rL
    printf " %6.2f", r
    printf " %6.2f", v
    printf " %6.2f", d
    printf " %6.2f", dA
    printf " %6.2f", ang

    printf " %6.2f", x0
    printf " %6.2f", y0
    printf " %6.1f", x1
    printf " %6.1f", y1
    printf " %6.2f", eL
    printf " %6.2f", eR
    printf "\n"
}

# ------------------------------------------------
function abs (x) {
    if (0 > x)
        return -x
    return x
}

# ------------------------------------------------
function adv (n) {
    sec += dTsec

  # if (0.1 < abs(vL - vR))  {
    if (1) {
        rL   = D * vL / (vR - vL)
        r    = rL + D / 2
        v    = (vR + vL) / 2
        d    = v * dTsec
        dA   = -180 * d / (Pi * r)
    }
    else
        dA   = 0

    w0   = (ang     ) * Pi / 180        # compass
    x1   = x0 - r * cos(w0)
    y1   = y0 + r * sin(w0)


    ang += dA
    w1   = (ang     ) * Pi / 180        # compass
    x2   = x1 + r * cos(w1)
    y2   = y1 - r * sin(w1)

    dx   = 1
    dy   = 1
  # mark(x1, y1, dx, dy, n+2)
  # mark(x2, y2, dx, dy, n+2)

    line(x0, y0, x2, y2, "cyan")
    disp(n)

    x0   = x2
    y0   = y2

    if (vL > vR) {
      # printf "# - rotating right\n"
      # exit
    }
}

# ------------------------------------------------
function pid (err)  {
    Kp   = 0.08
    Kp   = 0
    Ki   = 0.4
    Kd   = 0
    acc += Ki * err

    errLst = err

    return err * Kp + acc
}

# ------------------------------------------------
BEGIN {
    Pi  = atan2(0, -1)

    E   = 20            # tic/rev
    K   = 0.9
    Dia = 2             # in.
    D   = 6             # in. between wheels

    ang = 0
    x0  = y0 = 0
    vR = 1              # rev /sec
    vL = K * vR

    printf "thickness = 1.8\n"

    dx = 0.1
    line(-dx,    0, dx,   0, "dark-gray")
    line(  0,   -1, 0,   30, "dark-gray")

    dTsec = 0.1
    for (n = 0; n < 300; n++)  {
        eL += E * dTsec * vL
        eR += E * dTsec * vR
        vL = pid(eR - eL)

        adv(n)
    }
}' | tee 2wd.xgr

Umm, change to K=1?

Or if not that, you need to set your setpoint other than a 1:1 ratio:

If you were the control system and manually running the system, you'd have to steer/drive the system to one side to offset the K=0.9 bias between the two wheels. You need a way to enter that non 1:1 steering bias into your control loop.

that simulates that the motors don't turn at the same speed. if they did, there would be no need for any of this.

If you draw a big box around your system, how does the information that it is not going the right direction/the wheels are different sizes/it needs to move the one wheel more clicks than the other/etc. enter the system?

Even cheap little forward-straight/reverse-turn RC cars have a bias adjustment that sets "straight", you need something to tell the system it is biased.

of course the wheels are the same.

the problem is that not only do they not run at the same spd/volt, they also don't accelerate at the same speed. The motors i have tended to run nearer the same speed once they got up to speed, but the different accelerations caused an initial drift.

the platform is autonomous. there's no person to correct