(Trying to) develop a speed servo using Arduino due & arduino motor shield R3

Hi all,

I'm trying to develop a simple "software speed servo controller" for a hobby car.

Te motor is a hobby DC one with an encoder (10 teeth) mounted on the shaft. I've had trouble when the speed is above 60 - 70 rpm, for the time measured in between teeth starts (randomly?) giving intervals much shorter than expected. The minimum interval -for a speed of 150 rpm- is 40 mS which, I think, the arduino due should be capable enough to handle.

As I'm a novice (not in programming neither in engineering) in the arduino realm, I've looking for something similar in the forum, and found this piece of code:

const int sensorPin = 2;
const int ledPin = 13;
const int sensorInterrupt = 4;
const int timeoutValue = 5;

volatile unsigned long lastPulseTime;
volatile unsigned long interval = 0;
volatile int timeoutCounter;

bool blink = false;

void setup()
{
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);    // enable internal pullup (if Hall sensor needs it)
  pinMode(ledPin, OUTPUT);
  attachInterrupt(sensorInterrupt, sensorIsr, RISING);
  Serial.begin(9600);
  lastPulseTime = micros();
  timeoutCounter = 0;
}

void sensorIsr()
{
  unsigned long now = micros();
  interval = now - lastPulseTime;
  lastPulseTime = now;
  timeoutCounter = timeoutValue;
}

void loop()
{
//  Serial.print("Sensor ");
//  Serial.print(digitalRead(sensorPin) == HIGH ? 'H' : 'L');
  Serial.print(" RPM ");
  if (timeoutCounter != 0)
  {
    --timeoutCounter;
    float rpm = 60e6/(float)interval;
    Serial.print(rpm, 1);
  }
  Serial.println();
  delay(500);
  blink = !blink;
  digitalWrite(ledPin, blink ? HIGH : LOW);
}

posted, long time ago, by dc42 (in fact, the only modification is the interrupt pin -const int sensorInterrupt). The code runs fine , but having exactly the same problem (at exactly the same speed).

I'm going to buy a cheap oscilloscope to see the optical encoder signal quality; maybe the problem comes from electrical noise or something similar (I promise keeping you all informed), but, in the meanwhile . . . has somebody something to suggest?

Thanks.

Hi all,

I opened this thread a few days ago to 1) explain what my project is, 2) report my very first problem developing it and 3) asking for help.

I had no success: No one has read the post.

Nevertheless, I will keep trying: should I get no comments, I, at least, will use the thread as a kind of blog of my project.

Here I go: my first goal is to (speed - servo) control a hobby DC motor so that I’m able to make a hobby model moving ahead – backwards “reasonably” straight; those motor are so simple that a “non feedback” control does not control (in fact) the rpm of the motor. The initial idea is to, at least, make the motor to rotate within a “window” of, say, a +- 10% of the DesiredSpeed.

I bought a “Baron” kit –which looks fine- that has four DC motors and two encoders to mount in the shafts. I started mounting the encoder in the shaft and writing a simple code (interrupt based; I will post it later) to see what happened: at low speed it worked (roughly), but as the speed went above 60 - 70 rpm, the system started to either oscillate, stop or going to full range.

My experience is that the best is to isolate (and attack) the problems one by one, so I tried to imagine what was going wrong: the code (roughly, but did) work at low speeds, so the first guess is that the problem was not coming by this side (the maximum frequency of the encoder signal is ~ 25 Hz, so interrupts come every 40 ms. The arduino has to cope whit it easily -if not, as we say in Spanish, “apaga y vámonos”). If I’m right: what else could be it?.

By means of the serial.print (be careful with it if you are dealing with ms, as it takes a “long” time to communicate trough a USB serial) I observed that the time intervals in between interrupts (RISING edge of the encoder signal) seemed (seemed: remember what I said about the time communicating) to divide into smaller pieces (i.e.: ordinary intervals of 100 ms; then four intervals of 40, 50, 5 & 5 ms –this is an example; it wasn’t so easy).

The main suspect became, then, the signal coming form the encoder: I have (for the moment; I’m equipping myself: USB oscilloscope) no means to confirming that the signal is not good, but, despite not having, still, any laboratory tools, I DO HAVE THE OPPORTUNITY TO CHECK THAT THE ARDUINO SEES THE INTERRUPT SIGNAL AND TRATS IT WELL. How?: easy, you can program the arduino to generate an almost square wave and to connect it to the pin interrupt. This is the code (excuse me for using such mixture of Spanish and english terms):

const int AInt = 4;

const int AGenInt = 3;

const int Frecuencia = 100;

volatile unsigned long MASpCalCurTime = 1;



//////////////////// SETUP SECTION ////////////////////

void setup() {

Serial.begin(9600); 

attachInterrupt(AInt,motor_a_isr,RISING);

pinMode(AGenInt, OUTPUT);
digitalWrite(AGenInt, HIGH);

}

//////////////////// MAIN SECTION ////////////////////
void loop() 
{

delay (500 / Frecuencia);

digitalWrite(AGenInt,LOW);

delay (500 / Frecuencia);

digitalWrite(AGenInt, HIGH);

} 
	
//////////////// MOTOR_A_ISR code ////////////////////	
void motor_a_isr ()
{

// detachInterrupt(AInt);  
 
MASpCalCurTime = millis(); 

Serial.println(MASpCalCurTime);


}
//////////////// MOTOR_A_ISR end //////////////////////

The trick (making the arduino interrupt itself as if it were an alien interrupt) is not as lying yourself, as the interrupt code executes on its own account (this is the idea. I could have used an external well shaped signal, but, as I’ve explained by now, I have not). The output (serial.println; be careful) is excellent: the times correspond exactly with the indicated frequency (const int Frequencies = 100; there is a little increase due to the other code lines and to the serial.println monitoring). I would say that it works fine to 10000 Hz: for frequencies above this the serial.println monitoring gets corrupted by the observing method itself (like Heisenberg principle. Tiene cojones ).

That’s all boys (for the moment. Keep you informed).

Regards

(Of course, I forgot indicating that you have to connect pins #3 & #4 for the previous code to work. Sorry) :cold_sweat:

Hi all,

Here's a summary of the situation:

  • I have the intention of making a hobby 4 wheels proto to move at a controlled speed and/or turn a certain -prefixed- angle: the goal is to control the movement through the encoder (a feedback loop) so that you don't have to guess the amount of space made by multiplying speed by time (without any idea of what the speed was in fact).

  • The very first feat is to read the encoder in "real time" basis: you have to connect it to an interrupt and, then, write a software that makes whatever you need every teeth of the encoder: the simplest is to store the "millis" so that, next time, everything you have to do is to subtract to have the "period" ("T"; the inverse -1/T- is the speed). If everything goes well, you should have a series of smooth readings (Serial.print). A few days ago I posted a piece of software that did that.

  • Sometimes it worked, sometimes it didn't. It did (work well) at slow speeds but when you speeded it up, the readings started being a bit random (not exactly random; it looked that the controller read 2, 3, . . . tooth instead of just one -not every time: it could start making good readings for a while and, suddenly, again failing).

  • As we say in Spanish, "sabe más el diablo por viejo que por diablo" (devil is sage not because he's clever, but for he is old): I had the impression that it was impossible to keep on going without a tool to see what happens in "real time". Even for this simple project things happen at 25 Hz (25 times a second. The maximum speed of the motor is about 150 rpm and the encoder has 10 teeth: 150 * 10 / 60 = 25), so an oscilloscope is mandatory. Fortunately, what costed 30 years ago 2.000 $ now costs 60 $: I bought a "Hantek" (a chinese made that is quite well aspected and works reasonably well). Here are the results:

** The very first image I got was the #1 I attach. It corresponds to the interrupt pin I'm using: it looks fine, specially the neat rising and falling edges; there are some spikes coming up and down from the flat parts but they don't look so big (as to interrupt the controller), so further investigation was needed.

** I added two lines of code to the interrupt (code) to send to a(nother) pin a HIGH signal while the interrupt itself is executing: I got the figure #2: Green lines (spikes) are the interrupt executing itself: a complete disaster.

** 1st, the interrupt should occur JUST in the RISING edge (as coded): in the image you can see that it happens when rising and when falling. In addition to this (2nd), there are additional executions of the interrupt that appear here and there. A disaster. (Or not?. Well, at least it corresponds with that the code makes: more interrupts than the correct ones means a bigger speed than the real one).

** These kind of problems are associated wiht "noise". It is a kind of "noise" you can't (normally) hear. In the images I enclose you can see the noise on the bottom and on the top. (I can't explain the basics of the -general- problem; sure you can find excellent papers in the net).

** I do have some experience on suppressing noise: 1) some coming from power supply and some "noisy" parts (the motor itself in this case) is diminished easily by connecting small capacitors in parallel. 2) The signal coming from the encoder (by the way: is an optically coupled one. A led that makes an "opto"transistor to conduct by lighting it) itself can carry noise too: another cap in parallel (to earth: see below).
[BE AWARE: Noise suppression has some of sorcery: you can't use any cap (even worse: some kinds of them make noise themselves). For this purpose small ceramic capacitors are the best. I have a beginners kit with a number of them (no idea of the value: a few uF)].

** So I used three of them. You can see the results in the figure #3. Falling edge interrupts have dissapeared completely: sure the encoder signal carried noise that has been (at least in part) removed.

The problem is, by no means, solved. You can see remaining (undesired) shootings (but I keep some bullets in my cartridge). I'm going to make the following.

  1. Separate power supplies: up to now I've been using the same DC supply for both the arduino and the motor. I'm going to supply them from different DC sources.

  2. Build a "solid" signal earth: whatever you might think, cables have resistance (i.e: they are not zero ohms), so there are minimal voltage drops in between points that are wired together (specially with those stacks of boards we use to make the prototipes). Sometimes these drops are big enough as to shoot the interrupt (this is not -only- a "noise" problem).

  3. Shorten the cables: in addition to contribute to the last problem, cables act as antennas. Everyone wants to keep them as long as possible (just in case) but, some times, you have to cut.

I'll keep you informed. :cold_sweat:

140508_1.jpg

140508_2.jpg

140508_3.jpg

Hi all,

I have good news:

  • I've gone deeper into the extrashootings problem: finally i've managed placing a small cap ( 1uF) in between the encoder input and ground (see photo. By the moment I'll use ground and earth as the same thing: It's not).

  • I have reinforced ground too (used bigger cables and connected things closer to the controller). By means of that two things I've almost suppressed extra interrupts

  • By adding a line of code, I've completely supressed the remaining extra shoots (I'll post the code complete when completely debugged, tuned and commented), so I've got a beatiful graph like the one in the last picture. (Speed response over 15 s)

I hope having It ready for next weekend.

I'll keep you informed.

140513_CAP.jpg

First of all, well done for getting so far on your project!

Secondly, I have had strange errors from encoders before and solved this by adding pull-up resistors to the signal lines. This stopped any floating signal noise from creating unwanted encoder counts. I also had to add a capacitor to the encoder input in order to eliminate noise.

Thirdly, the following posts may be of use:

Arduino Due with Quad Encoder (works with only 1 encoder): Using the Hardware Quadrature Encoder Channel on the DUE - Arduino Due - Arduino Forum

Teensy Library for use with encoders (works with multiple) : Encoder Library, for Measuring Quadarature Encoded Position or Rotation Signals

Good Luck!

JW

Hi,

Thank you.

I've made more progress this week. I'll post them today or tomorrow (I hope).

Keep in contact.

Thanks again.

Hi all,

Well, I have reached my first objective. A summary:

  1. The goal was to build (program) a “speed servo” for a hobby DC motor (see photo). The motor I’ve been working on is the standard that almost any kit includes; it mounts a 10 teeth encoder.
  2. Even being (much) more difficult, I choose to develop it using interrupts instead of waiting for the encoder input to change: it pays more and more as new projects are developed over this (first) one.
  3. I had these problems:
    a. Noise: although the encoder has a (surprisingly) clean signal, the first attempt (code) detected interrupts almost four times than expected. Solved by adding a capacitor (see earlier posts).
    b. Serial.print: is a powerful tool, but for time dependent code it will betray you (by the way: I haven’t managed to change the baud rate. As I received the oscilloscope I discarded that method to debug, even at higher baud rates).
    c. Floating point arithmetic/variables/computing/existence (y la puta madre que lo parió, as we say in spanish; excuse me –in case you understand; for others I WILL NOT translate it- but it –float everything, I mean- is absolutely discouraging): the arduino reference tells it: “Floating point numbers are not exact, and may yield strange results when compared.”. They really do. I have lost hours (if not days) trying to guess what was wrong in the code: finally I had to test EVERY line of code having floating point variables in a different sketch, for I wasn’t –never- sure (still I am not) if the line needed more “float()” or “x.0” decimals or whatever make up to make it work. (By the way, I cannot imagine a code having the lesser relation with engineering in which floating point arithmetic can “be avoided” –reference page again-. Perhaps it is a C language matter; it is the first time I use it, so I will never complain again).
  4. After solving all these, I had to struggle with the motor itself, but I guessed it in advance: those motors aren’t linear (although “freewheel” they are almost linear) and, the worst, as my next step is to use all this stuff to make an obstacle avoiding car (the following ones are more related with speed), they start spinning at an unpredictable voltage. I have spent about 15 hours improving this; I’ll explain it later.
  5. So finally I have the results you can see in the pictures; left screens correspond to no feedback response and their counterparts are the “servo” ones. All of them correspond to the motor previously trimmed for freewheel spinning and loaded to make the test. (Remarks: 1) green: reference; yellow: motor speed. 2) Spikes: they are noise. 3) “visible” ripple (in the yellow line): is not caused by the loop. What happens is that the encoder teeth are not equal. (Believe me: look at the left –not servo- curves. They have the same ripple!). 4) “Freewheel” conditions the yellow and green curves superimposed almost perfectly for the no loop case.)
  6. As you can see, the motor follows the reference much better in servo conditions, that was the main goal. A comment on the ramp case: the code has a “non feedback” part that starts the motor (I will upload the code fully commented –I menace-); then the loop -feedback- section takes control. What you see is the best I’ve got after trimming the two variables (loop gain and “heave” to start) that make the motor to spin and control it’s speed: it looks awful, but without the “heave” and the loop control, the motor made what you see (or, in many times, it didn’t start at all. It happened sometimes with the triangle too –the motor stopped al low speeds and didn’t restart).

It’s all. (By the way: will anybody explain me how to change the baud rate and how can I upload the code?)

Thanks.

BAUD_RATE.bmp (1.38 MB)

I keep with the project: This guy HydraRaptor: DC to daylight is a genius; deserves a monument.

(I will explain why tomorrow)

Ok. Here I go:

After testing the motor and the code (speed servo), results were acceptable for a hobby proto, so I duplicated the code and connected a second motor (for the other side) and watched what happened.

The code worked fine, but the second motor induced such a big quantity of noise that for certain speeds the whole system became ungovernable. I wandereded on the net for a while and found this superb, fantastic, precise and useful article.

God bless him. Thanks.

Hi,

Here (in this thread, I mean) I am again.

I have the project (phase one, at least: making a two motor hobby car to move forward and backwards, rotate and stop) at a controlled speed for a fixed time and/or distance finished. The prototipe moves quite well, having in mind that there are some quality constraints: encoders with small (ten teeth per turn) resolution, motors too simple (plastic gear; no repetitive behaviour; not easy maintenance -greasing-). Sure with a little bit more sophisticated ones (bigger gear ratio; encoders with at least 50 teeth) it will work much better. (I'll try that; for the moment it fits my needs).

My goal is (in this first stage) mount an IR distance sensor on the prototipe and make an obstacle avoiding robot. I've wrote the software so you can use simple instructions ("Forward (centimeters, speed)", "Rotate (degrees, speed)") in the "loop()"; I want to get children involved firstly by using these "language". This is the real goal.. We will see.

You have to recognize that arduino is not a friendly platform: really you can switch on a LED quickly without any soldering , but you need a mountain of hours to do something a little bit more complicated from scratch. A complete different thing is the efficiency you have once you are trained: I received the IR sensor yesterday morning. After mounting it in an UNO board I had (have) it working in a couple of hours (I wrote my own software 8)). I'll use it right this week to measure how tall are my daugthers (13 & 10) and grandson (8). May be this is other way of stimulate them . . . . . :roll_eyes:

This week I posted part of the code (the most important one, in fact) in other trhead to show a guy how to use the "finite state automat" technique I've used to code the DC speed control module. I have to admit that this way of coding (that was NOT my first approach) is not intuitive, but is really powerfull: the (flow of) the speed control module complicated a bit and finally I decided to use it to ease coding :cold_sweat:. Nevertheless, apart from the program flow (the automat) part, the rest (the end) of the code is directly related to the speed control part and has the conventional "up to down" program flow.

Here you have it (I'll post the rest of the program once I have it fully commented)

Regards

The code:

////////////// ABSTRACT ////////////////////////

// This piece of code is an excerpt of a program to control a hobby car. Roughly: it is a function that, when -continuosly- called from the main loop, adjusts the speed of the motor to the desired one (AMSpeedDesired).

// The code works fine. As it has been posted just to show how to program a "finite state automat", the global constants and variables definitions, the setup and the loop code have been ommited.

// This is the code as it is in my program. Some of the code has to be improved -removing values and substituing them for variables, piecing the code into "subfunctions" to make it a little bit more readable, etcetera-. For the sake of clarity I've added some comments on the fly (the whole program is "half" commented). As it is my first "serious" program in "arduino C" you may find some inconsistencies (type of variables, mainly). Sorry for that.

// V. Fombellida (vffgaston). July 2014.

////////// Functioning of the program //////////////

// A "finite state automat" is a technique to code programs that have a complicated flow and/or have to attend "events" that appear randomly. You have a short explanation in the wikipedia (the example it shows is, in my opinion, too simple as to make oneself a complete idea on the power of the technique).

// In this example the DC motor can be in five different states ("AMStatus") that correspond to "Stopped",. "Controlled -Ramp- Start", "Feed back controlled -proportional control-", "Restart -from an abnormal stop-" and "Unconditional -not controlled- start". In addition to the normal "Current state -> Event -> Transition -> Next state" logic, in this example one out of five pieces of code -corresponding to the five states- is executed every time the function is called.

// The speed (AMSpeed) is obtained by calculating the inverse of the interval corresponding to the RISING edge of the last two teeth of the encoder. For this purpose (storing the times) an isr routine is executed every RISING edge.

// The automat table is stored in four arrays:

// const int AMCCCStatus[] = {0,0,1,1,2,2,3,3,4};
// const int AMCC__Event[] = {4,2,3,1,3,0,3,1,5};
// const int AMCCNStatus[] = {4,1,0,2,0,3,0,2,2};
// const int AMCCTrnston[] = {5,1,2,3,2,4,2,3,6};

// (On the analysis phase you will write this table with 9 rows 0-4-4-5 ....... 4-5-2-6 and 4 columns; I've coded it this way because it seems much easier to write the rest of the code -to search for a matching event, determine transition, etcetera-).

// Of course, the amount of rows on a particular case -and their content- is determined by your specific problem. Any case, the rest of the code (to look for the matching event, next state and corresponding transition) should be valid for any implementation.

// In this particular case, the events are all "internal" in the sense that all of them are generated by times exceded and the other parts of the code changing the "AMDesiredSpeed". Just the event "1" can be deemed as an external one (new tooth).

// Just to show the power of this technique: I added the state number 4 (the fifth, in fact) because the starting of those hobby motors is almost completely random (for the same DC voltage the same motor can actually start or it can decide to wait some hundredths of volt; to make sure it actually starts better to give it full voltage for a while). As, for this purpose, the code is trivial ("analogWrite(AMotPWM , 255);") the modification of the program flow (adding a line to the table) took few minutes.

/////////////////// A_M_Ctrl_Code /////////////////////
void A_M_Ctrl_Code()
{

// Specific variables and constants
int i = 0;
volatile float AMSCorrection = 0;
volatile float AMHeave = 0;
volatile float AMSpeedError = 0;
const float AMK = 40;
const int AMHeaveProp = 10;
const float AMSpeedCorrFactor = 0.25;
const float AMUnderSpeed = 4.0;
const float AMFxdStTime = 600;
/////////////////////////////////////////////////////
// Automat table

const int AMCCLines = 9;

const int AMCCCStatus[] = {0,0,1,1,2,2,3,3,4};
const int AMCC__Event[] = {4,2,3,1,3,0,3,1,5};
const int AMCCNStatus[] = {4,1,0,2,0,3,0,2,2};
const int AMCCTrnston[] = {5,1,2,3,2,4,2,3,6};

// Other automat variables
boolean AMCCUnattendedEvent = false;
int AMCCTransitionToExecute;

// Events updating
boolean AMCCEvents[6] = {0,0,0,0,0,0};

if (( float (millis() - AMSpCalCurTime)/1000.0) > (AMUnderSpeed / AMSpeedDesired))
{
AMCCEvents[0] = true;
}
else
{
AMCCEvents[0] = false;
}

if (AMSpCalPrvTime < AMSpCalCurTime)
{
AMCCEvents[1] = true;
}
else
{
AMCCEvents[1] = false;
}

if (AMSpeedDesired != 0)
{
AMCCEvents[2] = true;
AMCCEvents[3] = false;
}
else
{
AMCCEvents[3] = true;
AMCCEvents[2] = false;
}

if (millis() <= AMFxdStTime)
{
AMCCEvents[4] = true;
AMCCEvents[5] = false;
}
else
{
AMCCEvents[5] = true;
AMCCEvents[4] = false;
}

// Look for suitable event (corresponding to the current state)

while (AMStatus >= AMCCCStatus && i <= AMCCLines)

  • {*
    if (AMStatus == AMCCCStatus && (AMCCEvents[AMCC__Event*]))
    _ {
    AMStatus = AMCCNStatus; // Update state*

    * AMCCUnattendedEvent = true; // Flag for transitions*
    AMCCTransitionToExecute = AMCCTrnston*;
    }
    i++;
    }*_

*//Transitions managing *
if (AMCCUnattendedEvent)
{

* switch (AMCCTransitionToExecute)*
* {*
* case 0:*
* {*
* AMCCUnattendedEvent = false;*
* }*
* break;*
* case 1:*
* {*
* AMCCUnattendedEvent = false;*
* }*
* break;*

* case 2:*
* {*
* AMStatus = 0;*
* AMCCUnattendedEvent = false;*
* }*
* case 3:*
* {*
* AMCCUnattendedEvent = false;*
* }*

* case 4:*
* {*
* AMCCUnattendedEvent = false;*
* }*
* break;*

* case 5:*
* {*
* AMCCUnattendedEvent = false;*
* }*
* break;*

* }*
}
*//Code to execute. *
switch (AMStatus)
* {*
* case 0:*
* {*
* analogWrite(AMotPWM , 0);*
* AMDCOutputPrv = 0;*
* }*
* break;*

* case 1:*
* {*
_ AMHeave = AMK + AMSpeedDesired * AMHeaveProp * ((millis() - (AMSpCalCurTime))/ 1000.0);
* if (AMHeave > 255.0) AMHeave = 255.0;
if (AMHeave < 0.0) AMHeave = 0.0;
AMDCOutputNew = AMHeave;
AMDCOutputPrv = AMDCOutputNew;
analogWrite(AMotPWM , AMDCOutputNew);
}
break;*_

* case 2:*
* {*
* if (AMSpCalPrvTime < AMSpCalCurTime)*
* {*
* AMSpeed = 1000.0/(AMSpCalCurTime - AMSpCalPrvTime);*
* AMSpeedError = AMSpeedDesired - AMSpeed;*
_ AMSCorrection = AMSpeedCorrFactor * AMSpeedError;
* AMDCOutputNew = AMDCOutputPrv + AMSCorrection;
if (AMDCOutputNew < 0) AMDCOutputNew = 0;
if (AMDCOutputNew > 255) AMDCOutputNew = 255;
analogWrite(AMotPWM , AMDCOutputNew);
AMDCOutputPrv = AMDCOutputNew;
AMSpCalPrvTime = AMSpCalCurTime;
}
}
break;*_

* case 3:*
* {*
_ AMHeave = AMK + AMSpeedDesired * (AMHeaveProp * ((millis() - AMSpCalCurTime)/ 1000.0) - (AMUnderSpeed / AMSpeedDesired));
* if (AMHeave > 255.0) AMHeave = 255.0;
AMDCOutputNew = AMHeave;
if (AMDCOutputNew > 255.0) AMDCOutputNew = 255.0;
if (AMDCOutputNew < 0) AMDCOutputNew = 0;
AMDCOutputPrv = AMDCOutputNew;
analogWrite(AMotPWM , AMDCOutputNew);
}
break;*_

* case 4:*
* {*
* analogWrite(AMotPWM , 255);*
* }*
* break;*
* }*

}
//////////////// A_M_Ctrl_Code end //////////////////////
[/quote]

That looks great!

In software, the technique is normally referred to as Finite State Machine (FSM), in computer science courses they may refer to Finite State Automaton (FSA), but FSM is the general usage.

Your robot for kids reminds me of Logo http://el.media.mit.edu/logo-foundation/logo/turtle.html

Thanks,

It's the idea (logo). I thought making it with a "real" thing (the proto is a four wheels model) would be (perhaps :.) better. I will tell you in two weeks (My grandson comes in Spain next monday).

Thanks again