pwm ouput limiting

hello,
ok, so say I have a robot controlled by two joysticks. I want to make it so I can simply press a button on either of the joysticks to increase the pwm value by 4 every time the button is pressed. (the robot has two motors for each side of the tank-style robot). this seems like a good idea, but it means I have to limit the maximum value for the y-axis on each controller to something like 138. this way I can add 4 to its power each time the button on the appropriate joy stick is pressed, without going over 254. is there a simple way to limit the joy sticks top output value to 138?

ps-I am aware that shaft encoders are the new fad, and are far more accurate, but this would simply be a way to help me learn the code better and it is a temporary fix to the problem untill I have some good time to understand how to program the shaft encoders.

thanks for your patience,
Stephen :ahh:

If I understand you correctly, then this should work. I can’t remember the exact two-joystick code, but this concept should be valid.


if (p1_sw_top)
{
  pwm01 = p1_y + 4;
  pwm02 = p2_y + 4;
}
if (pwm01 > 138)
  pwm01 = 138;
if (pwm02 > 138)
  pwm02 = 138;

thanks for the help. by the way, I meant 238, not 138. (just stating that cause I feel dumb :)) no matter, thanks for the help

however, that won’t work. because every time the code is read again, the new speed (238 + 4) will be reset right back to 238 again. considering the code is read every like twent-something milliseconds, the robot would never increase its speed.

be careful. This won’t work exactly as expected. The code above will increment the PWM value EVERY PROGRAM LOOP THAT THE BUTTON IS PRESSED FOR. While you may not press the button for very long, ALOT of program loops occur in this time and your pwm value will go haywire. To prevent this, you need to only increment once when the button is first pressed. An example of how to check if a button was jsut pressed goes somethign like the following:


int previous_Button_State = 0;

//check to see if the button was just pressed.
if (p1_sw_top & !previous_Button_State)
{
  //do stuff here
}
previous_Button_State = p1_sw_top;

thanks for the help. by the way, I meant 238, not 138. (just stating that cause I feel dumb ) no matter, thanks for the help

I was a bit confused as to why you are limiting it that low.
:wink:

Here’s a variation.
If you mean to increase the top joystick speed (originally 238) by 4 every time the button is pushed then you’ll need to preserve the last known value. Expanding on the Joshua and James examples (but only looking at one of the joysticks to simplify):


static unsigned char rightTopSpeed=238;
static char previous_top_Button_State = 0, previous_trig_Button_State = 0; //FALSE
 
if (p1_sw_top & !previous_top_Button_State)
{
	if (rightTopSpeed < 251) // Limit how high it can go
	{
		rightTopSpeed+= 4;
	}
	previous_top_Button_State = p1_sw_top;
}
 
// You might want to be able to decrement as well
else if (p1_sw_trig & !previous_trig_Button_State) 
{
	if (rightTopSpeed > 238) // Limit how low it can go
	{
		rightTopSpeed-= 4;
	}
	previous_trig_Button_State = p1_sw_trig;
}
 
if (pwm01 > rightTopSpeed)
	pwm01 = rightTopSpeed;
[font=Verdana]

[/font]

That should probably be

if (rightTopSpeed < 250) // Limit how high it can go

otherwise your top speed could go as high as 257 – which, i suspect, would cause unexpected results. :ahh:

You know, I actually thought about that too, but forgot to carry through on the thought.

Thanks Greg:)

would this code work to help keep the robot from swerving?(uses tank style control with pwm_01 and pwm_02 on one side and pwm_03 and pwm_04 on the other side of the robot) It should. also let me know if there are any errors in it.


	signed char distance = p1_y - p2_y;
	if (distance < 0)
	distance = -(distance);     //the absolute value of distance
	else if (distance <= 14)
	{
	p1_y = p2_y = (p1_y + p2_y)/2;
	}
	pwm01 = pwm02 = p1_y;
	pwm03 = pwm04 = p2_y;
        

the only possible problem I can see is how it converts (but doesn’t really convert) a signed char to an unsigned char (the pwm values). is this a problem?

No, p1_* is unsigned char. The problem may be, though, if the sum of p1_y and p2_y is greater than 255. This would cause wrap around. (eg, 128+128 equals 0).

this would work, though

p1_y = p2_y = ((long)p1_y + p2_y)/2;

Jamie’s example gets you closer to what you want to experiment with.
I have another quick note on your code:

signed char distance = p1_y - p2_y;

Will result in a compile error because the declaration of a variable (“signed char distance”) is fixed at compile time, and the value assigned can only be a constant. Since in this case p1_y & p2_y are variables and can be different each time the routine is called, to get past the compiler this would need to be expressed as:

signed char distance;
distance = p1_y - p2_y;

The first statement is evaluated at compile time (on your PC) and the second will be evaluated at run time (when your code is running in the controller).

Your method of correcting will expose another problem with driving straight.
The right/left drive trains are rarely 100% balanced. Manufacturing differences in the motors, team fabrication differences in the friction between the gears/sprockets, chains, slight binding and misalignment, the left/right balance of the robot, and so on. This usually means that to drive straight the motors on one side might get a pwm of say 200, while the motors on the other side need to get 180.

Now a driver corrects for this automatically through a little practice with the robot by pushing the throttle on one side a little more than the other until the robot is seen to be driving straight. If you implement your proposed scheme the code will override this minor correction on the part of the driver and it might actually be harder to drive straight.

(I have an ulterior motive here to introduce you to a primitive form of proportional correction, the first step into PID.)

An easy method is to slow the more powerful side down to match the less powerful side as a percentage of full power, e.g., if p1_y is positive…

stronger side power = p1_y - (p1_y/127 * constant)
weaker side power = p2_y

The simplest way to select constant is:

  • Run the robot at full power and note which side lags.
  • Pick a value for constant above, put it into the code and run the robot again.
  • Repeat until you are driving straight.

[font=Verdana]These corrective values will be different for driving forwards and backwards, so add an if statement for that.[/font]