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.
Ultrasonic is next R2D2
But, in the mean time (as I plan to take a few days away this weekend) feel free to try it yourself. Hint: Ping is the other way around to IR, so anything that is less than needs to change to greater than and vice versa). If you aren't bothered about variable names being wrong it's a very easy change, 6 lines of code is all that would need changing, literally a 2 second job.
All of the scripts are in the EZ-Cloud for easy downloading and altering. All of them are saved in script manager, named part 1, part 2, part 3 and part 4 so should be easy to alter.
@R2D2. I got impatient again/
Part 5 - Ultra Sonic Sensor
So far we have been using the IR sensor and GetADC to find out if there is anything or anyone in close proximity to the robot but HC-SR04 Ultra Sonic is the more popular option. So let's take a look at what we need to change to use HC-SR04 Ultra Sonic sensors.
We will start off with the script from Part 3 with one sensor. A little "challenge" for you would be to update the last script in part 4 to accept ultra sonic rather than IR if you fancy a quick test
Anyway, the code as it was;
The first thing to look at would be the way we check the proximity. Currently we use the GetADC command as explained in part 1 but that is not the correct command when using a HC-SR04 Ultra Sonic sensor. There is a special command written just for the sensor called GetPing
So we need to replace the GetADC parts with GetPing...
Now, if you tried running that code or clicking on the check syntax button it would tell you there is a problem. The GetPing needs two ports to be defined. One for the Trigger and one for the Echo. So we need to update that line and we need a couple more new variables to define.
And update the configuration variables to suit the new variables and remove the old redundant ADC variable. We may as well update the version number while we are at it too.
So now we have the code checking the HC-SR04, the code checking the value against the pre-set distance value and acting accordingly... Well, almost!..
One more thing that needs to change is the IF which checks the values. The IR sensor's value increases when it gets closer to an object but the HC-SR04 sensor's value decreases. So we need to turn that condition around;
becomes
And when it's all put together you will end up with something a little bit like this.
In Part 6 I will go through updating the code with 3 sensors and adding in options in the configuration to choose if it uses IR, Ping or both. Feel free to take a crack at it yourself.
The same principal can be used for other sensor types. Light sensors to act when it gets either dark or light. Gas sensors to act in the event of a gas detection. The camera with color detection or face detection. There are endless possibilities and I hope to see them on your robots
.
@ Rich, your scripts are so versatile and adaptable to many robots, it's like going to the supermarket i choose the meal. The variables seem to offer endless possibilities, although, also require a large brain squeezed at times. I'm eager to see the next chapters
Hey @Rich
Very impressed with your work and may well grab it for my students at school....
Since this is being shared far and wide have you considered adding a description box and adding your name?
Eg.
Identification of authorship here is intended to help direct questions to the author and not for copyright or ownership purposes.... lol
@Tameion
I have considered that and have full header information in my scripts in my project (and pretty much any other scripts or code I have ever written) however in these tutorials I didn't bother as the pages and posts are very long as it is.
If you download the project with the scripts in you are greeted with a nifty little notepad control though with a bit more information in it
.
It is as I expected it would be....
Keep up the good work $)
BTW the cleanup you did of the time script was impressive.... just trashed mine and replaced it with yours - Lol
Any time you want to use these for your students feel free by the way. If you want to pay for me to come and talk to them I'd be up for that too
Thanks for the kind words
Part 6 - Multiple Ultrasonic Sensors
Last time we went through changing the IR sensor to Ultrasonic. Now we will change the script for 3 IR sensors to give the option of 3 IR or Ultrasonic Sensors.
So we start of with the code for 3 IR sensors from Part 4;
The key areas to adjust in this script are the variables, to allow for the option of IR or Ultrasonic and the runaway and sensorcheck sub routines.
We already know, from Part 5 that the ultrasonic sensors require 2 digital ports, one for Trigger and the other for Echo. So we know that we need some variables for these ports added at the top of the script. We also want to add in the option variable for choosing IR or Ultrasonic.
So we visit the variable area of the script;
Since it's getting big, and it's all about making things as easy as possible while we are here we will also restructure it to make it easy.
First we want to set out the Options such as sensor type and only when moving forward;
Next we will set up the movement configuration;
Then we will set out all of the Port Configuration including the 6 new variables for the Ultrasonic sensors.
And finally we need to put down the detection sensitivity configuration
Now it looks like a really complex script but really all we have done is set up a bunch of variables. This shows my point about breaking down code to figure it out, a lot of the time it will look a lot worse than it is.
Combine all of the smaller pieces of the configuration to give you the start of the script;
Now we have the variables all set up it's time to tackle the sub routines.
We will want to look at the sensor check routine first as without it the runaway routine wouldn't know the direction to turn in. So we have the routine from Part 4
In to that we need to add a few things. First the code for checking the ultrasonic sensors and second the commands to decide which sensors to check.
Adding in the code for the ultrasonic sensors is pretty much the same as Part 5 changing the code. But in this case we leave the IR code in there also.
The code to check a ultrasonic sensor is;
We want to assign these to variables like the IR readings so for all three sensors we would have something like;
But, we only want those commands run if the configuration says so. The same goes for the IR code. So we add in another IF to check on the option and run the code if it is turned on.
So now the code to check the ADC and Ping will only run if the configuration is set to check them. And that's almost it for the sensorcheck sub routine, all that is left is the code to run the runaway code;
Simply add it to the above code;
Now the code will check the sensors as specified in the config and if any of them fall within the conditions it will run the runaway code.
So now we need to look at the runaway code. The final part of this.
So it's already set up for the IR sensors from Part 4 but we need to add in the same kind of checks as the sensorcheck code had added while on the other hand avoiding any rouge commands from unused sensors. A few more IFs come in to play here again, just like the sensorcheck.
And then put all of that together and you have the final code for Part 6
Now I have deliberately left one minor bug in the code somewhere. I will reveal it and tackle it in a later post but I figured if I was getting tired of writing this then you would be getting tired of reading it, so digest the above until next time. See if you can find the bug and feel free to post about it (I leave myself open for other bugs doing this but hey, all of us are learning including me).
Adding in test mode may well be the next part and overcoming the minor bug mentioned. Both should tie in nicely together.
As always this script example, while will run fine and function correctly is not supposed to be a working example for a useful function but supposed to explain the methods used to have actions and commands run depending on circumstance.