0

I'm working on a project where I need my arduino to detect the value of encoder at the instant the reading of the joystick change to 128. When the joystick is at rest, the reading is 128 which also means, my robot will hold its position/brake. Values above or below 128 correspond to the motor moving forward or backward.

I actually want to record the encoder value exactly at the first instant my arduino reads 128, so that I can apply PID position control so that my robot can brake or hold its position against gravity. The first instant when the joystick reads 128, that is the encoder value that I'd like to set as the Setpoint.

Here's some explanations for implementing PID in Arduino. http://playground.arduino.cc/Code/PIDLibraryConstructor

For instance the joystick readings go from 140, 137, 131, [128], 128, 128, 133, 139, 131, [128], 128 and at the same time, the encoder gives out corresponding values. I need the encoder values at the Joystick value of 128 in the square bracket, [] in the example above.

If I use the code below, it will just run the statements in {} whenever it sees 128, which is not what I want. FYI, the motor sometimes tend to backdrive, and this gives different encoder value also at 128. What I only need is the first encoder value at the first reading of 128 whenever I encounter it.

void loop()
{

  int pwmSpeed;

  int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);

  Input = encoder0Pos;

  if (Y_axis == 128)
  {

    Setpoint = encoder0Pos;
    myPID.Compute();
    analogWrite(pwm, Output);

  }

  else if (Y_axis > 128)
  {
    pwmSpeed = Y_axis;
    digitalWrite(dir,HIGH);           // set DIR pin HIGH or LOW
    analogWrite(pwm, pwmSpeed);            //analogWrite(pin, value)     
  }
  else
  {
    pwmSpeed = abs(Y_axis-255);
    digitalWrite(dir, LOW);
    analogWrite(pwm, pwmSpeed);

  }

}

Thanks.

//New edited code is shown below:

What do you think of the code? Did I do it correctly? I will test it once I get back to the lab.

If 128 is detected, encoder value is stored in Setpoint and then Pid.compute() is executed for as long as 128 is detected. For this duration, Pid.compute() will compute the error = Setpoint - Input and use Pid formula to calculate the Output that can be found in the analogWrite(pwm, Output). Motor will work to maintain its position at Setpoint.

However if other than 128 is encountered, it will just execute the 'else if' and 'else' statement to move the robot forward or backward.

global g_detect128 = false;

void setup() 
    {
//any code here
    }

void loop()
{

  int pwmSpeed;    
  int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);

  Input = encoder0Pos;

 if (!g_detect128 && Y_axis == 128)
    {
    Setpoint = encoder0Pos;
    g_detect128 = true;
    }


  if (Y_axis == 128)
  {

    myPID.Compute();
    analogWrite(pwm, Output);

  }

  else if (Y_axis > 128)
  {
    pwmSpeed = Y_axis;
    digitalWrite(dir,HIGH);           // set DIR pin HIGH or LOW
    analogWrite(pwm, pwmSpeed);            //analogWrite(pin, value)     
  }
  else
  {
    pwmSpeed = abs(Y_axis-255);
    digitalWrite(dir, LOW);
    analogWrite(pwm, pwmSpeed);

  }

 if(Y_axis != 128)
    {
    g_detect128 = false;
    }

}

migrated from electronics.stackexchange.com Sep 18 '15 at 5:36

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

  • Why was this question migrated here? It seems like a pure programming problem. It should be sent to StackOverflow where I feel confident they would know how to respond to it. – Nick Gammon Sep 18 '15 at 7:26
  • @NickGammon Also, it already had a (correct) answer. Why bounce it all over Stack Exchange? – Roger Rowland Sep 18 '15 at 9:03
  • I apologize if this is sent to the wrong section. If I have further question, should I proceed here or should I post at stackoverflow? – goddar Sep 18 '15 at 9:10
  • @goddar If it's pure programming, StackOverflow. If it's something particular to do with Arduino (hardware or software), post here. If it's general electronics/circuit related, then post on EE. – Roger Rowland Sep 18 '15 at 9:27
2

If you only want to catch this event once - when it first hits 128, you just need a global variable to flag when you've seen it:

boolean g_bSeen128 = false;

void setup()
{
    // ... whatever
}

void loop()
{
    // ... your existing code

    // catch first time we see 128
    if (!g_bSeen128 && Y_axis == 128)
    {
        // ... do whatever you need here. e.g.
        Setpoint = encoder0Pos;
        myPID.Compute();
        analogWrite(pwm, Output);

        // stop the event being caught next time
        g_bSeen128 = true;
    }

    // from comments below - to just ignore consecutive 128's, add this:
    if (Y_axis != 128) g_bSeen128 = false;

    // ... your existing code

}

If you only want to do something if the input changes, no matter what it is, you can keep track of the last input:

int g_nLastInput = -1;

void setup()
{
    // ... whatever
}

void loop()
{
    // get input
    int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);

    // if input has changed ...
    if (Y_axis != g_nLastInput)
    {
        // ... save latest input
        g_nLastInput = Y_axis;

        // now process the change, e.g.
        if (Y_axis == 128)
        {
            // ... do something special for 128
        }
        else
        {
            // ... do something else for other inputs
        }
    }
}

I'm not sure what you're trying to do with the PWM when you get inputs either side of 128, it seems to me that you might want to go in one direction if the input is less than 128 and go in the other direction if it's greater than 128. In either case, the magnitude of your PWM speed should just reflect how far you are from 128 in either direction. So subtracting 128 from your input will give a delta that is +/- 128 and we can scale its absolute value to 0..255 for the PWM setting.

If that's correct, an alternative way of coding your original logic might be like this:

void loop()
{
    // get input
    int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);

    Input = encoder0Pos;

    // if input has changed ...
    if (Y_axis != g_nLastInput)
    {
        // ... save latest input
        g_nLastInput = Y_axis;

        // now process the change
        int nDelta = Y_axis - 128;

        if (nDelta == 0)
        {
            // i.e. Y_axis is 128
            Setpoint = encoder0Pos;
            myPID.Compute();
            analogWrite(pwm, Output);
        }
        else
        {
            // choose direction
            digitalWrite(dir, (nDelta > 0) ? HIGH : LOW);

            // set PWM speed scaled to 0..255
            analogWrite(pwm, abs(nDelta) * 2);
        }
    }
}
  • Thanks Roger. That answers my question above. I think the way I program it is wrong. What I really want is to record the encoder value as the Setpoint whenever it encounter the first value of 128 at any time during the operation. Then I want to feed that Setpoint (intended stop position) and the Input(current encoder position) to the Pid.compute() so that it will hold its position at the Setpoint. For example, if the readings are 130, [128], 128, 128, 140, 132, [128], 128. What if initially the joystick moves the motor, brake, then move again and then brake? – goddar Sep 18 '15 at 9:08
  • @goddar Ok, then after the if that I showed you, you just need to add if (Y-axis != 128) g_bSeen128 = false; So that will ignore consecutive 128's but will pick up new instances. I've updated the answer. – Roger Rowland Sep 18 '15 at 9:24
  • goddar, what should happen in that 130, [128], 128, 128, 140, 132, [128], 128 sequence? Should the encoder be read twice, after 130 and after 132? Or just once, after 130? – James Waldby - jwpat7 Sep 18 '15 at 20:36
  • In the example, I would like to read the encoder value whenever arduino receive 128. I highlighted the ones I need to read with the square bracket, [ ] . So it will read twice in that example, first reading is at 1[28] after 130 and 2nd reading is after 132. What is your concern jwpat7? May I know? – goddar Sep 19 '15 at 1:08
  • Hi Roger or anyone else, how about other methods to achieve the what I want in my question above? This is for my knowledge since we're already discussing this topic. – goddar Sep 19 '15 at 1:10

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.