Pololu Encoders and Commands

Hi,

I wanted to use the pololu encoders in conjunction with the 42x19 wheels to enable really precise movement. I was wondering if there was a function that would enable me to wait for the robot to reach a certain number of rotations before doing the next task, e.g. the robot waits for encoder_a and encoder_b to reach 100, then resets the count, then waits for encoder_a to reach 10 and encoder_b to reach -10, effectivly turning in a circle, then waits for encoder_a and encoder_b to reach 50 again. I ask because there doesn’t seem to be any functions like this, and they would need to be executed in order (the commands need to be in a specific order).

I was wondering if there was any syntax for this kind of movement, and if so what is it.

If there wasn’t I was wondering if someone could make a library that would be similar to this

Thanks.

Also, If this is in the wrong section, feel free to move it

Hello.

You didn’t mention what type of device you are programming, but from your previous posts I guess it’s an Orangutan. Unfortunately, we don’t offer a function that does what you want, but it would be possible to write it yourself. Let us know if you get stuck.

–David

Whoops! I forgot that part

Indeed, it is a Orangutan SVP-324.

I did go ahead and try to write the functions myself, but found myself a bit lost. In addition, I am not the greatest programmer by any stretch of imagination, so while this might be a huge favor to ask, would it be possible for you (or someone else) to do the basic code for the functions?

Thanks

Here is a little snippet that does part of what you want:

void move_to(int target_counts_ab)
{
  while(svp_get_counts_ab() < target_counts_ab)
  {
    set_m1_speed(100);
  }
  while(svp_get_counts_ab() > target_counts_ab)
  {
    set_m1_speed(-100);
  }
  set_m1_speed(0);
  svp_get_counts_and_reset_ab();
}

This is a very basic function that probably will end up over-shooting the target position. Also, this function makes a lot of assumptions about your system (e.g. setting motor1 to a positive speed will increase the counts on ab) but it might work for you. Also, it doesn’t handle the case where you want the motor to turn more than 32767 counts from the starting position. Once you understand how it works, you should be able to expand it to do both motors and tailor it to your application.

If you have trouble making progress, I recommend reading some books about C programming.

–David

So I understand that, and that worked really well. However, I wasn’t able to make it work so that it would run both motors at the same time and wait for both motors to reach a target encoder count.

Here’s what I have:

void move_to(int target_counts_ab, int target_counts_cd)
{
  while(svp_get_counts_ab() < target_counts_ab & svp_get_counts_cd < target_counts_cd)
  {
    set_m1_speed(100);
	set_m2_speed(100);
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
	lcd_goto_xy(0,1);
	print_long(svp_get_counts_cd());
  }
while(svp_get_counts_ab() < target_counts_ab & svp_get_counts_cd < target_counts_cd)
  {
    set_m1_speed(-100);
	set_m2_speed(100);
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
	lcd_goto_xy(0,1);
	print_long(svp_get_counts_cd());
  }
  while(svp_get_counts_ab() < target_counts_ab & svp_get_counts_cd > target_counts_cd)
  {
    set_m1_speed(100);
	set_m2_speed(-100);
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
	lcd_goto_xy(0,1);
	print_long(svp_get_counts_cd());
  }
  while(svp_get_counts_ab() > target_counts_ab & svp_get_counts_cd > target_counts_cd)
  {
    set_m1_speed(-100);
	set_m2_speed(-100);
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
	lcd_goto_xy(0,1);
	print_long(svp_get_counts_cd());
  }

  set_m1_speed(0);
  svp_get_counts_and_reset_ab();
}

I wrote with the intention that it would run both motors until each of the encoders reached the set target distance, but it would only wait for one to reach the correct distance before stopping.

How would I fix this so that it does what I want?

I didn’t check all of your code but right away I noticed that you should use the logical AND operator (&&) instead of the bitwise one (&).

–David

So I tried using the Logical AND operator (&&) but I keep having the same problem, where one wheel will reach the desired count but then both will shut off. Here is what I have

void move_to(int target_counts_ab, int target_counts_cd)
{
  while(svp_get_counts_ab() < target_counts_ab && svp_get_counts_cd < target_counts_cd)
  {
    set_m1_speed(100);
	set_m2_speed(100);
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
	lcd_goto_xy(0,1);
	print_long(svp_get_counts_cd());
  }
  set_m1_speed(0);
  set_m2_speed(0); 
}

The purpose of this should have been to have both wheel move forward until the ab encoders reached 100 AND the cd encoders reached 100. If one reached before the other, it should have also stopped that one motor (so if ab reached 100 while cd was at 90, then m1 would turn to 0 but m2 would continue to run until cb also reached 100)

Where am I going wrong?

while(svp_get_counts_ab() < target_counts_ab && svp_get_counts_cd < target_counts_cd)

The line above means to run the loop while both counts are less than the target. Therefore, the loop terminates when either count surpasses its target. Do you understand why?

–David

I can’t say that I do. Could you give a brief explanation why?

The only thing I can think of is that in order for it to run, it requires that both count be under the targets (The && operand), so when one exceeds the target, the requirement is no longer valid and the loop terminates. But how would I solve this?

Alright, so I understand why the previous code would stop once one of the encoders reached a certain count, but I’m still fuzzy on how to make it so that both run until both reach the same count (both run, ab hits 100 so motors for ab stop, then cd continues from whatever it was when ab hit 100 until it too hits 100 then cd motors also stop)

To have each run separately requires two separate control structures. The logic for each motor needs to be separate because they can be doing different things.

One way to do it would be this:

void move_to(int target_counts_ab, int target_counts_cd)
{
  byte checkDone = 2;
  set_m1_speed(100);
  set_m2_speed(100);
  while(checkDone > 0)
  {
    if(svp_get_counts_ab() >= target_counts_ab)
    {
      set_m1_speed(0);
      checkDone &= 1;  //Clear bit 1
    }
    if(svp_get_counts_cd >= target_counts_cd)
    {
      set_m2_speed(0);
      checkDone &= 10;  //Clear bit 0
    }
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
    lcd_goto_xy(0,1);
    print_long(svp_get_counts_cd());
  }
  
}

This method declare a status variable so that it can tell when each motor is done. Decimal 2 is binary 0b11. The first encoder controls bit 1, so when the encoder count reaches the target, checkDone is set to 0b0x (“x” is unknown). The second encoder controls bit 0, and sets checkDone to 0bx0 when it reaches the target. Once both reach the target, checkDone equals 0b00 and the loop exits.

There are often many ways to solve any problem in software. There are some enhancements that could be made to this, and there are entirely different ways to go about it.

That makes a lot of sense, and I understand how it works. But when I tried to put it into AVR studio 4, and tried to compile it, it gave me an error “…/test.c:6: error: ‘byte’ undeclared (first use in this function)” which I think means that it doesn’t recognize byte as a valid form of definition. This also meant that the program failed to compile. Is there a proper syntax for byte in AVR studio, or do you have to do something different?

Here’s a slightly modified version of Darth Maker’s code that should compile correctly. An “unsigned char” is a byte, and the lines that do the binary logic have been fixed.

void move_to(int target_counts_ab, int target_counts_cd)
{
  unsigned char checkDone = 0b11;
  set_m1_speed(100);
  set_m2_speed(100);
  while(checkDone > 0)
  {
    if(svp_get_counts_ab() >= target_counts_ab)
    {
      set_m1_speed(0);
      checkDone &= ~0b10;  //Clear bit 1
    }
    if(svp_get_counts_cd >= target_counts_cd)
    {
      set_m2_speed(0);
      checkDone &= ~0b01;  //Clear bit 0
    }
    lcd_goto_xy(0,0);
    print_long(svp_get_counts_ab());
    print(" ");
    lcd_goto_xy(0,1);
    print_long(svp_get_counts_cd());
  }
  
}

–David

Thanks for the help, but when I put in the code, it still didn’t compile, so maybe you put the uploaded the wrong version?
All that was missin were a few changes, which I did. Here is the final code

void move_to(int target_counts_ab, int target_counts_cd)
    {
      unsigned char checkDone = 0b11;
      set_m1_speed(100);
      set_m2_speed(100);
      while(checkDone > 0)
      {
        if(svp_get_counts_ab() >= target_counts_ab)
        {
          set_m1_speed(0);
          checkDone &= ~0b10;  //Clear bit 1
        }
        if(svp_get_counts_cd() >= target_counts_cd)
        {
          set_m2_speed(0);
          checkDone &= ~0b01;  //Clear bit 0
        }
        lcd_goto_xy(0,0);
        print_long(svp_get_counts_ab());
        print(" ");
        lcd_goto_xy(0,1);
        print_long(svp_get_counts_cd());
      }
     
    }

This only works (as is) going forward, and has a tendency to overshoot the target by a few (about 3-7 ticks per 100). But all in all, thanks for all the help

Yeah, I forgot to change “byte” to “unsigned char” when I originally posted it. I have since corrected my post. I’m glad you were able to figure it out anyway, and I’m glad that it’s working.

The overshoot is expected because we only stop braking after we’ve reached the target position.

–David

Yeah, I forgot to make those binary numbers in the code.