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

Brownout2 #18

Merged
merged 24 commits into from
Feb 4, 2022
Merged

Brownout2 #18

merged 24 commits into from
Feb 4, 2022

Conversation

eggaskin
Copy link
Contributor

If this works for everyone, we will use this as a base for our subsystem power management/brownout. Please review.

dx44383 and others added 4 commits November 19, 2021 16:01
Ippyb
Ippyb previously approved these changes Jan 25, 2022

private ControllableSubsystem tankSubsystem;

// private ControllableSubsystem climbSubsystem;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alignment

Also, is there a reason you have an empty line between each subsystem? I would think they'd make a nice block of 4 or so line.


// private ControllableSubsystem shooterSubsystem;

private int currentCurrentLimit;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a personal style recommendation: when I name variables that correspond to physical things I like to append the units to the variable name. In this case it would be currentCurrentLimit_A. This way I can check units by looking at variable names.

proan
proan previously requested changes Jan 25, 2022
Copy link

@proan proan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see the current limits be constants at a minimum.


this.tankSubsystem = tankSubsystem;

currentCurrentLimit = 350;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Could these be constants, or will they change during a match?
  2. Are you sure you want to do integer arithmetic with these?


System.out.println("Checking for a brownout...");
// Check PDP voltage; if close to a brownout:
if (PDP.getVoltage() < 7) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does PDP.getVoltage() return an integer or a floating point number? You should make your comparison value match.

int channels = 0;

for (int channel : PDPChannel) {
sum += PDP.getCurrent(channel);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does PDP.getCurrent() return an integer or a floating point number?

//scale all subsystems by set (sensible) amount
for (ControllableSubsystem subsystem : subsystems) {
int currDrawn = subsystem.getTotalCurrentDrawn();
int tempscale = currDrawn - (int)(currDrawn*0.2);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned about all the integer arithmetic. Do we know what the expected range of values are here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard, because PDP.getCurrent() returns double, but CANSparkMax expects an int for setSmartCurrentLimit(). I can get rid of some of the intermediary int casts but it will still have to be cast to int in the end for scaling.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's do that. Since you measure in double let's use that for all the math and then cast (or better yet, design a rounding function) to an int for the current limit. CS math isn't quite the same as pencil-and-paper math, so it's best to stick with double for the math (that only has issues with equals, not multiplication and division).

public void setCurrentLimit(int limit) {
this.currentLimit = limit;

int motorLimit = currentLimit/4; //number of motors
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be careful with integer division. Do you know what happens for currentLimit not being evenly divisible by 4?

@ky28059
Copy link
Member

ky28059 commented Jan 25, 2022

Instead of having a checkPriority(ControllableSubsystem) method which returns an int from 1-n and then having to iterate to find the lowest priority, can we instead have a Queue<ControllableSubsystem> in order from low to high priority and have scale() keep popping from that? The only reason I can think of for this maybe being a little complex is converting the array in the constructor to a Queue; maybe we can assume the subsystems are passed in in order of priority?

@ky28059
Copy link
Member

ky28059 commented Jan 25, 2022

Although I suppose returning an int priority is better for dynamically updating priority based on conditions like whether the turret is ready to shoot or whether its climb time; in that case though, I think maybe a double priority would allow for better tuning?

for (ControllableSubsystem subsystem : subsystems) {
double currDrawn = subsystem.getTotalCurrentDrawn();
int tempscale = (int) (currDrawn * 0.8);
subsystem.setCurrentLimit(tempscale);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does brownout scaling set everything to a flat 0.8 scale while scale() sets everything to its minimums? Are there cases where the minimum value is above 0.8 * currDrawn and the brownout scaling is less harsh than normal scaling?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe that 80% should be a default value?
BTW this is a good design question to answer.

int lowPriority = 10; // This int should be higher than the number of subsystems

// If we've already scaled many subsystems, just scale more dramatically for everything
if (checked.size() > 3) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does scale() give up after 3 subsystems? Also, if brownout scaling is sometimes more forgiving than minCurrent, would this result in the lowest priority subsystems getting more power than if they had been scaled normally?

}

double currDrawn = lowestPriority.getTotalCurrentDrawn();
lowestPriority.setCurrentLimit((int) lowestPriority.minCurrent());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems pretty harsh, perhaps doing some math and scaling things proportionally would be better?


@Override
public double getTotalCurrentDrawn() {
return PowerController.getCurrentDrawnFromPDP(fLeftMotorPort, fRightMotorPort, bLeftMotorPort, bRightMotorPort);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this can instead be a getPDPPorts method and have PowerController call getCurrentDrawn itself.

@proan
Copy link

proan commented Jan 25, 2022

Regarding priorities for your mechs/modules, @ky28059 has raised some good questions:

  • Do priorities shift during a match (My thought is "yes" when you transition to "climb" but because that's the end phase, it doesn't significantly impact the priority system design)
  • How to represent priority? Is it a number, a position in a list or queue, or some other kind of custom class or datatype? (An example from Linux is the udev system, which uses integers from 00 to 99 with 99 being last and thus most important)

@@ -13,14 +13,21 @@
import edu.wpi.first.wpilibj.Filesystem;
import edu.wpi.first.wpilibj.GenericHID;
import edu.wpi.first.wpilibj.XboxController;
<<<<<<< HEAD
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Github made you commit merge conflicts? Have you resolved these or are they just on the branch?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, you should keep HEAD for all of these. The conflicts look to be from very old changes from before pathfollowing was merged.

I think Aditi bulldozed over my old commits when merging her branch with remote, so this merge readds those commits and makes it compatible with the new changes.
This allows easier shared logic between subsystems (an interface would require each subsystem to implement their own versions of every method as it does not have access to fields). The original idea was to use this for climb cleanup as well as brownout, but basically anything that needs to be shared across subsystems can exist here.
@ky28059
Copy link
Member

ky28059 commented Feb 2, 2022

The idea for weighted average (and priority setting) is for subsystems to be able to somewhat scale themselves based on current situations. For example, in InternalSubsystem.java,

@Override
public void periodic() {
    double priority = shotRequested ? 8.0 : 5.0;
    powerController.setPriority(this, priority);
    powerController.setPriority(turretSubsystem, priority);
    // ...
}

With weights, it was detemined that base * dynamic would give too harsh a difference between a subsystem with base priority 4.0 and a subsystem with base priority 2.0 (here, tank would get double the allotted current as turret for just existing). However, some form of multiplication would be really useful for being able to nuke the priority of a subsystem during something like climb; climbInit() might set a subsystem's dynamic priority to 0 so that during climb, current isn't wasted by being allotted to a deactivated subsystem.

Or we could do something else for climb, idk.

@ky28059
Copy link
Member

ky28059 commented Feb 2, 2022

image
image

The precise values of the base priorities can be played around with, but these values seem reasonable (comparing tank to turret when both are at resting dynamic priority and when turret is at a higher priority).

@ky28059 ky28059 requested a review from proan February 2, 2022 04:05
@ky28059
Copy link
Member

ky28059 commented Feb 2, 2022

Alternative brownout strategy from Liang:
Make sure at all times that the sum of the current limits of all the subsystems adds up to the sustainable current. When a subsystem begins to approach its limit (the ratio of used to unused current increases), allocate it more limit by taking limit from a subsystem whose ratio is lower.

This would naturally fix the climb (and climbInit) problem as climb will not use any current before the climb phase which means its limit would be distributed to other users (a similar process holds true for subsystems during climb).

I can attempt to implement this soon.

@ky28059
Copy link
Member

ky28059 commented Feb 2, 2022

Although, an issue with this approach is that in the scenario where the current draw is pushing the sustainable current there isn't really a clean way for a subsystem to say "my ratio might be the same as this other system but screw them and give me more power"

This makes the calculations a little less clean, but is needed to prevent subsystems "locking" when drawing 0 current (resulting in their limits being set to 0) as well as give each subsystem some breathing room.
ky28059
ky28059 previously approved these changes Feb 3, 2022
Copy link
Member

@ky28059 ky28059 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm self-reviewing here, but I think brownout is mergeable. The new plan is really really clean!! (and its one issue with minimum and 0 currents was just fixed). I know @proan brought up the difference between sustainable current draw vs sustainable voltage, but given that we'll be using new batteries I think we can measure the sustainable current value and trust that maintaining that will sustain the voltage at a desired level for the entire match.

@eggaskin eggaskin dismissed proan’s stale review February 4, 2022 23:41

changes were made

Copy link
Member

@ky28059 ky28059 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bugs that came up during testing were fixed so hopefully everything is working swell. The totalSustainableCurrent needs to be measured, as does limits for each subsystem, but this branch can be merged so that I can rebase shooter.

@ky28059 ky28059 merged commit caa612c into develop Feb 4, 2022
@ky28059 ky28059 deleted the brownout2 branch February 4, 2022 23:44
e3l pushed a commit that referenced this pull request Mar 5, 2022
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

Successfully merging this pull request may close these issues.

6 participants