2

So, I was working with a project in which I used a joystick module to control two servos at the same time. The joystick controls the servos in a way that when the joystick is moved along x-axis, both servos move in the same direction but when joystick moves in y-axis, the servos move in different directions. I have this program:

#include <Servo.h>
Servo servo1;
Servo servo2;
int joyx = 0;
int joyy = 5;
int joyval;
int joyvalx; 
int joyvaly;
void setup() {
    Serial.begin(9600);
    servo1.attach(3);
    servo2.attach(5);

}

void loop() {
    Serial.println(joyvalx + "," + joyvaly);
    int x = analogRead(joyx);
    int y = analogRead(joyy);
    if(x != joyvalx){
        joyval = map(x, 0, 1023, 0, 180);
        servo1.write(joyval);
        servo2.write(joyval);
    } 
    if (y != joyvaly){
        joyval = map(y, 0, 1023, 0, 180);
        servo1.write(joyval);
        servo2.write(1023-joyval);
    }
}

However, the servos don't seem to work properly. One servo works fine but the other just gets stuck. Also, if I use the code for only one direction (x-axis or y-axis) by removing the code for the other, then both servos work good. I can't understand the problem. If anyone does, please help me.

  • 2
    1. You don't initialize joyvalx and joyvaly. 2. You never assign anything to joyvalx or joyvaly. – Majenko Jul 8 '18 at 12:24
  • 1
    +1 for nicely formatted code – jsotola Jul 8 '18 at 19:36
  • your answer is here if I use the code for only one direction (x-axis or y-axis) by removing the code for the other, then both servos work good ........ you have two pieces of code that are like two dogs fighting over a bone – jsotola Jul 8 '18 at 19:42
  • 1
    1023-joyval, which is 0 to 180? ... – frarugi87 Jul 9 '18 at 9:53
2

The problem, as jsotola pointed out, is that your code writes totally different values to the servos very fast. You don't combine the two values from the joystick, but just overwrite the previous servo value. So this cannot work.

As I interpret your description, you want the x axis to move both servos the same amount in the same direction (in unity), while the y axis determines the difference of position between them. If you move the y axis to one side, the first servo will go a bit clockwise, while the other goes a bit counter-clockwise. When you then move the x axis, both servos will move to the corresponding direction, while maintaining their position difference.

It is better to first write a formula, how you will calculate each servo position from the given joystick values. The above behavior can be described with these formulas:

servo_1_value = mapped_x + mapped_y;
servo_2_value = mapped_x - mapped_y;

Now you have to map the joystick values correspondingly:

mapped_x = map(x, 0, 1023, 0, 180);
mapped_y = map(y, 0, 1023, -90, 90);

Note, that you should change the parameters for mapping y to the values you need. In the above code they are set to the maximum (meaning that moving the y axis to either end will effectively disable the x axis, since the servo cannot move past 0 or 180 degrees).

You don't really need to check, if the value changed. But if you really want to, you should check the calculated values for each servo separately. Something like this:

if(servo_1_value != old_servo_1_value){
    servo1.write(servo_1_value);
}
if(servo_2_value != old_servo_2_value){
    servo2.write(servo_2_value);
}

But you don't really need to check for a change here.

  • I like this answer; I'd just add one very important thing: you should not call the functions at max speed, but rather call it let's say once every 10 ms. The responsiveness is still high, but 1) the other parts of the program run better and 2) you on't try to give mechanical components commands which are too fast – frarugi87 Jul 9 '18 at 9:56
  • Yes, you can do this, but I don't think, that writing at max speed really would do something bad. The servo is controlled via PWM and it will go to the specified position as fast as it can, you cannot control it's speed. When writing slower (with a delay or a millis() construction), then there only will be lesser positions in between, but the overall value change would be the same; at maximum an instant jump from 0° to 180°. On the other side it would prevent jitter, if you measure a bigger number of analog values and only write the average to the servo. – chrisl Jul 9 '18 at 13:01
  • in fact point 2 should not be applicable for servo motors (I checked the library and it updates the value once per timer overflow, so it automatically neglects all the other commands). Nevertheless having a human interface in constant acquisition is not something very advisable in my opinion; it drains resources (even if in this case no other "tasks" have to be performed) and floods with useless information the receiver (for instance, the PC at the other end of the serial link). This, again, apart from the mechanical problems which in this case are not present due to the library design – frarugi87 Jul 9 '18 at 14:11
  • 1
    You are right, for a bigger program this is important. I didn't include it for simplicity, but it's definitely a good point for a remark. – chrisl Jul 9 '18 at 15:35
  • Thanks @chrisl, your answer did do the work. Now both servos are working great. Thanks a lot. – Faiq Irfan Jul 10 '18 at 7:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.