Vex Math Errors?

Recently I have been doing some relatively advanced math for my Vex robot (some isn’t that hard, some is a little more complicated), and every time I do, I make sure to test out the equations both manually (with a calculator), and in simulation (code them into a computer program and run them with test values on my computer). Once I get them working perfectly, I put them back into the Vex program, check everything out to make sure it’ll theoretically work, build it, load it, and bam, it doesn’t.

These are not mathematical miscalculations, all the math checks out. Neither are they variable overflows, I’m using variables that are plenty large for the application, and type casting them where necessary. These are instances where something just doesn’t work on the controller, and I can’t figure out what.

Specifically, the most recent ones have been for my holonomic drive program. I’ve had a holonomic control program working for a while, but recently I added in a scaling algorithm to make the joystick map to the speed and angle of the robot more closely. Basically, the individual wheel speed equations put the wheels at full tilt going forward/backward or left/right, but on the diagonals, there was a limited circle on the joystick you could move around before the equations overflowed the wheel speed variables, so I just capped them. This algorithm removed the need for capping and just scaled everything down to the wheel that was most out of range. In simulation.

In practice, if a wheel value gets out of range, all 4 wheels just stop.

Also, I tried halving the speed of an arm control motor by feeding it ((value-127)/2)+127 (so you can drive the motor slowly with a digital channel). It works great, but only in one direction. If you hit one button, the motor moves in one direction. If you hit the other button, the motor moves in the same direction as before.

Are these compiler errors, firmware errors, or PIC errors? I am, of course, always open to the idea that it’s user error, as it so commonly is, but I’ve checked all of these systems multiple times, and by all rights, it looks as if there’s nothing wrong except the fact that it doesn’t work. I’ve included my most recent program for reference (written in WPILib, the library used in EasyC). Feel free to criticize it all you want, I know my code isn’t pretty.

*As a note, in the code, I use the “~” character to invert unsigned character values. It is a bitwise operand that flips the value of all of the bits in the byte. It is equivalent to subtracting the value from 255.
DinoBot.c (3.78 KB)

We used to use a quadratic to scale our driving but here’s what we found out was that each line of code can only use one operator ( + * / - ). To halve a value, we had to do this:

var1 = var - 127
var2 = var1 / 2
varfinal = var 2 + 127

There’s a specific line in the help files that helped us figure it out but i can’t remember where it is…

This certainly would be disappointing.

What programming tool(s) were you using? Once we know that, I’ll be really interested in seeing what its manufacturer has to say.

Blake

Wow… that’s kind of really strange. I’m using Piklab + C18 v2.4 compiler on Wine (I’m running this all on Ubuntu 9.04), with the WPILib API. I have never had a problem with using multiple operators in general, for example, the values for each wheel coming straight out of the equations are always right. Which help file are you referring to, EasyC? If so, I’m afraid I don’t have that program, and we have never used it in robotics either.

Would this be an error with the compiler? You have to use version 2.4 with the Vex firmware, because they haven’t released any updated firmware that can deal with the newer executables, so I’m not sure where in the development line this issue would have crept in.

Also, do you mean you can only use one operator total, several instances of the same operator, or one operator type (+/- or *//)?

Thanks for the help, this makes a lot of sense seeing the errors I’ve been receiving.

Also, I narrowed down some of the symptoms to integer math errors, so I’ve attached the modified code. Unfortunately, eliminating those errors only presented me with new ones. The changes are in the scaling algorithm line, and the manipulator function (which is now completely working because I gave up and hard coded the values).

Edit: By separating the algorithm in the for() loop into individual operators, it worked, which means this is the problem. Being an extreme nerd and perfectionist, though, I can’t stand to leave it there, I’m going to do a few searches and see what I can find out about fixing that.

Thank you very much!
DinoBot.c (3.72 KB)

So it seems that even though there was indeed a problem with the multiple operators per line, there’s also another problem. I freely admit this one might be coming from me. I’ve written a cubing function for the joystick values so there’s more sensitivity near center, and higher speed farther from the joystick. All of the operations are separated onto their own lines, and again, it works in theory, and it works in simulation, but not on the Vex microcontroller. Here’s the function:


short int cubejoy(short int joyval) {
int intjoyval;
joyval -= 127;
intjoyval = (int)(joyval * joyval);
intjoyval *= joyval;
intjoyval /= 16384;
intjoyval += 127;
printf(“cubejoy(%hd) = %d\n”, joyval+127, intjoyval);
return (short int) intjoyval;
}

The short integer “joyval” is the value from a joystick axis. As you can see, each line of this code only uses one operator total. The printf() statement is for diagnostics (added after I realized the robot wasn’t going anywhere).

Here’s the deal; changing the integer to a long integer fixes the problem. Does the Vex microcontroller use different length regular integers from the rest of the computing world?

Again, thanks for all of the help! I hope to soon send a fully functional scaled holonomic drive function with joystick value cubing capability to the Vex Forum code archive.

Check the help files of the development tools you are using.

It’s the preprocessor(s), the libraries, and the compiler that matter, not the microcontroller.

The microcontroller can do infinite precision arithmetic (within the constraints of thermodynamics), or create results that match any chosen word length.

Blake

That’s strange - I don’t know what software you are using, but it just doesn’t make any sense that you could only use one math operator per line.

I copied a program put out on the forum last year for a holonomic drive VEX robot and I didn’t have any problems. I was using EasyC and I know some of the lines had equations that used more than one math operator (+ - * /) on one line. The program worked fine.

NO. According to the C language standard, the size of on integer is compiler / processor specific. So, for example, on larger systems (ARM microcontrollers, PCs, servers, etc) an “int” is ususally defined as 32-bits. But on most smaller (i.e. native 8-bit or 16-bit CPU) an “int” is usually defined as 16-bits.

The VEX uses a Microchip PIC18 chip which is a native 8-bit chip. For math operations on 16-bit and 32-bit variables, it uses software libararies and multiple instructions. Bottom line is that calculations on an 8-bit variable and much faster and generate less instructions than 16 or 32 bit.

The C language standard specifies that intermediate calculations in an expression be done at “int” precision. I work with many different embedded systems and the Microchip compiler is the only one that has a default setting to **NOT **follow this requirement.

Microchip C18 compiler has a optional mode where if the result variable is 8-bits and the variables in the expressions are 8-bits then all the intermediate calculations are performed at 8-bit precision. You can easily come up with examples where intermediate calculations can overflow results but the final result fits in 8-bits. This option can be disabled by compiler toggle.

I strongly suspect this is the root cause of the problem. in this thread And the comment of performing calculation with one operation per line of code is a way of manually bypassing this and forcing to “int” level calculation.

When I need to use the digital buttons, I use the following line of code


motor[port1] = vexRT(Btn6U)*127 + vexRT(Btn6D)*-127;

You replace the 127 and -127 with the value you wan the motor to go when the respective button is pressed. You can even modify this to hold a motor at a certain power when nothing is pressed if you needed to hold a lift stedy if it would normally sink with motor power 0.


motor[port1] = 10 + vexRT(Btn6U)*117 + vexRT(Btn6D)*-137;

The 10 in this example is the motor power required to hold the arm steady. Once again the motor powers can be changed as you need them, just be sure that when you press a button, the motor power is never set greater than 127 or less than -127 as this will cause a 0 to be sent as the power. NOTE: Be careful to pay special attention to the 10 in this example.

The Microchip PIC18C Compiler defines the type int as a 16-Bit integer and long int as a 32-Bit integer, so in order for your math to work use the long int type and declare all your variables used in your equations as long int. You can retype them to (int) when needed as long as the answer will fit into 16-Bits. If necessay you can get even larger positive values using unsigned int or unsigned long int types.

For this you need two different algorithms. You need inversed algorithms for inversed directions.
For direction one you would use what you currently have:
((value-127)/2)+127
but for the inversed of direction one you would use:
((value+127)/2)-127

Also, using this algorithm would result in the motors always turning because you are always outputting a value higher/lower than 0 (assuming digital use).
you would probably want to use a different algorithm for this.