Though I've been thinking on and off about the smoothing code you posted it took me a while to get my head around it and I've been very busy so this is the first chance I have to tell you my take.
I LIKE IT, though of course I have some changes to suggest. I haven't done any "real world" testing, so there may also be some unintended consequences yet to be discovered.
First, lets see graphically what it does. The following was generated by a spreadsheet, not a Roboteq, and just shows what happens when the stick is held full forward with SpeedPotMin = 20.
The green line shows what Throttle does if pushed forward moderately quickly without any smoothing - it would be quite a bit steeper if one slams the stick forward. The yellow line shows how your algorithm adjusts the Throttle value that actually goes to the motors. The blue line shows the effect of moving-average damping (and I'll get to that later).
At speed below SpeedPotMin (20% of 1000) the yellow line overlays the green, but after 200 it is much shallower, but always above the speed line. This has two effects, both beneficial. First, brief changes in stick position will have a much more damped response than without this routine. Suppose you had reached speed = 600 and the stick jiggled back to 550. Without the damping Throttle would go from 1000 to 550 very quickly. But, with the damping routine, at speed = 500, the adjusted throttle is 680 (rather than 1000), and the change toward 550 will not only start from a less extreme value, but will take more time because it's following a shallower slope. Second, although there is substantial damping with the adjusted throttle value always > speed, the chair's acceleration is determined by the accel/decel parameters and the smoothing doesn't introduce any sluggishness. We get tremor or bump damping without any loss of responsiveness.
The amount of damping is not user adjustable, however - it's determined by the PotMin and PotMax values and the division by 20 in the line
- Code: Select all
TempPot = Pot - abs((Pot - (abs(SpeedLeft) + abs(SpeedRight))/20))
The values you've chosen seem good to you, but I don't know whether they'll work for all chairs and all users.
There's also no damping if you just release the stick to center. Then, Throttle = 0 and adjusted Throttle = 0 despite the other calculations. This probably isn't a serious limitation though because with hand off the stick you can't be jiggling it anyway.
Compare this to what happens with moving-average damping (blue line). With this, the slope of the Throttle line with the stick held steady at 1000 is just as steep as when there's no damping, except at the start and end of the acceleration. There, the slope is curved, but much shallower than the unmodified joystick value. Damping happens whenever the stick is moved, not when it's held steady, but the same S curve will be generated if the stick is moved at any speed - under 200, in the middle, at the top. It's easy to adjust the amount of damping - - average more cycles and you get more damping. But that's also exposes the worst "feature" of moving-average damping. If the number of cycles is too high, the damped change of throttle is slower than what accel/decel would do to speed and the chair gets sluggish. This was most obvious if I just released or centered the stick - deceleration got delayed, yuck.
So, I like what you've done so much that I'd like to put it in my system, test it out on the bench with dummy loads, and then in the chair. I have to solve a couple problems, one minor, one more interesting, in order to do this. The minor problem is that with a brushed controller and no encoders I do not have motor speed values. It's a minor problem because motor PWM is, for this purpose, an adequate stand-in for speed. The more difficult problem is that I don't do these calculations in the Roboteq but in the Joystick pod (MASTER module) and just send Throttle and Steering to the Roboteq over the CAN bus. The only connection to the Roboteq is the 2 wire CAN cable and there's a division of labor; MASTER handles all driving calculations and Roboteq handles all motor control calculations. To implement your code in my system exactly as you've written it would mean either moving the SpeedPot calculations to the Roboteq (and sending a Pot value message repeatedly from Master to Roboteq) or leaving the calculations in Master, but repeatedly send PWM1 and PWM2 values from Roboteq to Master. Neither solution is very elegant and the first is too much work, so I started thinking about whether the same kind of damping could be done in Roboteq after the final Throttle and Steering values have arrived, without involving the pot at all. The answer is yes; I can get exactly the same curve as generated by your routine, and get some advantages, by doing the following:
- Code: Select all
DampingStrength = 5
ThrottleAdjust = abs(Throttle) - (abs(Speed1)+abs(Speed2))/2)
Min = abs(Throttle/DampingStrength)
ScaledThrottleAdjust = ((abs(Throttle)-Min)*ThrottleAdjust)/abs(Throttle)
IF (Throttle >= 0) THEN
AdjustedThrottle = Throttle-ScaledThrottleAdjust
ELSE
AdjustedThrottle = Throttle+ScaledThrottleAdjust
END IF
SteeringAdjust = abs(Steering) - (abs(Speed1)+abs(Speed2))/2)
Min = abs(Steering/DampingStrength)
ScaledSteeringAdjust = ((abs(Steering)-Min)*SteeringAdjust)/abs(Steering)
IF (Steering >= 0) THEN
AdjustedSteering = Steering-ScaledSteeringAdjust
ELSE
AdjustedSteering = Steering+ScaledSteeringAdjust
END IF
This makes incorporating the smoothing algorithm into my system simple. I can just add this at the start of the SetMotors: subroutine and send AdjustedThrottle and AdjustedSteering to the motors (instead of Throttle and Steering). But there's another advantage.
Because pot values are neither used nor modified, I can now have a parameter that sets the strength of the damping without having to change pot min and max (which I might not want to do for other reasons). If DampingStrength = 1, there's no damping. If DampingStrength = 5, it duplicates what you get. If DampingStrength > 5 the damping gets stronger, with the AdjustedThrottle line getting asymptotically closer to the speed line as DampingStrength is increased. With DampingStrength = 10, it's twice as strong as with your routine (and damping starts at speed = 100 instead of speed = 200). With DampingStrength = 200, the AdjustedThrottle differs from Speed by no more than 5 (out of 1000) units, and movement is so damped that the chair may not move at all. HOWEVER, even at ridiculously strong damping the AdjustedThrottle curve is always above the Speed line so there's no change in acceleration/deceleration if the stick is deliberately moved. A "do what I say when I say it".responsiveness is not compromised.
I am going to be pretty involved with other things until mid September (and will be in Seattle for a couple weeks of October), but I will try to test this out before posting revised analog and CANbus scripts.