Students created a machine that lifts a weight. It starts when button is pushed, stops when reaching upper limit, reverses direction on next button push, stops when reaches lower limit switch. This is a continuous loop. Problem we are having is direction does not always change. Can you please help me help my students?
task main()
{
int countValue=3;
while(1)
{
if(SensorValue[button]==1)////////////////////////////PUSH THE BUTTON IT RUNS ALL MOTORS POSITIVE DIRECTION
{
Right now, your direction-changing code is inside of an “else if” statement, which will only run if the “if” statement before it is not true. Because the “if” statement before it checks if the button is pressed, the direction will only try to be reversed if that condition is NOT true, so when the button is not pressed.
From what I read it seems that you want it to reverse the direction every other time it’s pressed (hence why you’re using modulus), so have it check to see if you should reverse INSIDE the actual “if” statement, because you want that to happen when the button is pressed.
Why not get rid of some of the conditionals? Just put a +/-1 along with countValue. Swap it each button press. Make the motor powers that value multiplied by the desired power amount.
Just to explain clearly what the problem is:
Pressing a button, the way the code is structured, is a state, not an event.
Your loop will run many times before you release the button, thus ticking the counterValue up by pretty much random number every time you press a button. Sometimes this increment ends up odd (behaves as expected), sometimes it’s even (no observed change in direction).
You need to recognize the button press event from the button press state. One way to do that is to keep a bool lastButtonPressed and only consider the press if !lastButtonPressed.
I’ll give you a chance to figure out the exact code yourself, but feel free to come back for more hints.
Yes, @nenik is right. You need some sort of delay whenever you read buttons or you end up reading them many, many times. But there is a simpler approach that handles a bunch of things together. Here is some pseudocode:
int goUp = 1;
while (true) {
if button is pressed {
set the motors to goUp*127
countValue++;
goUp=-goUp;
while(SensorValue[upper]==0 && SensorValue[lower]==0) {
wait1Msec(5);
}
stop the motors
}
}
Here the delay is forced by running until a limit switch is hit before going back to check the if statement. Now, if you’re not using countValue for anything else (like keeping track of the total), it can just be dropped. This has also assumed you don’t want to be able to reverse direction in the middle, but it sounded like you did not want that based on the original statement.
You’re still flying through this program at high speed. The program will finish its loop several times in the time it takes a person to press and release the button a single time. That means you’ll register a whole bunch of different things for one press. Look at what I wrote above about delays for button presses.
And, as mentioned by others, if you’re not hitting your button, you’ll go to the next option repeatedly.
You really need to change the approach. Look through what I wrote above.
Callen
I am truly stumped. I guess I don’t understand how to use a delay. I tried using what you shared and the motors would not change direction at all. What is the reason for the line
goUp=-goUp; //////what is this suppose to do? reverse motors? Why did you initially set it equal to 1? Does the 1 mean a value of 1 or does it mean “on”
Is my code close to being functional? I understand that the program loops very quickly when the button is pushed but I truly can’t figure out what everyone is telling me here. I asked an IT guy at school today and even he can not help.
Why not get rid of some of the conditionals? Just put a +/-1 along with countValue. Swap it each button press. Make the motor powers that value multiplied by the desired power amount.
How would I replace conditionals with +/- countValue
bool is a variable type that has a boolean value. Meaning it is either true or false. One typical use for a bool is for flag variables that are used in conditional statements.
The exclamation point is a logical “not” operator. It gives the logical negative of the term which follows the not. “not true” is false; “not false” is true. So, the pseudo code line “if !lastButtonPressed” should be read as “if not lastButtonPressed”. Since lastButtonPressed is of type bool, the if condition will only be true when lastButtonPressed is false.
I haven’t looked at all at the logic @callen presented, but suggesting a bool flag and testing it the way he/she indicates is a good sign that he/she knows a bit about this sort of thing
There are more flaws in the code anyway. For example, the end stop will still be in effect when you release the button (especially since we added the edge-trigger logic).
Let’s follow the logic starting with the elevator all the way up and count=3 when you press the button.
The button press event is (correctly) recognized, so the motors are started. In the “up” direction though.
The code quickly (think microseconds) skips the else branches and goes into the next loop iteration.
But even though you’re still likely holding the button, the first blocks gets skipped, since the button wasn’t released in the mean time.
As count is 4 by now, the second block gets executed, switching the motors to go down (good, what we wanted) and counting up to 5.
But the next loop iteration runs quickly again, skipping the first two blocks - button still held, and count is now odd.
The motors only had a chance to run for microseconds so far (in reality, not at all, there’s a delay in tens of milliseconds regardless of any system inertia), so the lift didn’t move yet.
So the last condition is true - the elevator still pressing the endstop and thus stopping the motors again.
I wonder if the elevator ever moved with the new code, or ever moved down with the old code.
Based on the above, you see your conditions need to be structured very differently. For example, you can’t check the upper end stop if your intention is to move down (and vice versa). How to write a working code depends on your planned learning outcome, i.e. whether you specifically wanted to showcase the modulo operator, or explicit state variable.
One way to structure the code (while loosing the above mentioned lessons) would be making the state implicit (encoded in the program counter position), like:
while (true) {
while (...) { // the elevator is down or raising
// handle upper endstop and possibly direction change
}
// fall through when done on or direction change
while (...) { // the evelator is up or going down
// handle lower endstop and possibly direction change
}
// fall through when done on or direction change, wraps around
}
Please try the code I sent you. I’m updating it from pseudocode here. This should make it reverse direction
int goUp = 1;
int motorValue=0;
while (true) {
if(SensorValue[button]==1) {
motorPower=128*goUp;
startMotor(rightMotor,motorPower);
startMotor(leftMotor,motorPower);
startMotor(midMotor,motorPower);
if(goUp==1) {// I don't know which + v. - is up or which is down for you, but you can swap them
while(SensorValue[upper]==0) {
wait1Msec(5);
}
else {
while(SensorValue[lower]==0) {
wait1Msec(5);
}
stopMotor(leftMotor);
stopMotor(rightMotor);
stopMotor(midMotor);
goUp=-goUp;
}
}