Varying Motor Voltage Reduces Power Output

When 2 different motor voltages are alternated rapidly, the result appears to be slower than just the lower of the 2 voltages.

For example, if 127 power is applied for 10ms, then 126 power is applied for 10ms, and repeat, then the result is slower than a constant 126 power:

int iteration = 0;
while(1) {
  int pow = (iteration++ % 2 == 0) ? 127 : 126;
  leftDrive.move(pow);
  rightDrive.move(pow);
  pros::delay(10);
}

Videos

Here’s a video of this behavior for a drive (provided by Vincent from 10478K).
The first forwards motion is 127, and the second forwards motion is alternating between 127 and 126.

Another example in the context of a catapult: varying, constant.
In this video, I’m randomly changing the voltage, but I saw similar behavior when alternating between 127 and 126 power.

Questions

  1. What’s going on here at a hardware/VexOS level?
  2. Is this something that could be fixed by user code or a firmware update?
2 Likes

I can’t really tell anything from the videos. All I see is a robot driving forward then backwards. Do you have any non-subjective measurements ? Did you measure the speed of the mechanism ? Why would you even want to do this ?

4 Likes

I can’t really tell anything from the videos. All I see is a robot driving forward then backwards.

In the first video, the second forward motion is noticeably slower than the first forwards motion as the second is alternating between 126 and 127 power every 10 ms.

In the second video, the varying voltage causes the catapult to stutter, whereas with the third video (constant voltage) there is no stutter.

Do you have any non-subjective measurements ? Did you measure the speed of the mechanism ?

No, I didn’t have the time to make any actual measurements. When I do have the time, I want to try graphing the velocity over time.

Why would you even want to do this ?

Originally it was supposed to be an easy solution to this problem, since I figured it wouldn’t have much effect on performance. But upon testing, I found that was not the case. But this is an edge case, and not the main reason.

This also serves as an analog to the behavior of a pid/velocity controller (applied voltage might be changing every 5/10ms). Why does that matter? Well, we at LemLib have been thinking about updating the motor every 5ms rather than every 10ms to increase performance. But, if changing voltage causes a drop in voltage, then this increased update frequency would instead be detrimental to performance.

2 Likes

I did a very quick test using VEXcode, displaying motor speed on the screen, toggling between two voltages close to 12V, and didn’t notice any significant reduction in speed, however, the motor did not have any load so not exactly the same conditions as you had.

We are in the run up to worlds so really have no time to study what may be happening before May, however, a few comments based on your PROS issue.

First, there are a couple of translations going on from your 127/126 to the actual values sent to the motor. from PROS source code.

// Remap the input voltage range to the motor voltage
// scale to [-127, 127] -> [-12000, 12000]
int32_t command = (((voltage + MOTOR_MOVE_RANGE) * (MOTOR_VOLTAGE_RANGE)) / (MOTOR_MOVE_RANGE));
command -= MOTOR_VOLTAGE_RANGE;

so 127 becomes 12000, 126 becomes 11906
these are the values sent to vexos.

vexos then converts these into a pwm range that the motor supports, that’s +/- 100
so 12000 becomes 100 and 11906 becomes 99.

as you correctly theorise, vexos only sends a new pwm value to the motor if it has changed.

We do handle resending some parameters if a motor disconnects, but not previously set speeds, only things like current limits which are seen as a safety issue.

The motor firmware will only update the internal pwm if the mode has changed (ie. you entered voltage mode from some other mode) or every 10mS. pwm is also slew rate limited to reduce current transients (ie. we do not allow pwm at -100 to transition to +100 instantly), that should, however, have no impact on small changes of less than 25% of the range IIRC. The pwm will always be pushed through the current limiting algorithm and reduced if measured current is too high as well as the battery normalization algorithm that tries to compensate for battery voltage being different from the ideal 12V. so there’s a lot going on here and perhaps the motor has an issue when dealing with changing voltage that’s almost at maximum, I really have no idea.

5 Likes

x-axis: frequency of voltage change (hz)
y-axis: power loss (deg drifted when driving straight)

tested on continuous 100 power on left side of drivetrain and alternating 100/99 power on right side of drivetrain

I saw the video posted by OP and my first thought was “that looks like drive friction”. I’ve never noticed any behavior like this, so I tested it.

Using OPs code but forcing the left side to go 127, robot went forward and took a very hard right, and looked significantly worse then the video in OP. Strange… I ran the same code but forced both sides to go 127 and the robot goes perfectly straight.

I did some other tests, here is what I observed from them:

  • 127, 126 went straight
  • 127, 126-127 at 5ms fluctuation curved a lot
  • 64, 63-64 at 5ms went straight
  • 64, 60-64 at 10ms curved a little at the start then went straight
  • 120, 115-120 at 10ms fluctuation curved a lot
  • 64, 60-64 at 10ms with ~5lbs of weight added went basically straight

So this is a problem at higher voltages and stops being a problem at lower voltages. Maybe the 5lbs wasn’t enough to load the motors in the final test above?


I ran more tests but I recorded with an IMU the end angle. All of these tests were done around 100, 99-100. The goal of this test was to figure out the relationship between update frequency and how much the robot curves. I ran each test 3 times, and all of the data is below.

Control test 1. 100, 100 with 10ms, no power fluctuating. End angles:
0.5, -0.5, 0.1

Control test 2100, 99 with 10ms, no power fluctuating. End angles:
-0.3, -0.7, 0.3

  chassis.drive_brake_set(MOTOR_BRAKE_HOLD);
  int iteration = 0;
  int delay_time = 10;
  int fast = 100;
  for (int i = 0; i < 500; i += delay_time) {
    int pow = (iteration++ % 2 == 0) ? 0 : 1;
    chassis.drive_set(fast, fast - pow);
    pros::delay(delay_time);
  }
  chassis.drive_set(0, 0);
  pros::delay(50);
  printf("%f\n", chassis.drive_imu_get());

The code above was run for every test below, with the only difference being delay_time was changed.

10ms. End angle was:
21.15, 22.5, 22.4

20ms. End angle was:
21.1, 21.5, 22.5

25ms. End angle was:
18.5, 21.6, 18.2

50ms. End angle was:
13.0, 15.0, 14.5

100ms. End angle was:
3.9, 6.6, 9.0

200ms. End angle was:
1.5, 0.6, 1.5


It seems like this is correct. Load changes how this behaves.

4 Likes

Hi Jess

As you had done some analysis, I did spend a couple of hours digging into this today. It is a problem with motor firmware that causes pwm to be reduced when changes are sent quickly and are close to the maximum pwm value (ie. max voltage). I have a temporary fix, but would need much more testing before we would release anything as much of the complexity of the motor firmware involves transitioning between the different modes of operation (constant velocity, move to position, voltage etc.) and I did not even try that today. In any case, we would not release an update this close to worlds unless it was obviously giving an unfair advantage to teams, and this is the opposite of that.

4 Likes

I’m curious about this, and especially about how it impacts PROS’s decision (AFAIK) to keep the Cortext-style input range ([-127,127]) rather than the float(or are they doubles) values that Vex Code uses.

In that last line you mention vexos then converts these into a pwm range that the motor supports, that’s +/- 100 so 12000 becomes 100 and 11906 becomes 99. is the pwm range in vexos a integer in the range of +/-100 or is it a float/double in that range?

Maybe coming at it from the other perspective - would vexos deliver the same voltage to the motor from VexCode (sorry, I don’t remember the branding on Vex’s C++ implementation anymore) if the user requested11.952 Volts (99.6% of 12Volts) as if the user requested 12.0 Volts?

2 Likes

yes.

I don’t know exactly why we only used +/- 100 for the open loop control, I suspect it was a decision based on the IQ motor experience and needing to fit several variables into a single 16 byte packet for the motor. In hindsight it should have been done a little differently. Inside the motor the final pwm control has (more or less) 10 bit resolution.

4 Likes

Is there a chance of 10bit control in a future version of vexos?

1 Like

Is there a plan to release a fix for this any time soon?

No plan, probably never unless there’s some other reason to go back into the motor firmware.

1 Like