Bot-twins :: Programming Transmitter Channel 5

Dear Bot-twins,
You posted the following on in the offical Q/A section. They won’t answer programming questions like this in that area. So I’ve posted it here and then other programmers can take a shot it answering it.

I’m not an EasyC person so I can’t tell you what to drag around. In mostly C psudo code:

[INDENT]//if the button is not pushed the value is ~128
if (rec2.channel5 > 200) then
[INDENT]while ( sensor6 == 1) PWM6=255;[/INDENT]
if (rec2.channel5 < 50) then
[INDENT]while ( sensor5 == 1) PWM6=0;[/INDENT]
[/INDENT]

Good luck!
Foster

That code will halt your control loop until the sensor connects.
To avoid that problem, you need the concept of “stored state” and a statemachine.
Here is a simple untested implementation that uses a variable p6 to store the state (want up = 255, or want down = 0 );


if ( rec2.chan5 > 200 ) then p6 = 255;  // go up
if ( rec2.chan5 < 50  ) then p6 = 0;    // go down
if (( uplimit == 0 ) and (p6 > 200) ) then p6 = 127; // stop up
if (( dnlimit == 0 ) and (p6 < 50) ) then p6 = 127;  // stop down
 setmotor(6,p6);  // do the motor only once per while loop

if chan5 is sending 127, then p6 is never changed.
once chan5 sends 0 or 255, then p6 is changed.
if p6 is non-idle, and the appropriate limit is set (==0), then p6 is set to idle again.
It is important to not initialize p6 everytime through the loop, other than with this code.
Coding the four if statements as one triple-nested trinary operation is left as an exercise for the obfuscationist.

Very good point. One plus for RobotC is that you could put the up/down sequence in a task. Then all the looping/check cycle is done by the system.

How about:
P6=127+(128*(rec2.chan5>200)uplimit)-(127(rec2.chan5<50)*downlimit)
?
The supra-obfuscationist

:)Thanks, everybody, for your help and for putting up with the fact that we re-asked the question without knowing it had been answered. Thanks also for the RobotC advice and the potential advantages inherent in it if we tackle that for the next game. Good luck to everyone who is headed to Dallas!

Looks good, even better than a nested trinary.
Standard C can safely assume that uplimit and downlimit (digital input sensors) are either 0 or 1, and that a comparison test (a>b) evals to either 1 or 0.

Although previous answers have been acknowledged, its still good to have discussion of coding choices. This answer was posted in the experts area:(somewhat condensed whitespace here)

 
      int rx2ch5; 
      int upLimit; 
      int downLimit; 
      rx2ch5 = GetRxInput ( 2 , 5 ) ; //Get Transmitter 2 , Channel 5
      upLimit = GetDigitalInput ( 5 ) ; // Get Limit Switch In port 5
      downLimit = GetDigitalInput ( 6 ) ; // Get Limit Switch In port 6
      if ( rx2ch5 > 127 ) // Top CH5 Button Hit
        {  SetMotor ( 6 , 255 ) ; }// Run the motor Full Speed Clockwise
      if ( rx2ch5 < 127 ) // Buttom CH5 Button Hit
        {  SetMotor ( 6 , 0 ) ; } // Run the motor Full Speed Counter Clockwise
      if ( upLimit == 0 || downLimit == 0 ) // Top Limit OR Bottom Limit Hit
        {  SetMotor ( 6 , 127 ) ; } // Stop the Motor

Because of the multiple SetMotor commands per while loop,
I predict the following negative effects of this code:

  • Holding down a button will jitter the motor through the limit switch.
  • Once that happens, to recover may also require holding down the other button.
  • If the jitter in either direction is zero, motor will be unable to lift off the opposite limit switch.

Recommendation: do SetMotor only once per motor, after checking limit switches and directions, as in previously posted examples in this forum.

jgraber,
I agree that the code you quoted above is not optimal. One minor (brain-faster-than-fingers syndrome, probably): You meant “do SetMotor only once per loop…”, didn’t you? I wholeheartedly agree that sending control signals only to countermand them a few machine cycles later is bad practice.

On a related point, you may have noticed that my one-line, algebraic approach does have a functional difference from how I understand your code to work. Mine requires that the button be held for the duration of motion. That is both a consequence of my approach and a characteristic I prefer. (The preference may be because I’m a safety engineer by trade.)

Lastly, when you referred to “one triple-nested trinary operation”, did you mean:


if (cond1) then (action1)
   else if (cond2) then (action2)
          else if (cond3) then (action3)
                 else (action4)

or


if (cond1) then (action1)
   else if (cond2) then (action2)
          else (action3)

As there are only three different actions to take (move up, move down, stop), I don’t see a need for the longer of these. My solution using this approach does use compound conditions (up button pushed and up limit not reached) and (down button pushed and down limit not reached), but I think the complex conditions are preferable to the brute force approach of:


p6=127
if (rx2ch5>200) then p6=255
if (rx2ch5<50) then p6=0
if (downlimit=0) then p6=127
if (uplimit=0) then p6=127

In practice, though, I doubt it matters which of the logic approaches one takes, as the uCTLR is probably far faster than either the machine or its operator. Setting the motor only after one has evaluated all of the relevant conditions, though, is important.

Eric

original quote: do SetMotor only once per motor,
OK, that could be confusing since it needs to be ‘done’ every time through the loop. While “do SetMotor only once per loop” would be able to update only one motor port…
I mean that only one SetMotor statement, for each motor port is needed in the main loop.

My bad; I failed to notice that you failed to meet the requirements.
It would have been good for you to point that out originally,
and your concerns for safety tradeoffs.

To meet the requirements, rather than some other problem,I believe >=3 conditions are required to select 4 actions ( start up, start down, stop, nochange); Can you demonstrate a working 2 condition solution?

That will lock up as soon as the limit switch is set, and never recover.

Do you have any different **working **solutions to the stated problem?

I don’t recall any mention of a second motor.

To what “requirements” are you referring? Relatedly, how, if all, does your proposed solution meet them?

Is that a lamentation or a thinly-veiled accusation of intellectual dishonesty?

I agree that it is (at best) impractical to write a mechanism to choose among four outcomes with only 2 condition statements. However, we appear to differ as to whether there needs to be a “nochange” result of the decision tree. If there does not, as I believe to be the case, then there are only three possible outcomes and only two condition statements are needed.

True, but I point out that I never said that code would work, just that it was “brute force”.

Different, pray tell, than which? I’m particularly interested in what you have decided is the “stated problem”.

In the interest of frankness: I do have a suspicion as to what “requirement” you believe you have met and I have not. However, I don’t think you’ve met it either. To avoid prejudicing your response to this posting, though, I’m not going to state my suspicion until I’ve received your reply.

TIA for your response,
Eric

It was late and my attempts at snarkiness reduction were insufficient.
I’ll try a snarkiness reset, and skip all the painful sub-quoting, and start over.

If you check the top of the thread, Foster quoted Bot-twins requirements as follows:

Thats what I refer to as the stated problem, the problem statement, the requirements.

It is certainly legit to comment when you think the requirements are unsafe,
but I intend to only provide code examples intended to meet those requirements in this thread.

It is the “single touch” requirement that requires the ability of “no change” in the decision tree. My interpretation of this requirement is that “a motor in motion should stay in motion” without holding down the button, until the limit switch at the end of that motion stops motion in that direction.

I’ve certainly not tested my previous solutions, so if you can point out their failures, you’ll be doing a favor to me, as well as to all future readers. I have an implementation intended to be simple to understand shown below in larger context.
Note that there are no elses, and it is possible for more than one condition to be triggered

p6 = 127; // initialize, or not, the default starting state should be off.
while(1){ 
  //.. do other motors, but dont change p6 or do setmotor(6,)
  // bucket control, single touch up/down on channel 5 runs until limit switch hit
  if ( rec2.chan5 > 200 ) then p6 = 255; // try to go up
  if ( rec2.chan5 < 50 ) then p6 = 0; // try to go down 
  if (( uplimit == 0 ) and (p6 > 200) ) then p6 = 127; // stop going up 
  if (( dnlimit == 0 ) and (p6 < 50) ) then p6 = 127; // stop going down
  setmotor(6,p6);   // update motor 6 with value of p6 just once per while loop
} // wend

I could stick an else after the first then, but it wouldn’t make it more clear.
I could combine the last two conditions with an or, but it wouldn’t make it more clear.
It looks like this is the best I can do for clarity, and likely for performance too.
I no longer think a nested trinary is a useful exercise.
A statemachine could be interesting, but only for its own sake, and would be vastly wordier than these 5 lines.

Your algebraic solution was this:


P6=127+(128*(rec2.chan5>200)*uplimit)-(127*(rec2.chan5<50)*downlimit)

While it is a lovely implementation of a limit switch,
and I like the demonstration of a (0 or 1) conditional as the multiplicative identity operator, it doesn’t have the “no change” option needed by the “single touch and release” requirement, so it will stop when you release the button, right?
I can’t figure out how to fix it either.