Below is the code, in C, we used to convert our potentiometer values to radians for use with our turning equations. These values were used to make it simpler to implement the equations we were relying on to ensure that the wheels each individually turned to the correct angle. To be specific, it was in order to keep our wheels as close to Ackermann conditions as possible. For more information about this please see the ODRB page.
double potRadVal (double x) { // converts pot value to Radians to use with cos // 472.5 is dead center of 0-945 output (the number of ticks on our potentiometer) // about 1 ticks for every degree of rotation // front wheels have a total movement of 147 degrees // 0 to 90 degrees if front inner // 0 to 57 degrees if front outer // 0 degrees is straight double y = 0; if (x > 513) { y = (x/8.275)-57; return y*(3.14/180); // converts from degrees to radians } else if (x < 431) { y = (-x/8.275)+57; return y*(3.14/180); // converts from degrees to radians } else { return 0; } }
This next example converts the joystick analog ticks into potentiometer values so we know how far to turn the wheels. The full range of the joystick's movement was from 1000 at the center out to approximately 1800 at the extremes. A strange choice of values that forced us to do some manual checking with our ranges as we were programming to make sure that we never received a value that wasn't accounted for in any of the system states. It took a lot of testing for us to find a safe "middle" range where we could stop the turning motor consistently, since the joystick never reset to exact 1000 when released.
double stickToPot (double x) { // converts the turn stick input to Pot Values double y = 0; if (x <= 1450) { // left side of turn stick to pot values if (x >= 1060) { // between 30 degrees and 0 y = x*0.8-742; return y; } else { // greater than 30 degrees y = x*1.7391-1737.5; return y; } } else if (x >= 1550) { // right side of turn stick of pot values if (x <= 1940) { // between 30 degree and 0 y = x*0.8-742; return y; } else { // greater than 30 degree y = x*1.7391-2563.9; return y; } } else { return 435; // theoretical center for potentiometer } }
The next sample demonstrates how we mapped the Radio Control Transmitter (Tx) and Receiver (Rx) to the proper pins in order to read their analog values. The values would then be used for computation in our steering and driving code. It also shows how we stored our potentiometer value and bump switches. The bump switches were designed to trigger in the event of oversteer driving our mechanical linkage beyond a safe range. If they triggered it would interrupt any calls to turn until it had checked to ensure the direction of the turn was away from the bump switch that was triggered. It also prints the values it currently is seeing from the remote control in the commented out sections, which we would use for debugging purposes.
// Tx/Rx Code // Read the signals from the channels throttleCh = pulseIn(throttlePin, HIGH, 25000); turnCh = pulseIn(turnPin, HIGH, 25000); // converts the controller input to servo values throttleOut = map(throttleCh, 1015, 1880, 1000, 2000); turnOut = map(turnCh, 1015, 1880, 1000, 2000); //Serial.print("Throttle Out:"); //Serial.println(throttleOut); //Serial.print("Turn Out:"); //Serial.println(turnOut); //delay(100); // Potentiometer Code potIn = analogRead(potPin); // reads sensor value //Serial.print("potIn Value Is:"); //Serial.println(potIn); //Bump Sensor leftBump = digitalRead(leftLimitPin); rightBump = digitalRead(rightLimitPin); //Serial.print("Left Limit is:"); //Serial.println(leftBump); //Serial.print("Right Limit is:"); //Serial.println(rightBump);