Using motor ticks w/o 'mav' or 'mrp' functions

8 replies [Last post]
Terry
Terry's picture
Title: NooBot
Joined: 06/08/2009
Posts:
BotPoints: 55
User offline. Last seen 6 years 1 week ago.

I find that the speed commands to the motors using the 'Link" controller is not very reliable nor accurate, especially at lower speeds.
However, for many behaviors, speed is not the most important behavior; its moving with accuracy to a desired position. Did you know you can drive the motors by power using the 'motor()' command and still monitor its rotational position with the 'get_motor_position_counter(n), where 'n' is the motor port? If you go to http://botballprogramming.org and search for "printing" or "printf assignments" you'll find sample code for robot testing using this method. I think the robot motion is more accurate using this approach.

History is a race, between Education and Catastrophe

ruler501
ruler501's picture
Title: NooBot
Joined: 01/29/2012
Posts:
BotPoints: 367
User offline. Last seen 8 years 3 weeks ago.

Could you do some tests to see if this would be true? I'd be interested in seeing 2 or 3 robots tested with a variety of movement controls to see which were most accurate(and at different speeds to see if that effects it). I could probably write some test code to run if you could run it on robots and measure distance traveled that could be some valuable information for the community.

EDIT: Here are the most obvious movement algorithms I could think of. Would be interesting to see how consistent they are and which ones have obvious biases(the clamp may cause some problems)

  1. #include<stdio.h>
  2.  
  3. //! relative speed the robot should move at as percent of max(functions will auto-scale). Needs to be more than MINSPEED
  4. #define SPEED 50
  5. //! minimum speed to prevent some problems from low power. Also in percent
  6. #define MINSPEED 10
  7. //! distance the robot should travel during the test in ticks
  8. #define FINALDIST 2000
  9. //! Define algorithm it should use(pick from the enum below)
  10. #define ALGORITHM ALG_MRP
  11. //! The steps for acceleration in the ALG_MRPA algortithm
  12. #define STEPS 25
  13. //! port the left motor is plugged into
  14. #define LMOTOR 0
  15. //! port the right motor is plugged into
  16. #define RMOTOR 3
  17. //! Simple utility function
  18. #define CLAMPVEL(x) ((x) < MINSPEED ? MINSPEED : (x))
  19.  
  20. enum{
  21. ALG_MRPD,
  22. ALG_MRPA,
  23. ALG_MAVD,
  24. ALG_MAVL,
  25. ALG_MAVQ,
  26. ALG_MOTD,
  27. ALG_MOTL,
  28. ALG_MOTQ
  29. } algorithms;
  30.  
  31. int main(int argc, char* argv[]){
  32. int curdis=0, curvel=0;
  33. switch(ALGORITHM){
  34. case ALG_MRPD:
  35. mrp(LMOTOR, SPEED*11, FINALDIST);
  36. mrp(RMOTOR, SPEED*11, FINALDIST);
  37. bmd(LMOTOR);
  38. break;
  39. }
  40. case ALG_MRPA:
  41. for(int i=1; i <= STEPS; i++)){
  42. mrp(LMOTOR, 11*CLAMPVEL(SPEED*i/STEPS), FINALDIST/STEPS/2);
  43. mrp(RMOTOR, 11*CLAMPVEL(SPEED*i/STEPS), FINALDIST/STEPS/2);
  44. bmd(LMOTOR);
  45. }
  46. for(int i=STEPS; i > 0; i--)){
  47. mrp(LMOTOR, 11*CLAMPVEL(SPEED*i/STEPS), FINALDIST/STEPS/2);
  48. mrp(RMOTOR, 11*CLAMPVEL(SPEED*i/STEPS), FINALDIST/STEPS/2);
  49. bmd(LMOTOR);
  50. }
  51. break;
  52. case ALG_MAVD:
  53. mav(LMOTOR, SPEED*11);
  54. mav(RMOTOR, SPEED*11);
  55. msleep(1000*FINALDIST/(SPEED*11));
  56. break;
  57. case ALG_MAVL:
  58. while(curdis < FINALDIST){
  59. curdis = get_motor_position_counter(LMOTOR);
  60. mav(LMOTOR, 11*CLAMPVEL((FINALDIST-curdis)*SPEED/FINALDIST));
  61. mav(RMOTOR, 11*CLAMPVEL((FINALDIST-curdis)*SPEED/FINALDIST));
  62. msleep(5);
  63. }
  64. break;
  65. case ALG_MAVQ:
  66. while(curdis < FINALDIST){
  67. curdis = get_motor_position_counter(LMOTOR);
  68. mav(LMOTOR, 11*CLAMPVEL((FINALDIST-curdis)*(FINALDIST-curdis)*SPEED/FINALDIST/FINALDIST));
  69. mav(RMOTOR, 11*CLAMPVEL((FINALDIST-curdis)*(FINALDIST-curdis)*SPEED/FINALDIST/FINALDIST));
  70. msleep(5);
  71. }
  72. break;
  73. case ALG_MOTD:
  74. motor(LMOTOR, SPEED);
  75. motor(RMOTOR, SPEED);
  76. while(get_motor_position_counter(LMOTOR) < FINALDIST) msleep(5);
  77. break;
  78. case ALG_MOTL:
  79. while(curdis < FINALDIST){
  80. curdis = get_motor_position_counter(LMOTOR);
  81. mav(LMOTOR, CLAMPVEL((FINALDIST-curdis)*SPEED/FINALDIST));
  82. mav(RMOTOR, CLAMPVEL((FINALDIST-curdis)*SPEED/FINALDIST));
  83. msleep(5);
  84. }
  85. break;
  86. case ALG_MOTQ:
  87. while(curdis < FINALDIST){
  88. curdis = get_motor_position_counter(LMOTOR);
  89. motor(LMOTOR, CLAMPVEL((FINALDIST-curdis)*(FINALDIST-curdis)*SPEED/FINALDIST/FINALDIST));
  90. motor(RMOTOR, CLAMPVEL((FINALDIST-curdis)*(FINALDIST-curdis)*SPEED/FINALDIST/FINALDIST));
  91. msleep(5);
  92. }
  93. break;
  94. case default:
  95. printf("A command is messed up somewhere\n");
  96. }
  97. off(LMOTOR);
  98. off(RMOTOR);
  99. return 0;
  100. }

Terry
Terry's picture
Title: NooBot
Joined: 06/08/2009
Posts:
BotPoints: 55
User offline. Last seen 6 years 1 week ago.

The scope of what you are suggesting is beyond my available time or interest. I assume the code above is meant as an outline of a test plan. From my experiments with a couple Links, the mrp and mav tests with speeds less than 50% [500 >SPEED>10] will cause much randomness in both the forward distance and the final attitude of the bot. Even for higher speeds, 5 to 10 runs would be required to get a sense of the error distribution [a lot of manual measurement]
- I found the ALG_MAVD method to be unreliable as well.
- I'm not familiar with your notation for CLAMPVEL(), is that in C++? please explain.
-The ALG_MOTD method requires testing with a range of battery charges to bound the error [quite time consuming]
-I might experiment with a variation on the ramp-up, ramp-down method and report back.

Please let me know if I misinterpreted your request.

History is a race, between Education and Catastrophe

ruler501
ruler501's picture
Title: NooBot
Joined: 01/29/2012
Posts:
BotPoints: 367
User offline. Last seen 8 years 3 weeks ago.

I would expect from those to have ALG_MAVD to be least precise it is basically the same as mrp with less accuracy
CLAMPVEL is just a preprocessor define function using the ternary operator. It could also be written as

  1. int CLAMPVEL(int x){
  2. if(x < MINSPEED) return MINSPEED;
  3. else return x;
  4. }

I actually didn't think about the battery causing problems.

I didn't neccesarily mean for just you to test them but rather anyone who has access to try it out with various settings(preferably with repitition on each setting to check for consistency).
I think the *Q ones will probably be the most accurate(A quadratic ramp down from fastest speed to slowest). The might be improved with a smoother increase in speed so it isn't jerky though. It also might be useful to take into account the minimum speed so the curve is smoother.
And as I've said the MAVD will probably be least accurate with the MRPA being right after it(I think all the separate commands will cause some problems, but that might be able to be compensated for).
Also just as a note with mrp and mav the maximum velocity is usually closer to 1100 and depends on the robot and charge. I assumed 1100 in my code(so the conversion from percent is just multiply by 11)

Jeremy Rand
Jeremy Rand's picture
Title: Botball Youth Advisory Council
Joined: 04/03/2009
Posts:
BotPoints: 1168
User offline. Last seen 8 years 1 week ago.

Hi Terry,

Have you played around with the PID gains? My guess is that poor accuracy at low velocities would be caused by overcorrection/oscillation, which would be improved by fiddling with the PID gains. I'm also going to conjecture that KIPR didn't do much tuning of the PID gains... a few hours of experimenting with the Ziegler-Nichols method might yield good improvements.

I would be surprised if motor() yields better results than a properly tuned PID controller, because motor() will possibly make different wheels move at different speeds in a way that is dependent on battery level.

-Jeremy Rand
Senior Programmer, Team SNARC (2012-2013), Norman Advanced (2010-2011), Norman HS (2008-2009), Norman North (2005-2007), Whittier MS (2003-2004)
2012-2013 VP of Tech, 2011 President, Botball YAC (2009-2013)
Mentor, Alcott and Whittier MS

ruler501
ruler501's picture
Title: NooBot
Joined: 01/29/2012
Posts:
BotPoints: 367
User offline. Last seen 8 years 3 weeks ago.

It's more than low accuracy though. I noticed that the wheels wouldn't even turn if the power was too low(somewhere around 100ticks/second)

Jeremy Rand
Jeremy Rand's picture
Title: Botball Youth Advisory Council
Joined: 04/03/2009
Posts:
BotPoints: 1168
User offline. Last seen 8 years 1 week ago.

@ruler501 Wheels not turning at low speeds sounds like a PID gain issue as well.

-Jeremy Rand
Senior Programmer, Team SNARC (2012-2013), Norman Advanced (2010-2011), Norman HS (2008-2009), Norman North (2005-2007), Whittier MS (2003-2004)
2012-2013 VP of Tech, 2011 President, Botball YAC (2009-2013)
Mentor, Alcott and Whittier MS

ruler501
ruler501's picture
Title: NooBot
Joined: 01/29/2012
Posts:
BotPoints: 367
User offline. Last seen 8 years 3 weeks ago.

I should probably learn more about PID gains I guess

Terry
Terry's picture
Title: NooBot
Joined: 06/08/2009
Posts:
BotPoints: 55
User offline. Last seen 6 years 1 week ago.

Jeremy,
I haven't experimented with the PID gains, but from my experience the motors act like the lag in the control loop is too great and varies from one sample to the next (if so, PID gain will not fix it). The two drive motors seem to take turns moving forward. [setting the PID gain is not easy, even under ideal timing, its largely trial and error]
Also, on startup one or the other of the motors sometimes jitters, leading to an attitude angle error. For speeds over ~600 the speed smooths out, but sometimes one motor stops before the other even though the stop is initiated by one.
I was surprised to find that, on the Link, the EMF integral, or sum, which is the 'count', is available with just power to the motors; this isn't true in the simulation.
Perhaps the OS in the Link has two free-running samplers of each motor port EMF when the mav function is active and they are not synchronized.

History is a race, between Education and Catastrophe