Motor Jittering - any mistakes?

Hey guys, so I’m trying to use a proportional loop in order to keep both sides of my lift stable, so the program I have written makes it so that the lift side that is slower is the target and the other side will correct itself to stay level with the target, using potentiometers. But for some reason, one potentiometer is giving a lower value than the other, even though the lift sides are at the same level. In order to fix this (sort of), I just made the lesser value add 1350 to itself so that they are around the same area on both sides. However, when I tested my program without pressing any buttons, and I just moved the lift by hand , the correcting side tries to adjust to the target, but then it stops for a reason that I can’t find, then moves, then stops. It never actually reaches the target position, as the jittering causes the lift to shake and it goes back down. I’m really scratching my head at what I did wrong, so maybe you guys could help out? (Also, I’m doing this as a side project at home, and so I do not have access to parts at my school, and so all I have is just my computer, and the bot.) The parts that involve the correction of the lift are in the liftCorrection task, and I have already defined all necessary variables.

task correctionLift ()
{
	
	while(true)
	{
		rightLiftValue = (SensorValue[liftPotR] + 1350);
		
		correctionLiftError = rightLiftValue - SensorValue[liftPotL];
		correctionLiftProportional = correctionLiftError * correctionLiftKp;
		
		correctionLiftFinal = correctionLiftProportional;
		
//		motor[liftLeft] = correctionLiftFinal;
		wait1Msec(15);
		
	}
}


task chainPid ()
 {






   while (true)
   {

   chainError = chainTarget - SensorValue[chainBar];
   chainProportional = chainError * chainKp;
   chainFinal = chainProportional;
   sonarValue = SensorValue[liftSonic];
   motor[chainLift] = chainFinal;


		writeDebugStreamLine("chainTarget = %d, chainPos = %d, chainError = %d, chainFinal = %d", chainTarget, SensorValue[chainBar], chainProportional, chainFinal);
  wait1Msec(10);




   }
 }



task autonomous()
{

  motor[baseLeft] = 100;
   motor[midLeft] = 100;
   motor[baseRight] = 100;
   motor[midRight] = 100;

 motor[liftLeft]  = 0;
    motor[liftRight]  = 0;

   wait1Msec(4000);


     motor[baseLeft] = 0;
   motor[midLeft] = 0;
   motor[baseRight] = 0;
   motor[midRight] = 0;
}

/*---------------------------------------------------------------------------*/
/*                                                                           */
/*                              User Control Task                            */
/*                                                                           */
/*  This task is used to control your robot during the user control phase of */
/*  a VEX Competition.                                                       */
/*                                                                           */
/*  You must modify the code to add your own robot specific commands here.   */
/*---------------------------------------------------------------------------*/

task usercontrol()
{
  // User control code here, inside the loop
//startTask (liftPid) ;
startTask (chainPid) ;
startTask(correctionLift);
  while (true)
  {




   motor[baseLeft] = vexRT[Ch3];
   motor[midLeft] = vexRT[Ch3];
   motor[baseRight] = vexRT[Ch2];
   motor[midRight] = vexRT[Ch2];




  if (vexRT[Btn8L] == 1)
  {
  	motor[mogoLift] = 45;
  }
  else if (vexRT[Btn8D] == 1)
  {
  	motor[mogoLift] = -90;
  }
	else
	{
		motor[mogoLift] = 0;
	}

	 if (vexRT[Btn6U] == 1)
   {
    motor[liftLeft]  = 80;
    motor[liftRight]  = 80;
   }
   else if(vexRT[Btn6D] == 1)
  {
motor[liftLeft]  = -50;
    motor[liftRight]  = -50;
    }

   

    else
    {
   	motor[liftLeft] = correctionLiftFinal;
    motor[liftRight]  = 10;
    }

It’s a bit hard to follow with the odd indentation, the lack of comments, and the seemingly useless added variables. What I mean about the variables are things like

chainProportional = chainError * chainKp;
chainFinal = chainProportional;

motor[chainLift] = chainFinal;

where you could just write

motor[chainLift] = chainError * chainKp;

Even if you want to record the value, chainProportional and chainFinal never seem to have different values, so they are just duplicates that do nothing but use extra memory and confuse the code for readers.

I’m out of time for the moment, though.

Get a datalog (or add a debugging printout and log the debug stream to see what values did left and right pots report and what motor correction did your proportional controller applied. BTW: What’s your Kp value?

Now, consider this: Your lift holding value is apparently 10 (that’s what you use for right side), but for ballanced lift, you’ll keep the left side at 0.

Another thing to consider is the non-linear motor response, in relation to your Kp. If your lift is mis-matched just a little, it won’t try to correct (any motor value less than 20 is unlikely to move the lift at all). That means you may need more aggressive Kp or full PID. (other option is to use sign-corrected square of the error).

Finally, let’s talk about the potentiometers. They are noisy, non-linear and sometimes mis-firing. We had one that had a pretty consistent dip in the values read at some angle, so when you were raising the lift slowly (and having the pot values mapped to 0-100 on both sides), one side was reading 0 … 10 … 50 … 60 … 40 … 70 … 100. You can imagine what that did to the lift balancing.

Another thing we have run into was different curves - with both sides mapped to 0-100, the pots were reading about 0 on the low end, about 100 at the high end, but in the middle, one was reading 50 while the other about 54, so a perfectluy tuned PID with balancing, when going along the heights, would have the lift straight near the bottom, leaning significantly in the middle byt straight again at the top. For this, students made a testing rig, fixed 5 pots on a common shaft and did a full span logging the values. We have then picked the best matched pair of pots.