[C] BrickPi - Controlling motors by encoder value?

Hello,

I am currently working on a project involving an older RPi 1 Model B and the first BrickPi, as well as this C library. The project involves moving a pen on a piece of paper in order to draw various things. While extreme precision is not crucial, I am interested in finding the best method to accomplish this.

For the past few days, I’ve been trying to use a busy loop to simulate the motor running for some time. Example:

movePen(150);
waitMicrosec(500000);

I’ve done a lot of research and tried various timing mechanisms, and the final one I’ve arrived at is using the Cycle Counter Register on the Pi. However, the results are still not consistent, and the pen leaves large erroneous marks.

As a last resort, I am currently trying to control the motors based on the Encoder values. I do not fully understand how Encoder and EncoderOffset are related in the code, but this the code that I am having problems with:

void moveRight(int motor, int amount, int speed) {
  if (BrickPi.Encoder[motor] == 0) {
    BrickPiUpdateValues();
  }

  long start = BrickPi.Encoder[motor];
  long target = start + amount;

  printf("ENCODER AT START: %ld\nTARGET: %ld\n", start, target);

  while (BrickPi.Encoder[motor] < target || (target != 0 && BrickPi.Encoder[motor] == 0)) {
    if (BrickPi.Encoder[motor] == 0) {
      BrickPiUpdateValues();
    }

    if (labs(target - BrickPi.Encoder[motor]) < 200) {
      BrickPi.MotorSpeed[motor] = 103;
    } else {
      BrickPi.MotorSpeed[motor] = speed;
    }
    BrickPiUpdateValues();
    printf("ENCODER: %ld\n", BrickPi.Encoder[motor]);
  }
  BrickPi.MotorSpeed[motor] = 0;
  BrickPiUpdateValues();
  printf("ENCODER AT END: %ld\n", BrickPi.Encoder[motor]);
  BrickPi.EncoderOffset[motor] = BrickPi.Encoder[motor];
  BrickPiUpdateValues();
}

The code is a work in progress and is not extremely clear. However, here are some of the issues:

  1. With the above code, the robot works fine for a few calls to the function. However, sooner or later the encoder reports incorrect values (First image is a normal output, second image is incorrect)

  2. Why does the encoder erroneously report 0 values (not shows in images, but happens often; that is why I try to ignore them in the code)

  3. I can provide additional code if needed, but I am at least on the right track? Is there a better way to achieve this?

Thank you!

BrickPi.EncoderOffset[motor] = BrickPi.Encoder[motor]; will clear the encoder value (set it back to 0), and should usually only be done once (typically at the beginning of the program). If you were to call it multiple times, the encoder value would be good for dead-reckoning, but not for absolute position.

I think a PID or PD algorithm would work well for this application.

Thank you @Matt,

After removing that line from my moving functions and placing it at the beginning of the program, the issue appears to be gone. I’ve also added a small delay using usleep in the main while loop of the function, and apparently, I get less erroneous 0 reads.

Since there is no documentation for this version of BrickPi (at least as far as I know), I ended up doing a lot of things by trial and error.

As for your last suggestion, unfortunately, this is my first project on robotics, as well as on the Raspberry Pi (and BrickPi), so I don’t even know what a PID controller is.

1 Like

PID regulation is a smart and smooth regulation algorithm for machinery. IMO this reference is a good way for starting to learn about it:
http://www.inpharmix.com/jps/PID_Controller_For_Lego_Mindstorms_Robots.html

2 Likes