All script examples are on the EZ-Cloud for download and updated after each additional post Download Now
Index Part 1 - You are here Part 2 - Page 1 Post #6 Part 3 - Page 1 Post #8 Part 4 - Page 2 Post #6 Part 5 - Page 2 Post #9 Part 6 - Page 3 Post #5 Part 7 - Page 4 Post #3
I have some time on my hands and nobody seems to be asking questions at the moment so I though I'd just write up a nice and simple introduction in to EZ-Script. I may write more in the future but we will see how received this is first.
EZ-Script is a powerful scripting language with a wide variety of commands. The command user manual is displayed to the right of the EZ-Script environment within ARC and a PDF version of the manual is maintained and downloadable from here.
Scripting needn't be difficult. A lot of people see lines and lines of code in the examples and are overcome by this however the number one rule in scripting, at least for me is to think logically, dumb it down and tackle one piece at a time.
I will go through how to write an example script in a logical manner and have a working script as an end result. In this example we will define variables, look at If statements, control devices attached to the EZB and read data from the EZB.
First we need to work out the algorithm for the task we want to achieve. Think of it as you think of a recipe when making a meal. It's a sequence of events in a specific order to achieve the overall result.
This example we will make our robot scared of contact and run away when anyone or anything comes in close proximity. In order to achieve this there are some hardware requirements; Drive motors or servos Proximity detector
For this example we will assume the robot is driven by DC motors via a 4 wire HBridge, with a correctly set-up HBridge Movement Panel in ARC and for proximity detection a low range infra red sensor connected via the ADC port ADC0.
So first, we need to think about what it is we are doing. We need to know if anything is coming in close proximity to the robot so we need to read the information supplied to the EZB via the infra red detector.
EZ-Script has a neat command for this, the GetADC command;
Quote:
GetADC( Port ) Returns the ADC value of the specified port Example: GetADC(adc0)
So the first part of our code would be to get that ADC value and store it in a variable for ease of use. We will call this variable $proxsense. Notice the $ symbol preceding the variable name, this is required for all variables.
$proxsense = GetADC(adc0)
The value of ADC0 is now stored as the variable $proxsense.
So now that we have the value of the proximity sensor we need to use it. We need to know if someone or something is in close proximity to the robot, so we need to compare the value of ADC0 to a known close proximity ADC value. This varies on different hardware and testing may be required for accurate results. For the benefit of this example we will assume an ADC value of 50 or less is close proximity.
So let's add this as another variable;
$proxclose = 50
Easy right? It doesn't get much harder either
So we have the current sensed proximity value and the minimum allowed proximity value stored as variables. We want to be able to do something if the sensed proximity is more than the maximum allowed proximity. If you read that sentence you may be able to work out the next command we need to look at...
The IF command;
Quote:
If (Value Condition Value ) IF condition can support multiple comparisons and functions. Condition tree must be closed with an ENDIF See the Functions section of this document. Condition can be =, , =, , AND, OR Example: If (GetDigital(D0) = 1) Print("One") EndIf Example: If ($Day = 2 AND $Hour = 3) Print("Hello") EndIf
So let's look at this logically, we have the sensed proximity, the maximum allowed proximity and want to see if one is higher than the other.
IF($proxsense > $proxclose)
ENDIF
This will look at $proxsense, check it against $proxclose and if it is greater than (>) $proxclose it will run the next commands. If not then it will jump down to the endif command. All if statements must be finished by an endif command.
So the code so far should look like this;
$proxsense = GetADC(adc0)
$proxclose = 50
IF($proxsense > $proxclose)
ENDIF
While the code will compare the values it still doesn't do anything. Nothing has been defined in the if statement. But what we have achieved is for the script to now be able to find out if someone, or something is in close proximity to the robot.
So now we want to have the robot do something if the statement is true. The next question is what do we want it to do if someone or something is too close? We want it to run away, all scared and full of panic.
So how do we do that?
First we decide if we want the robot to just reverse away, as if running backwards. We could, but do you run backwards? No, you turn and run. So we will make the robot turn 180 degrees (roughly) and run away.
How do we do this in EZ-Script? Easily!..
EZ-Script has all five of the Movement Panel commands. Forward, Reverse, Stop, Left and Right;
Quote:
Forward( [speed], [milliSeconds] ) Using a Movement Panel Control, this will start your robot in the Forward direction. Optionally, you can provide the speed and/or number of milliseconds to move. You will require at least one Movement Panel to be configured within the project. This function will control that movement panel. Speed is a number between 0 and 255 Example: Forward() Example: Forward(200) Example: Forward(255, 5000)Reverse( [speed], [milliSeconds] ) Using a Movement Panel Control, this will start your robot in the Reverse direction. Optionally, you can provide the speed and/or number of milliseconds to move. You will require at least one Movement Panel to be conf igured within the project. This func tion will control that movement panel. Speed is a number between 0 and 255 Example: Reverse() Example: Reverse(200) Example: Reverse(255, 5000)
Stop() Using Movement Panel Control, this will stop your robot. You will require at least one Movement Panel to be configured within the project. This function will control a movement panel. Example: Stop()
Left( [speed], [milliSeconds] ) Using a Movement Panel Control, this will turn your robot left. You will require at least one Movement Panel to be configured within the project. This function will control that movement panel. Optionally, you can specify the speed and/or number of milliseconds to turn. Speed is a number between 0 and 255 Example #1: Left() Example #2: Left(200) Example #2: Left(200, 5000)
Right( [speed], [milliSeconds] ) Using a Movement Panel Control, this will turn your robot right. You will require at least one Movement Panel to be configured within the project. This function will control that movement panel. Optionally, you can specify the speed and/or number of milliseconds to turn. Speed is a number between 0 and 255 Example #1: Right() Example #2: Right(200) Example #2: Right(200, 5000)
Direction of turn doesn't matter so either the left or the right command would be suitable. For the purpose of this example we will turn left. To turn 180 degrees is not an exact science since the robot has no means of knowing it's direction. Turning is time based and this must be calculated by timing your robot for how long it takes to rotate 180 degrees. For the purpose of this script we will assume the robot rotates 1 degree in 0.1 milliseconds or 180 degrees in 1800 milliseconds.
LEFT(255,1800)
Now that the robot has done an about turn and is facing away from the scary thing in front of it it needs to run forwards to get away. So a forward command is issued. We will make it run away for 5 seconds.
FORWARD(255,5000)
And that's it. As simple as that. So the code so far should look like;
LEFT(255,1800)
FORWARD(255,5000)
Now let's put it all together. We can do this a couple of ways. One way would be to put the left and forward commands inside the if statement, and if you have a basic script there is nothing wrong with that at all but I want to show you the Label, Goto and Return commands too;
Quote:
:Label Defines a label for a GOTO() command Example: :My_LabelGoto( label ) Goto a specific :Label location Example: Goto(My_Label)
Return() Return from a Goto() If you jump to a position of code with a Goto(), the Return statement will allow you to return back to that piece of code following the last Goto() If you attempt to Return() with an empty stack, nothing will happen. The script will ignore the Return() statement. Example: Return()
These commands can be used to set up what I like to call Sub Routines. A small piece of code which can be called up from many places within the code. These are great if your script is long and manages many different tasks that all may require the same sub routine.
So we set up the "runaway" sub routine;
:runaway
LEFT(255,1800)
FORWARD(255,5000)
RETURN()
And then we add in the Goto to the first part of the code we wrote;
$proxsense = GetADC(adc0)
$proxclose = 50
IF($proxsense > $proxclose)
GOTO(runaway)
ENDIF
And when we put it all together;
$proxsense = GetADC(adc0)
$proxclose = 50
IF($proxsense < $proxclose)
GOTO(runaway)
ENDIF
:runaway
LEFT(255,1800)
FORWARD(255,5000)
RETURN()
At this point there is an obvious problem. Once the script runs and the if statement is run it follows on to run the runaway code, regardless of the outcome of the if statement. It also only runs once. This is taken care of with another label and another goto command. The label at the start of the script and a goto after the endif. This loops the script around forever.
The code should now look like this.
:loop
$proxsense = GetADC(adc0)
$proxclose = 50
IF($proxsense > $proxclose)
GOTO(runaway)
ENDIF
GOTO(loop)
:runaway
LEFT(255,1800)
FORWARD(255,5000)
RETURN()
The last thing to tackle is the demand the script above may have on the hardware and your PC. Reading from the ADC port can be demanding on the system. The way to overcome this is with a Sleep command, which pauses the script for the desired time.
Quote:
Sleep (milliseconds) Pauses for specified milliseconds Example sleeps for 1 second: Sleep(1000)
To restrict the number of reads of the ADC port we will add in the sleep right before it loops around, giving a sleep command for 1 second.
:loop
$proxsense = GetADC(adc0)
$proxclose = 50
IF($proxsense > $proxclose)
GOTO(runaway)
ENDIF
SLEEP(1000)
GOTO(loop)
:runaway
LEFT(255,1800)
FORWARD(255,5000)
RETURN()
And there we have it, the completed script. It's simple yet effective. The script will run, it will then check the value of ADC0, check if this is less than the minimum allowed value, if it is then it will jump down to the "runaway" sub routine, turn left, run forwards and return back to the main script. If not then it just loops around and around forever.
This post has not been written with the intention of showing a detection script but more for showing how to tackle writing any script. I hope you can now take what I have shared above and start creating your own scripts and routines to make the robot perform the tasks you require it to perform.
If you have any specific tasks that you would like to achieve but cannot quite figure out where to start please mention them and we can all discuss the way to do this, break it down piece by piece like the above and find you your solution.
I would like to see a script in digital outputs for bcd decoding I have a project that needs to decode a digital circuit using bcd 1,2,4 and 8 using 4 digital I/0.
ANY help would be cool
Also, just to answer any questions anyone may be thinking about "Why would I want to allow for two different types of sensors in my robot?" since I've not addressed that yet other than purely for flexibility in sharing scripts.
It's leading up to this but with the variables and the IF nests to only check and run code depending on the variable we will eventually be able to use $time and $date or even other sensors, locations etc. to have the robot decide for itself which sensors to use.
A typical example is the IR sensor which dislikes natural light, or sunlight. Not a problem in the UK, we haven't seen the sun other than in movies or on TV. But if it's daytime you could have your robot only use the UltraSonic sensors. When it gets dark out it changes over to IR.
I don't see where you're enabling the "Runaway" script...no GOTO(runaway). Is that the bug?
Have I missed that?.. Oops... time for an edit (the disadvantage of doing it in parts and having to piece it back together)
That wasn't it, although good eye
It seems I completely messed up the :sensorcheck part somehow...
All fixed
I just messed up the :sensorcheck subroutine in the final script. The call for runaway was in the snippets above it all but I copied and pasted the wrong bits. And that's why it pays to triple check before posting.
Thanks for these lessons Rich. They will be tremendously helpful to me during the next stage of my build. You are providing us with a stepping stone into the wonderful world of scripting and I am grateful for that. I am sure I will have many questions for you
I am following your robot build with great interest. It's going to be very cool.
Rex
Rich's work is always impressive, I think it's a good job for everyone, you could afford to order some customized shirts with the words "Doctor script"

It fills me with joy whenever I read how well received this is. They do say that helping is it's own reward and I have to admit they were right when they said that. Besides, it is something that I can get lost in and it helps me unwind and escape, forgetting the problems of the day
And additionally, if it results in more people being able to put together scripts it means there are going to be loads of scripts for all to use, all doing different awesome functions.
I have plenty of plans for the small tutorials so expect them to continue coming for a while longer yet. There are things I've not yet touched on, there are things I have not even used myself yet but all will be covered eventually.
I'm waiting on my serial LCD display currently, I have a few plans for tutorials for using one of those with variables and making it display information or even animate text (if I can figure it out myself - I wont know until it turns up though).
Math functions are also something I want to cover too. The idea from the ping avoidance with sweeping servo script for having the robot center itself in a corridor is one I can't wait to explore and sharing that should be both informative and fun.
The best thing though is by explaining each step of the way I am finding I learn more too, and it gets committed to memory. Which is great as I can write script ideas while at work and figure out what's required, in what order etc.
Once again, thank you everyone for the kind words, they mean a lot. It's nice to see the appreciation after some things that have been popping up recently.
Part 7 - IF conditions
While a big bug was spotted it wasn't the one I was referring to. But due to the way I am writing these I kinda messed up while piecing the code back together - the code in the project file on the EZ-Cloud was correct (in my defence).
But the bug I was referring to is in this part of the code;
What could happen is a double runaway. The code first checks if IR sensors are active, if they are it will check to see which way to run away. Execute the run away (if required) and then check if Ping sensors are active, if they are will run away again.
I left this in as it lead on to the next part I wish to explain and example. The conditions that can be used within IF commands.
If we refer to the EZ-Script manual under IF we are told that;
I'm assuming the forums have replaced some of the conditions due to the formatting, but if it has just look in the EZ-Script Reference Manual. You will find it on page 5.The conditions we need to look at are AND and OR. We want to combine the code above so that if both sensor types are enabled it will perform an AND and an OR check. Currently it just checks for AND, to ensure that two of the sensors are either higher or lower than the other (depending on sensor type) to determine which sensor has the closest proximity.
Using AND and OR in the same condition is pretty straight forward but you must write the condition correctly. Think about it logically, imagine someone is giving you instruction for instance "if the time is 12am and it's a monday or if the time is 4am and it's a saturday you should be asleep in bed" two separate conditions combined in one. It wouldn't make much sense if it was "if the time is 12am or the time is 4am and it's a monday or a saturday..."as you wouldn't know which time goes with which day.
So, let's take a look at the code and change it to avoid the bug. My way of doing this may be different to someone else's way but I'm a firm believer in stick with what you know. My way would be to adjust the whole routine and rather than use two different IF conditions which run one after the other to use one IF condition with ELSEIF so that if the first is true then the rest don't matter, if the first is false it checks the second, and so on.
We will also need to add in a further condition to check if both sensor types are to be used. In an effort to save the post becoming very long I will only post the outline of the code for now.
So now the code will have a choice of three options. The final ELSEIF could be just an ELSE, I prefer ELSEIF to ensure it only runs if the condition is met, it's personal preference really.
The code within the ELSEIF ($irsensor = 1) and ELSEIF ($pingsensor = 1) remains as it was however in the new code for both sensors at once we will need to combine the two.
This is where the AND and OR conditions come in to play. We need to work out what it is that needs to be true to run what code.
We know that; If the left hand sensors detect proximity we need to move right If the center sensors detect proximity we need to move left If the right hand sensors detect proximity we need to move left
We also know that; If the left hand IR reading is higher than the center IR reading and the left hand IR reading is higher than the right hand IR reading then something is to the left. If the left hand Ping reading is lower than the center ping reading and the left hand Ping reading is lower than the right hand Ping reading then something is to the left. If the center IR reading is higher than the left hand IR reading and the center IR reading is higher than the right hand IR reading then something is in front. If the center Ping reading is lower than the left hand Ping reading and the center Ping reading is lower than the right hand Ping reading then something is in front. If the right hand IR reading is higher than the left hand IR reading and the right hand IR reading is higher than the center IR reading then something is to the right. If the right hand Ping reading is lower than the left hand Ping reading and the right hand Ping reading is lower than the center Ping reading then something is to the right.
So let's put that as IF conditions (very long if conditions);
So now it checks if the left IR is higher than the other two or the left Ping is lower than the other two. The same for the center and the same for the right.
And then it is just a case of adding in the code for turning the robot in the right direction, and putting it all back together
Also, the sensorcheck code needs a slight adjustment;
This code will currently run checks on the IR if applicable, then could run the runaway code without knowing the ping sensor readings. Then it will run the runaway code after receiving the Ping sensor readings again (if applicable), that's if it hasn't halted on error.
To overcome it is very simple with IF. First we need to check which sensors are active with the
much like in the above routine.
Then the required code for checking only the sensors used added in to the IF and ELSEIF conditions, with the code for both sensors having the IF condition for running the runaway code checking all three IR sensors and all three Ping sensors, if any are true then runaway.
You could, if you wanted to, add in two new sub routines for getting the Ping and getting the IR sensor readings and replacing the code for Gotos however with only using the same code twice I have opted to just add it in twice. It's personal preference, personally once or twice I will type it all out, three or more and I like to make sub routines. I digress, but if you want to test what you are learning a good exercise would be to make the routines and call them up.
Now that the sensorcheck code is also fixed it's time to piece all of the bug fixed code together. You should end up with something a little bit like this;