Bang bang code?

Hi. I’ve heard many things about the bang bang code as a control loop and I’m just wondering what one looks like (Set up and all). Also, does it work well with single flywheels?

Thanks. :slight_smile:

Yes, it works well with flywheels.

if (flywheelSpeed > targetSpeed) {
    motor[flywheel] = 0;
} else if (flywheelSpeed <= targetSpeed) {
    motor[flywheel] = 127;
} 

Harrison, stop trolling :stuck_out_tongue:

“bang-bang” is a term for a very simple control loop, usually too simple to really be useful. It refers to any control loop that has only two states, one for when you are above the target value and one for when you are below. For a flywheel, you might tell the motors to speed up by a set amount if the flywheel is below the target speed, or slow down if the flywheel is above the target speed.

An example that might actually work (though not well) for a flywheel is something like this:

// (competition template stuff and functions go here)

// This code is for illustration only, it would not work well on a robot.

task usercontrol()
{
    /* 
    sensitivity controls whether the control loop responds slowly (will take longer
    to settle, but be gentler on the motors) or whether it responds faster. A higher
    value is more sensitive i.e. responds faster.
    */
    float sensitivity = 0.5;

    /* 
    tolerance controls the range of speed values that are close enough to the target
    for the robot to maintain its current speed. Higher tolerance will make the control
    more stable but less precise.
    */
    float tolerance = 1;

    /* 
    encoderReadings array contains the shaft encoder values in increments of 10ms
    for the last 100ms. These are used to estimate the current speed of the flywheel.
    */
    int encoderReadings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    while(1)
    {
        if (currentSpeed > (targetSpeed + tolerance){
            motorPower = motorPower - sensitivity;
        }
        else if (currentSpeed < (targetSpeed - tolerance)){
            motorPower = motorPower + sensitivity;
        }
        
        currentSpeed = getCurrentSpeed(encoderReadings);

        setFlywheelMotors(motorPower);

        wait1msec(10);
    }
}

A much better way to control a flywheel is to use the difference between the current speed and the target speed (called the error) to set the value, instead of just checking if the current speed is higher or lower than the target. A subset of this approach is proportional control, where the response is linearly proportional to the error.

is that all you guys have for the code? Is it that simple? just wondering. I’m looking for code also

Can you maybe supply some code for the control you are talking about Is it PID Control? Please post some code thanks a lot!
or send to me at zkw917@gmail.com

In this bang bang controller situation, what’s the best way of calculating the flywheel speed?
Can someone give example code?

I think what you do is you take the encoder value/rpm and map it on the range from value 1 to value 127? I’ m not very sure also.

Here is an example of a PC controller (what @Oliver W is probably referring to as a proportional controller).


float mtrConst = 70,
	kPFly = .05,
	target = 160; //target RPM of motor (you can scale this by your gear ratio to get the flywheel's speed)
int encNow,
	encLast = 0,
	timeNow,
	timeLast = 0;
const float ticksPerRev =  (784/3); //turbo motor conversion rate, change based on internal gearing
	/*torque = 627.2
	speed = 392
	turbo = 261 1/3 (784/3 to reduce rounding errors)*/
	
float velCalc() {
	encNow = SensorValue[flyEnc];
	timeNow = nSysTime;
	//multiply by 60000.0 and divide by tick-revolution conversion to convert from ticks/ms to rpm
	float vel = 60000.0 * (encNow - encLast) / (ticksPerRev * (timeNow - timeLast));
	encLast = encNow;
	timeLast = timeNow;
	return vel;
}

float flyPwr(float constPwr, float kP) {
	float err = target - velCalc();
	float P = err * kP;
	return P + constPwr;
}

//Overload setFly function for int and float parameters
//Makes manually changing motor power easier, but still accepts float variables
void setFly(int mtrPwr) {
	motor[fly1] =
		motor[fly2] =
		motor[fly3] =
		motor[fly4] =
		mtrPwr;
}

void setFly(float mtrPwr) {
	motor[fly1] =
		motor[fly2] =
		motor[fly3] =
		motor[fly4] =
		mtrPwr;
}

task main()
{
	while(true) {
		setFly(flyPwr(mtrConst, kPFly));
		wait1Msec(20); //Motors update every 20 ms anyway, prevents divide by zero errors in velocity calculations
	}
}

I do things a little bit weirdly, such as using non-void functions instead of a separate task, so if anyone has any questions, ask away. The only errors I got on it were for the motor and encoder names, since those were never defined in a #pragma. Also, it was written for 4 motors, to change that, add or remove motors from the setFly functions (only the float parameter one is used in this) as necessary.

I call it a PC controller because it uses only a Proportional term and a Constant term, but it is still a proportional controller. Think of it as an equation of motor power over error. The error is x, kP is the slope, and the constant is the y-intercept.


M = Pe+k
m = motor power
P = kP
e = error
k = constant

Also, as a side note, don’t map your encoder velocity between 1 and 127. That would only be useful if you set motor power to the encoder velocity, and that will achieve the exact opposite of what you want it to. As velocity decreases, motor power decreases, not increases.

How accurate is a PC controller on a flywheel? @lpieroni

A properly tuned PC controller can be really accurate, however, I don’t have a whole lot of experience with one. I understand the algorithm behind it, but my team has never used one. We use TBH instead, which I highly recommend. It’s not hard to write one, and it is way easier to tune. It doesn’t use a constant to maintain 0 error, so it reacts to changes in battery levels very well. One of the reasons we use it is that we have found our batteries to currently be operating at about half the rated capacity, so our voltage changes significantly during a match.
You can also take a crack at a TBH controller, which is. It has only one variable to tune, which makes . There are several threads about it on here, and it is discussed by a lot of people. Also, because it was popular in FRC in 2012’s Rebound Rumble, Chief Delphi has a few threads as well. Here is one with a C implementation about halfway down the thread, by Ether. It is very well explained, and the code is clean and easy to follow, even without any knowledge of C (all you need to know is signbit() gets the sign of a number, and num += x is the equivalent of num = num + x, just shorter).
If you have any questions about a TBH loop, I am happy to help.

Do you have any sample code for TBH I can look at? @lpieroni Thanks fir the help! I looked at the link you had, but I would like to see something for RobotC that uses TBH, four motors, and one IME as a sensor. Sorry for all the questions, I am new to programming code anything that tunes the speed of the motor.

Right here!
https://vexforum.com/t/flywheel-velocity-control-revisited/30480/1

More pearls of wisdom in here:
https://vexforum.com/t/tbh-tuning/30908/1

And add a discussion of using a weighted moving average in here as noise may effect the control loop:
https://vexforum.com/t/creating-an-array-within-a-struct-in-robotc/31788/1

Try it, graph it, adjust it, and then tune like crazy.

Here is a program I posted in another thread.


float kI = .025, //again, this is arbitrary
  mtrOut = 0,
  flyTarget = 800, //still arbitrary
  flyVel = 0,
  flyErr = 0,
  flyErrLast = 0,
  I = 0,
  TBH = 0;
int flyEnc = 0,
  flyVelTime = 0,
  flyEncLast = 0,
  flyVelTimeLast = 0;


//This is for a 4 motor flywheel, add/remove motors as needed, and change names if you want
void setFly(float pwr) {
  motor[fly1] =
    motor[fly2] =
    motor[fly3] =
    motor[fly4] =
    pwr;
}

task main {
  while(true) {
    flyVelTime = nSysTime;
    flyVel = (flyEnc - flyEncLast) / (flyVelTime - flyVelTimeLast);
    flyErr = flyTarget - flyVel;
    I += flyErr;
    mtrOut = I * kI;
    if(mtrOut > 127) {
      mtrOut = 127;
    }
    else if(mtrOut < 0) {
//Keep the motor power positive, to prevent damaging gears or motors
      mtrOut = 0;
    }
    
    if(sgn(flyErr) != sgn(flyErrLast) {
//If the sign of the error changes, then the error crossed zero
      TBH = (mtrOut + TBH) / 2;
      mtrOut = TBH;
      flyErrLast = flyErr;
//the last error doesn't matter unless the sign is different, so the last error is only stored when necessary
    }
    setFly(mtrOut);
    wait1Msec(20);
  }
}

Is there a way where the robot can do calculations when not pressing any button or anything?
Does it have to do with void, int. or something else?

It has to be in a task for it to run. It will be like driver control with a loop and everything.

I would recommend TBH for flywheels. Super easy to understand and works well with basic tuning. I can post mine( its a little more than the basic algorithm; I added feed-forward) if needed with comments.