As I’ve said in earlier posts, this year (In The Zone) my team is using RobotC for the first time. Programming in RobotC has given me a more detailed way of thinking about coding, as compared to easyC’s drag-and-drop limited interface.

A programming concept that I read a few months ago in a jpearman VEX Forum post (“RobotC – Bad Programming Habits“) was eye-opening enough for me that I thought I’d share it with other novice robot-programmers out there. The idea described here is perfectly doable—and recommended—in easyC as well; it’s just not an obvious thing to do given the interface.

The Trap

If you write your program as your brain walks through the steps of what you want to do, and you never circle back to look at the big picture, you can fall into various un-helpful programming habits. When writing a driver-control program, the thought process might be something like this: if I’m pressing button 6U or 6D, the motor will do XYZ; otherwise I want to control it with the joystick.

while (1) {
   if Button 6U pressed
      set motorA to xx
   else if Button 6D pressed
      set motorA to yy
   else set motorA to 0

   Joystick block connecting Channel 3 to motorA (if joystick
      moves more than deadband area)
}

What happens in the program’s execution, however, is that the motor value set by pressing the button is immediately overwritten by the joystick instructions. Let’s say the joystick is in the neutral position and I press 6U: each time through the loop it will send an instruction to set motorA to xx, and then just a moment later set motorA to 0 (based on the joystick position). This setup produces stuttering and jittering like you wouldn’t believe because the motor’s power is being changed in rapid-fire fashion between xx and 0.

OK, what if I switch these two—put the joystick first and button second?

while (1) {
   Joystick block connecting Channel 3 to motorA (if joystick
      moves more than deadband area)

   if Button 6U pressed
      set motorA to xx
   else if Button 6D pressed
      set motorA to yy
   else set motorA to 0
}

At the beginning of the loop, it sets motorA to my joystick value (let’s say 100 power), then very shortly thereafter it will see that I am not pressing button 6U or 6D, and then set motorA to 0 (the very last statement above). Again producing the super-spaz action of setting the motor to 100 and 0 in quick succession.

What I Would Normally Do

As jpearman points out in his post, one could certainly wrap each batch of commands (joystick & buttons) in an if–else tree. This method is fine in this simplistic scenario, and it is also what my team has been doing up until this point.

However, when you’ve got multiple functionalities, partner joysticks, etc., this strategy becomes cumbersome and very difficult to troubleshoot.

A Better Format

A better structure involves creating a variable to hold the motor power value during the loop, and then include ONLY ONE set-motor statement, down at the end of the loop:

define an integer variable, motorA_value

while (1) {
   motorA_value = 0; // resets to 0 at the start of each loop

   if Button 6U pressed set motorA_value to xx
   if Button 6D pressed set motorA_value to yy
   if Channel 3 value > deadband area, set motorA_value to
      Channel 3's value
  
   set motorA to motorA_value
   wait1Msec(20)
}

The most important thing about this structure is the second-to-last line above:

      set motorA to motorA_value

You do all your comparisons, calculations, machinations, chop, slice, and dice FIRST, and THEN you tell the motor to do just ONE thing. There is only one set-motor statement in the entire loop (easyC users: you would have only one motor block, located at the end of the loop; see next section).

This structure has the added benefit of being able to easily prioritize without a lot of nested coding. As written here, if buttons 6U and 6D happen to be pressed at the same time, 6D will take precedence because when it sets the value to yy, it overwrites the xx value set in the first line. THEN, if you happen to be pressing the joystick and a button at the same time, the joystick will take priority, because its assignment statement comes last and overwrites everything that came before it. If you want a different priority order, just rearrange the lines of code.

Notice that this structure is not an if–else hierarchy. Every statement is checked every time through the loop. Hierarchy is created by the order of the assignment statements, not by a nested if–else if–else tree.

Note also that there is a short 20 millisecond wait after the set motor command. This step does two things:

  • Allows RobotC’s task scheduler to move on to other processes that may be running; it needs a teeny wait in this loop to signal to the processor that it can move on.
  • Acknowledges the reality that there’s no point in giving motor commands more frequently than every 20ms, since it takes a certain amount of time for your command to find its way through the cortex, to the motor controller, to the motor.

The easyC Joystick Block

In easyC, the use of the joystick block is generally what leads to this trap. It’s convenient. You just drag it on over, boom. You’re done. But there is a better way that will allow you more control over your robot and more-sophisticated programming (and less super-spaz motor action).

To me, the joystick block always seemed like a black box. It’s such an integral part of easyC driver-control programming, and offered in such a neat little package that one is never prompted to think about what it’s doing under the hood.

If you look in your joystick function block area, there’s an item called GetJoystickAnalog. That block returns a numerical value representing the location of the joystick lever. Conveniently, the stick all the way at the top returns a value of 127, and all the way at the bottom returns –127. Sound familiar?

What the joystick block is doing for you is getting that joystick position (between –127 and 127) and setting the motor’s power equal to that value. It’s a 2-step process that gets handled in 1 step, with a friendly interface. (Arcade drive is slightly more complicated, but works the same way, using a combination of the x-axis and y-axis position of the stick. See my other post on how to program arcade drive.)

Joystick Code without the Joystick Block

Instead of dragging in a joystick block, drag over a GetJoystickAnalog block. Assign that value to a variable (in the example above, motorA_value), and then drag over a motor block and set its power level to motorA_value.

define an integer variable, motorA_value

while (1) {
   // xx is the channel you're using
   motorA_value = GetJoystickAnalog(Channel xx)
  
   motor block: motorA, power = motorA_value
   wait 20 milliseconds
}

Why would I want to do this? It’s more work, and it just does the same thing as a joystick block, right?

Yes, it is an extra step, but it’s worth it. Only by giving up the joystick block can you create the preferred coding structure as in the example above and open yourself up the same level of sophistication as RobotC programmers (see my post, Mapping Joystick Values—Totally Blew My Mind). If you want to stick with a joystick block, you’re limited to an if–else if–else tree, and run the risk of getting the nesting wrong and ending up with unusable jerky movement and/or code that’s very hard to decipher on the screen given the small number of code blocks/large amount of whitespace of the easyC interface.

Go on — give it a try, and move up to the next level!

Share this post: