Servo Speed on XY Axis

Hello,

Taking steps towards my overall goal but am stumped right out of the gate.

Overall, I would like my continuous rotational servo (while using the X joystick axis) to function as it currently does in the code. I would also like the servo to reduce speed of rotation 75% (speed/4) while using the joystick on the Y axis.

At this point, I am trying, at least, to have the joystick operate both on the X and Y axis… to see if my idea is sound. The attached code does not account for the reduction in speed… just trying to initially understand structure.

Currently, the servo functions as expected on the X axis but has no movement at all on the Y axis.

Trying to see where I am missing to move forward. Any directional help is appreciated.

#include <Servo.h>
#include <elapsedMillis.h> //timer function

Servo servoR;

int xPin = A0;
int yPin = A1;

int xval = 0;
int yval = 0;

elapsedMillis timer0; //timer function
#define interval 10 //adjust timer duration

void setup()
{
  servoR.attach(11);

  Serial.begin(9600); // also set up Serial port for debugging
  timer0 = 0; //resets timer
}

void loop() {

// SERVO CONTROL WITH JOYSTICK
  if (timer0 > interval) {
    timer0 -= interval; //reset the timer
    
  xval = analogRead(xPin);
  yval = analogRead(yPin);
  xval = map(xval, 0, 1023, 0, 179); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 179); // map Joystick to Servo values
  servoR.write(xval); // Turn servo to specified angle on Joystick X axis
  servoR.write(yval); // Turn servo to specified angle on Joystick Y axis

  }
}

Do you mean mapping yval to 0,89 instead of to 0,179? That will effectively half the speed since the continuous servo rotates with speed proportional to the serval write value.

If y axis is not working, put a Serial.println(yval); in the loop and inspect its value while you move the stick in y direction. The code you posted only has ONE servo and both x and y values are sent to that only servo. Hope your actual code has two servos.

Don't you need two servos for two axes ?

On the other hand if you want to "add" the two joystick positions to get a single movement for the servo you should do something like

xval = map(xval, 0, 1023, 0, 90); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 90); // map Joystick to Servo values
  combinedVal = xval + yval;
  servoR.write(combinedVal);

The way your code is written now

 servoR.write(xval); // Turn servo to specified angle on Joystick X axis
  servoR.write(yval); // Turn servo to specified angle on Joystick Y axis

the second line will immediately overrule the first line.

...R

Looking at the serial monitor, both X and Y axis shows appropraite readings 0 -179 respectively… so it is ‘reading’ both axis input.

Yes… the ‘goal’ is to use both joystick axis to control ONE servo… using the X axis it will behave as it does, using the Y axis would reduce speed/rotation 75%.

Using the suggestion below, results in the following:

No action = continuous rotation
Y- stops servo
Y+ no change, continuous rotation
X- no change, continuous rotation
X+ stops servo

xval = map(xval, 0, 1023, 0, 90); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 90); // map Joystick to Servo values
  combinedVal = xval + yval;
  servoR.write(combinedVal);
#include <Servo.h>
#include <elapsedMillis.h> //timer function

Servo servoR;

int xPin = A0;
int yPin = A1;

int xval = 0;
int yval = 0;
int combinedVal;

elapsedMillis timer0; //timer function
#define interval 10 //adjust timer duration

void setup()
{
  servoR.attach(11);

  Serial.begin(9600); // also set up Serial port for debugging
  timer0 = 0; //resets timer
}

void loop() {

// SERVO CONTROL WITH JOYSTICK
  if (timer0 > interval) {
    timer0 -= interval; //reset the timer
   
  xval = analogRead(xPin);
  yval = analogRead(yPin);
  xval = map(xval, 0, 1023, 0, 179); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 89); // map Joystick to Servo values
  combinedVal = xval + yval;
  servoR.write(combinedVal);
  //servoR.write(xval); // Turn servo to specified angle on Joystick X axis
  //servoR.write(yval); // Turn servo to specified angle on Joystick Y axis
  Serial.println(xval);
  Serial.println(yval);
 

  }
}

Stefin: Using the suggestion below, results in the following:

No action = continuous rotation Y- stops servo Y+ no change, continuous rotation X- no change, continuous rotation X+ stops servo

You have not told us whether that is what you want to happen, and if it is not, what should happen ?

...R

I thought I made that clear?

Stefin: I would like my continuous rotational servo (while using the X joystick axis) to function as it currently does in the code. I would also like the servo to reduce speed of rotation 75% (speed/4) while using the joystick on the Y axis.

Stefin: ... the 'goal' is to use both joystick axis to control ONE servo... using the X axis it will behave as it does, using the Y axis would reduce speed/rotation 75%.

When using the code below, the servo is ‘stopped’ in the resting position and functions correctly in the X and Y axis movement of the joystick; HOWEVER, the speed of the rotation is unchanged in either axis.

#include <Servo.h>
#include <elapsedMillis.h> //timer function

Servo servoR;

int xPin = A0;
int yPin = A1;

int xval = 0;
int yval = 0;
int combinedVal;

elapsedMillis timer0; //timer function
#define interval 10 //adjust timer duration

void setup()
{
  servoR.attach(11);

  Serial.begin(9600); // also set up Serial port for debugging
  timer0 = 0; //resets timer
}

void loop() {

// SERVO CONTROL WITH JOYSTICK
  if (timer0 > interval) {
    timer0 -= interval; //reset the timer
   
  xval = analogRead(xPin);
  yval = analogRead(yPin);
  xval = map(xval, 0, 1023, 0, 90); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 90); // map Joystick to Servo values
  combinedVal = xval + yval;
  servoR.write(combinedVal);
  //servoR.write(xval); // Turn servo to specified angle on Joystick X axis
  //servoR.write(yval); // Turn servo to specified angle on Joystick Y axis
  Serial.println(xval);
  Serial.println(yval);
 

  }
}

I understand that the speed of rotation would be the same since these values are identical:

  xval = map(xval, 0, 1023, 0, 90); // map Joystick to Servo values
  yval = map(yval, 0, 1023, 0, 90); // map Joystick to Servo values

However, whenever any changes are made to the ‘90’ value, the servo’s movement becomes erratic (rotating at a ‘resting’ state).

What direction should I be investigating to have the servo act as it does in the X axis of the joystick but when toggling the joystick along the Y axis, the speed of the rotation that was seen on the X axis is now reduced by 75%?

Thanks

What direction should I be investigating to have the servo act as it does in the X axis of the joystick but when toggling the joystick along the Y axis, the speed of the rotation that was seen on the X axis is now reduced by 75%?

OK, I'll take a stab. So any movement on the y axis will slow the servo by 75%. Is this getting any closer?

  xval = analogRead(xPin);
  yval = analogRead(yPin);
  int servoPos = map(xval, 0, 1023, 0, 90); // map Joystick to Servo values
  
  if(yval != 512) { // assuming 512 is mid-stick
    servoPos = servoPos / 4;
  }
  servoR.write(servoPos);

Or does the 75% vary with the y value? If so, in what way?

That's correct, I am looking at using a XY joystick to control the forward/back rotation of a servo with the joystick.

When using the Y axis movement, the servo will behave the same just at a slower rate then what you would get on the X axis.

Thanks for the reply, I'll play around with the code you posted.

OK, so what happens if the joystick is moved in a diagonal direction? The way you have been writing this makes that ambiguous.

Should the y value modify the x value? Or should the y value be separate from and override the x value?

Or should the y value be separate from and override the x value?

Yes, exactly

Diagonal?

So far, with the code I have been playing with... diagonal movement appears to 'blend' the two values... that behavior continuing would be fine.

I've been reading up on variable speed control and servos but yet to find the answer.

Thanks again.

OK you just said two completely different things. First you say the y value is completely separate from and overrides the x value, and then you say you want them "blended". Which is it? Are you intentionally being obtuse?

This is a very complicated way to set things up. Why not simply have one axis control direction and the other control speed. You have the same amount of control, without all the complication.

Delta_G: Are you intentionally being obtuse?

Thanks for the input, it is appreciated. Take care

In general, don't servos NOT allow you to control speed? They've got positional feedback, but variations in speed depending on "new position is far from old position" are accidental, very liable to change between different brands of servo, and perhaps between different samples of servo from a single brand...

I've been reading up on variable speed control and servos but yet to find the answer.

That is probably because most people would just use the single axis to control the servo direction and speed instead of trying to involve another pot in the mix. Your project seems to be more of an academic exercise than something practical.

Stefin: I thought I made that clear?

I was hoping you would take the concept in Reply #2 (and #1) and explain your requirement in that context.

What you want to achieve is just a variation on that arithmetic - use the Y value to adjust the X value. I think you need to take a pencil, paper and calculator (or spreadsheet) and work through some examples.

...R

zoomkat: Your project seems to be more of an academic exercise than something practical.

I will be adapting the code to use a Sabertooth and using motors instead of servos. The purpose is when using one axis (pot), the motors (wheels) will move forward/reverse. Then when using the axis of the other pot, I could have one side operate at normal speed and the other side's speed reduced by 75%... resulting in a turn. This is for a type of mobility scooter for a disabled person for a specific purpose.

Thanks for the input, I will research more on the issue.

Stefin: I will be adapting the code to use a Sabertooth and using motors instead of servos. The purpose is when using one axis (pot), the motors (wheels) will move forward/reverse. Then when using the axis of the other pot, I could have one side operate at normal speed and the other side's speed reduced by 75%... resulting in a turn. This is for a type of mobility scooter for a disabled person for a specific purpose.

Thanks for the input, I will research more on the issue.

It would have really helped if you had said all that in the first place about different motors and turning. That's a completely different exercise and there are tons of tutorials on how to drive a cart with two motors and a joystick. Somebody could have probably pointed you in the right direction very early on without all the headache involved.

They both use the servo library… so figured I would ask. Most ‘tutorials’ do not account for speed reduction on one side or using an XY joystick for steering/speed. As mentioned, I will research the issue

Thanks

#include <Servo.h>
#include <SoftwareSerial.h>

/* ================= INITIALIZATION ===================== */

/* initializes the servos */
Servo left;
Servo right;

/* initializes all necessary inputs for movement */
const int leftMotor = 2;  //left motor is in port 2
const int rightMotor = 7; // right motor is in port 7
const int LCDDisplay = 14; //LCD Display is in TX 3 (port 14)

const int stopValue = 1500; //neutral value
const int forwardValue = 2000; //full forward
const int forwardSlow = 1600; //slow forward
const int backwardValue = 1000; //full backward
const int backwardSlow =  1300; //slow backward
int leftValue = 0; //intializes left value for LCD Display
int rightValue = 0; //initializes right value for LCD Display

SoftwareSerial mySerial = SoftwareSerial(255, LCDDisplay);

/* =================== FUNCTION DECLARATION ==================== */

/* clears LCD Display */
void clearScreen()
{
  mySerial.write(12);  //clears screen
  mySerial.write(17);  //turns backlight on
  delay(5);
}

void writeDisplay()
{
  mySerial.print("Left Value:");
  mySerial.print(leftValue);
  mySerial.write(13);
  mySerial.write(17);
  mySerial.print("Right Value:");
  mySerial.print(rightValue);
  delay(5);
}

/* stops robot's movement */
void motorStop()
{
  rightValue = leftValue = stopValue; //sets values to be printed on LCD Display
  left.writeMicroseconds(stopValue);  //writes pulse (neutral / stopped) for 1.5 ms
  right.writeMicroseconds(stopValue); //writes pulse (neutral / stopped) for 1.5 ms
  writeDisplay();
  delay(2000);
}

/* moves robot forward */
void motorForward()
{
  rightValue = leftValue = forwardValue;
  left.writeMicroseconds(forwardValue);   //writes pulse (full positive rotation) for 2 ms
  right.writeMicroseconds(forwardValue);  //writes pulse (full positive rotation) for 2 ms
  writeDisplay();
  delay(2000);
  motorStop();
}

/* moves robot backward */
void motorBackward()
{
  rightValue = leftValue = backwardValue;
  left.writeMicroseconds(backwardValue);   //writes pulse (full negative rotation) for 1 ms
  right.writeMicroseconds(backwardValue);  //writes pulse (full negative rotation) for 1 ms
  writeDisplay();
  delay(2000);
  motorStop();
}

/* moves robot slow forward */
void slowForward()
{
  rightValue = leftValue = forwardSlow;
  left.writeMicroseconds(forwardSlow);
  right.writeMicroseconds(forwardSlow);
  writeDisplay();
  delay(2000);
  motorStop();
}

/* moves robot slow backward */
void slowBackward()
{
  rightValue = leftValue = backwardSlow;
  left.writeMicroseconds(backwardSlow);
  right.writeMicroseconds(backwardSlow);
  writeDisplay();
  delay(2000);
  motorStop();
}

/* turns robot left */
void rightTurn()
{
  leftValue = forwardValue;
  rightValue = backwardValue;
  left.writeMicroseconds(forwardValue);   //writes pulse (full positive rotation) for 2 ms
  right.writeMicroseconds(backwardValue);  //writes pulse (full negative rotation) for 1 ms
  writeDisplay();
  delay(1000);
  motorStop();
}

/* turns robot right */
void leftTurn()
{
  leftValue = backwardValue;
  rightValue = forwardValue;
  left.writeMicroseconds(backwardValue);   //writes pulse (full negative rotation) for 1 ms
  right.writeMicroseconds(forwardValue);  //writes pulse (full positive rotation) for 2 ms
  writeDisplay();
  delay(1000);
  motorStop();
}

/* veers robot left */
void leftVeer()
{
  leftValue = forwardSlow;
  rightValue = forwardValue;
  left.writeMicroseconds(forwardSlow);   //writes a very low positive pulse for 1.55 ms
  right.writeMicroseconds(forwardValue);  //writes pulse (full positive rotation) for 2 ms
  writeDisplay();
  delay(1000);
  motorStop();
}

/* veers robot right */
void rightVeer()
{
  leftValue = forwardValue;
  rightValue = forwardSlow;
  left.writeMicroseconds(forwardValue);   //writes pulse (full positive rotation) for 2 ms
  right.writeMicroseconds(forwardSlow);  //writes a very low positive pulse for 1.55 ms
  writeDisplay();
  delay(1000);
  motorStop();
}

/* ================= SETUP STEP ======================*/
void setup()
{
  left.attach(leftMotor);
  right.attach(rightMotor);
  pinMode(LCDDisplay, OUTPUT);
  digitalWrite(LCDDisplay, HIGH);
  mySerial.begin(9600);
  delay(100);
  Serial.begin(9600);  
}

/* ================ LOOP STEP =======================*/
void loop()
{
  /* see comments under the FUNCTION DECLARATION to see what each of the functions does */
  motorStop();
  motorForward();
  slowForward();
  motorBackward();
  slowBackward();
  leftTurn();
  rightTurn();
  leftVeer();
  rightVeer();  
}