I have an analog joystick hooked up to an Arduino Mega 2560 that will drive two DC motors. I read the joystick input, remap the values to what the motor controller understands (values between -127 and 127) and use the X-axis values to drive the left motor, and the Y-axis values to drive the right motor.
As it stands right now, the joystick has to be held at a 45º angle for it to make sense. In the "standard orientation", if I push to the top right corner, I get (127,127) which is full power to both motors so drives straight.
I would like to programmatically rotate the inputs so that in the standard orientation pushing :
up = (127,127),
down = (-127, -127),
right = (127,-127),
left gets (-127,127)
Here is my code so far:
// Arduino pin numbers
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
void setup() {
Serial.begin(9600);
}
void loop() {
int x= analogRead(X_pin);
int y= analogRead(Y_pin);
// remap the joystick input, inverting the
// Y-axis to match Cartesian plane
x = map(x, 0, 1023, -127, 127);
y = map(y, 0, 1023, 127, -127);
// calculate the new points rotated 45º
double new_x = (x-y)/sqrt(2);
double new_y = (x+y)/sqrt(2);
}
My rotated coordinates now range between -180 and 180.
Here is a different way to do it. The Y axis (forward back) controls speed and the X axis (left right) controls rate of turning.
const byte XPotPin = A0; // Left-Right control
const byte YPotPin = A1; // Forward-backward throttle
const int PWM_LIMIT = 255;
const int DEAD_ZONE = 10;
const int YAW_SENSITIVITY = 100;
void setup()
{
// Set pin modes on motor pins
}
void LeftMotorSetSpeedForward(byte speed)
{
// Set motor pins to run the motor forward at the specified speed
(void) speed;
}
void LeftMotorSetSpeedBackward(byte speed)
{
// Set motor pins to run the motor backward at the specified speed
(void) speed;
}
void RightMotorSetSpeedForward(byte speed)
{
// Set motor pins to run the motor forward at the specified speed
(void) speed;
}
void RightMotorSetSpeedBackward(byte speed)
{
// Set motor pins to run the motor backward at the specified speed
(void) speed;
}
void loop()
{
int speedInput = analogRead(YPotPin); // Forward/Reverse
int yawInput = analogRead(XPotPin); // Left/Right turn
// map 'speed' to the range -PWM_LIMIT (backward), +PWM_LIMIT (forward)
speedInput = map(speedInput, 0, 1023, -PWM_LIMIT, PWM_LIMIT);
yawInput = map(yawInput, 0, 1023, -YAW_SENSITIVITY, YAW_SENSITIVITY);
// Put in dead zones
if (speedInput > -DEAD_ZONE && speedInput < DEAD_ZONE)
speedInput = 0;
if (yawInput > -DEAD_ZONE && yawInput < DEAD_ZONE)
yawInput = 0;
int leftSpeed = speedInput + yawInput;
int rightSpeed = speedInput - yawInput;
// neither motor can go faster than maximum speed
leftSpeed = constrain(leftSpeed, -PWM_LIMIT, PWM_LIMIT);
rightSpeed = constrain(rightSpeed, -PWM_LIMIT, PWM_LIMIT);
if (leftSpeed < 0)
LeftMotorSetSpeedBackward(-leftSpeed);
else
LeftMotorSetSpeedForward(leftSpeed);
if (rightSpeed < 0)
RightMotorSetSpeedBackward(-rightSpeed);
else
RightMotorSetSpeedForward(rightSpeed);
}
Because, effectively, all you are doing is calculalting points on a unit circle. What you need to be doing is, effectively, evaluating the sine and cosine values corresponding to the X and Y coordinates from the joystick, and using those to calculate the motor speeds. Joystick full-scale Y (fully forward) should be both motors on full. As the joystick moves to the right from there, the right motor should be reducing in speed, so the car turns right. As the joystick moves left from there, the leftt motor should be reducing in speed, so the car turns left. At 45 degrees right of forward, you probably want the right motor speed reduced by about 1/4. At 45 degrees left of forward, you probably want the left motor speed reduced by 1/4. The sine of the angle would give you 0.707 full-speed at 45 degrees, which is a reasonable value.
No, those equations are correct for rotating a point.
But a point at 127, 127 is 180 long, thus rotated ends up at 0, 180 when rotated about 0.
old x
old y
new x
new y
1.00
1.00
0.00
1.41
0.50
0.50
0.00
0.71
127.00
127.00
0.00
179.61
-127.00
0.00
-89.80
-89.80
127.00
0.00
89.80
89.80
0.00
127.00
-89.80
89.80
0.00
-127.00
89.80
-89.80
50.00
50.00
0.00
70.71
-127.00
-127.00
0.00
-179.61
0.00
0.00
0.00
0.00
1.00
0.00
0.71
0.71
0.00
1.00
-0.71
0.71
OK, so you can paste a spreadsheet here, looks good on my end anyway.
It's the difference between a circle and the square that encloses it. It's too close to nap time for me to offer a solution.
Look at the box that the joystick defines - the rotated box will stick out, like you have seen… and a scaled box that fits in the origianl box will leave areas unreachable.