Spark! Fuzzy Logic Editor Help


Variables | Sets | Rules | API | Integration | Tutorial


 

Tutorial

In this tutorial you will build a fuzzy logic system that steers a RARS robot.  The acceleration of the robot is fixed.  You can write your own acceleration logic, steal some from an existing robot, or create a Spark! model to set the acceleration.  See "Now What?" for more details.

All the code you need is installed when you install the V1.2b version of Spark!  To verify that you have the correct version of Spark!, open Spark! and then select "Help | About".  If you're interested in the full RARS distribution check out the RARS Software page.

NOTE:  This tutorial is based on V1.2b of Spark! (the 2nd beta release).

 


Let's Get Started

 

Open Spark! and create a new model by selecting "File | New" or pressing the toolbar button

You now have an "empty" model that consists of 2 input variables, one output variable, and a rule block.

Save the model by selecting "File | Save" or pressing the toolbar icon.  Name the file "steering.spk" and place it in the 'rarsai' subdirectory.  This will be:

 C:\Program Files\Louder Than A Bomb! Software\Spark! Fuzzy Logic Editor\Example Files\rars075\rarsai 

assuming you installed Spark! in the default location

Note:  In the 'rarsai' directory you'll find a directory named 'original'.  This contains a steering model that you can use as a guide or use to run RARS if you're really impatient.

 


Determine Fuzzy Variables Needed

 

Now we must determine what the inputs to the steering model will be.  The goal of our robot is to stay in the middle of the track and navigate the turns.  Real simple - nothing fancy like trying to hit the "perfect line" around corners.  

Here are the inputs to the system:

  • Current Position
- Where we are on the track in relation to the center line we're trying to maintain.  
  • Facing
- The direction we're facing - more specific details on this later.  

Let's rename the Fuzzy Variables.  To rename the variable, click on the label in the tree view and type in the new name.  Enter the following names:

Original Name: Rename To:
Variable 0 Current Position
Variable 1 Facing
Output Steering Angle

 

Note:  The only restriction on identifiers in Spark! is that they must be unique (e.g. no two fuzzy variables can be named the same).  Spaces, dashes, etc. are allowed.

Your tree view should now look like this:

Note:  Capitalization does not matter

Save the model by selecting "File | Save" or pressing the toolbar icon. 


Create Sets

 

Now let's create some sets for the "Current Position" variable.  

Along with knowing if we're in the center of the track, or to the left or right of center, we also want to know if we're off the track.  Here are the sets we'll create:

Off Track Left
Left
Center
Right
Off Track Right

This variable's range is 0-100 (the default).  We will not change this as we'll express the "current position" as a value from 0-100 where 0 is the left side of the track and 100 is the right side.  More about this when we look at the robot code.  

Select the "Current Position" variable in the tree view.  To insert a set into the variable, we must go into "insert Set mode".  To do this select "Fuzzy Set | Insert Set Mode" or press the toolbar icon.

You will now see the "shadow" of the Set you can insert when you move the mouse over the variable view.  By selecting one of the "Membership Function" icons ()you can change the type of set to insert.  The default is the Triangle Membership Function - which is what we'll use for this tutorial.

To insert the Set, press the left mouse button.   You can change the width of the set BEFORE YOU INSERT IT by holding down the right mouse button and dragging the mouse up and down.

Insert 5 Sets, space them out evenly allowing each set to slightly overlap it's neighboring set(s).

Now, we want to move the Sets so we want to get out of "insert Set mode".  To do this you can select "Fuzzy Set | Insert Set Mode",  press the toolbar icon, or hit the ESC key.

Note:  If you insert too many sets, you can delete the extra set(s) by selecting the set then selecting "Fuzzy Set | Delete Set" or press the toolbar icon.

The sets were inserted with default names of "New Set x" where 'x' is a number indicating the order in which the set was inserted.

Note:  The first Set inserted does not have a number.

We want to re-name the sets so the names make sense.  Unlike most Fuzzy Logic tools you can use regular text to describe the sets.  Many systems limit you to using obscure abbreviations such as NV, FL, NZ, Z - don't ask us what they mean, we couldn't figure it out either.  Change the Set's names by clicking on the label and editing it.  

Original Name: Rename To:
New Set Off Track Left
New Set 1 Left
New Set 2 Center
New Set 3 Right
New Set 4 Off Track Right

 

Note:  You can also change the label by clicking on it in the tree view and editing it.

The order of the Sets is not important, they can be moved around.  So don't worry if you renamed "New Set 5" to "Center".

The fuzzy variable should now look something like this:

Save the model by selecting "File | Save" or pressing the toolbar icon. 

Note:  If you inserted the sets in the wrong variable - you can drag-and-drop them to the "Current Position" variable and continue with this tutorial.
 

Set Shoulders

 

This configuration (or your similar one) may work just fine, but we want to make two small changes.  The triangle membership function show us the Degree of Membership (DOM) of a set in the fuzzy variable.  If we look carefully at the "off track" sets they don't make much sense.  The DOM rises then falls, our degree of "off trackness" is only going to fall in the case of "left off track" or rise in the case of "right off track".  To indicate this we should make those set's "shoulders".

  • Select the "Off Track Left" Set and select "Set | Left Shoulder" or press the toolbar icon.
  • Select the "Off Track Right" Set and select "Set | Right Shoulder" or press the toolbar icon.
Note:  To select a set, click on it in the tree view or click ON the membership function in the variable view - clicking inside the membership function will not select the set.

Now our DOM values make a bit more sense.  You can see the DOM by moving the "tracker" at the bottom of the fuzzy variable.  When it intersects with a membership function the DOM is shown on the left and right. 

 In the illustration above, an input value of 21.61 results in the following DOMs:

Set DOM
Off Track Left .30

Left

.58
Center 0
Right 0
Off Track Right 0

 


Move The Sets

 

You can move the membership functions for the sets around as you wish.  To move an individual node of a membership functions, select it with the mouse and move it.  To move the whole membership functions, select a node and hold down the SHIFT key as you move the mouse.

While moving membership functions, if you want to show (or hide) the 'x' values for the it select "View | Set 'x' Values" or press the toolbar icon (by default this feature is already "on").

Save the model by selecting "File | Save" or pressing the toolbar icon. 


The Next Fuzzy Variable

 

Now on to the "Facing" variable.  Select the "Facing" variable in the tree view, that variable now appears in the Variable view (it's empty right now).  For this variable we want to change the minimum and maximum values.  To change them, click on the label and edit them.

Change the values to be:

Original Value: New Value:
0 30
100 -30

 

Note:  We'll explain why we selected these values when we examine the robot code.

The only restriction on min/max values is that they cannot be the same.

Now let's add some sets to this variable... refer back to the "Current Position" example above if you get stuck.  Make the "Facing" variable look something like this (add sets, set shoulders, and change set names):

Note:  The values on the upper left and right are a bit hard to read, this is because the "tracker" intersects the "left" set and is showing 100% DOM for that set - the values overlap a bit making it difficult to read.

Save the model by selecting "File | Save" or pressing the toolbar icon. 


The Output Variable

 

Now on to the output ("Steering Angle") variable.  Select the "Steering Angle" variable in the tree view, that variable now appears in the Variable view (it's empty right now).  Again,  we want to change the minimum and maximum values.  

Change the values to be:

Original Value: New Value:
0 1.57
100 -1.57

 

Note:  We'll explain why we selected these values when we examine the robot code.

For this variable we want 5 sets with almost the same distribution as the "Current Position" variable.  Since we've already done the work to position those sets, we can re-use them.  There are two ways we can re-use the terms:  cut-and-paste or drag-and-drop.  We'll look at each one here.

Cut-and-Paste is a standard operation in Windows software.  In this case we want to COPY, not CUT, but the idea is the same.

Select the "Current Position" variable in the tree view, and select the "Off Track Left" set.  Now copy that set by selecting "Edit | Copy", pressing CTRL-C, or press the toolbar icon.

Now select the "Steering Angle" variable and "paste" the set in by selecting "Edit | Paste", pressing CTRL-V, or press the toolbar icon.  The set is inserted in the same relative position as in the original variable.  The min/max values do not have to be the same to cut-and-paste between variables.  The "shoulder" attribute of the set is not carried over so you'll have to set that yourself if you want it - the relative position of the membership function remains so you get the same effect as if you set the shoulder attribute.

Note: The name of the Set is the same UNLESS there is already a Set with that name in the variable.  In that case the new Set is renamed to "Copy of X" where 'X' is the duplicate name

The second way to copy Sets is to drag-and-drop.

Select the "Current Position" variable in the tree view, and select the "Left" Set USING THE TREE VIEW.  Now hold down the SHIFT key (a '+' sign will appear next to the cursor) and drag the Set to the "Steering Angle" variable.  Release the mouse and the Set is "paste" into the variable.

If you did not hold down the SHIFT key the Set was MOVED to the new variable.  If that happened simply select the Set again and holding the SHIFT key, drag it back to the "Current Position" view.

Note:  Sets and Variables can be re-arranged by dragging and dropping.  The Notes and Rules views cannot be moved and are always last in the tree view.

Both methods (cut-and-paste and drag-and-drop) may be used to make copies of an Set within a variable.

Now rename the Sets to have the following names: 

Original Name: Rename To:
Off Track Left Sharp Left
Left Slow Left
Center Straight
Right Slow Right
Off Track Right Sharp Right

Set the shoulders for the appropriate sets and re-arrange the sets if you wish.  The output variable should now look something like this:

 

Note:  There is no "tracker" to check the DOM on the output variable

Save the model by selecting "File | Save" or pressing the toolbar icon. 


Creating Rules

 

We're now ready to create some rules for this fuzzy system.

Select the "Rules" node in the tree view.  You can now see a button for each set arranged in columns by Fuzzy Variable.  There are no rules for this model yet.  It may be difficult to see all the buttons in the rule view so you can resize the window and/or select "Rule | Fit To Window" or press the toolbar icon to rearrange the buttons to fit (as best as possible) to the current window size.  If all the buttons cannot fit, scrollbars will appear allowing you to view all the buttons.  

To create a rule, simply click on the set buttons that comprise the rule and select an output set.

For example:  Click on: "Off Track Left" (from the "Current Position" variable) and Right (from the "Facing" Variable).  Now click on "Sharp Right" in the output variable.  A line connecting those sets is created, that's a rule.   To remove that rule, click on the output set again and the line goes away.  To change a rule, simply select another output set and you'll see the line change. 

If we think about it for a little while, any time we're "Off Track Left" we want to get back on the track as quick as possible.  So for ALL cases where "Off Track Left" is active we'd want the output to be "Sharp Right".  

We'll create three rules:

  1. Press down the following buttons:  "Off Track Left", "Right", "Sharp Right" - you probably already created this in the steps you just finished.  
  2. Press down the following buttons:  "Off Track Left", "Center", "Sharp Right"
  3. Press down the following buttons:  "Off Track Left", "Left", "Sharp Right"

Note:  If a button is already pressed down, clicking on it a second time "pops" it up.

That wasn't so bad, but with large systems creating rules like that could get ponderous.  We need to do the same thing for "Off Track Right" but rather than creating a rule for every  Set that involves "Off Track Right" we can take a short cut.  

Click on "Off Track Right" and un-press any other sets so "Off Track Right" is the ONLY button pressed down.  Now hold down the shift key and click the "Sharp Left" set on the output ("Steering Angle") variable.  Three rules are now created and displayed.

The rule view should now look like:


At this point you may be wondering why some lines are bolded and others are not.  Rule are bolded in one of two situations:

  1. When they are "active"
  2. To indicate that they are part of the currently pressed buttons

"Active" rules are determined by the input to the system.  See the little rectangle under each button?  That is a graphical representation of that set's DOM (Degree of Membership) for the current input. 

Note:  If there are no "DOM bars" select "View | Active Rules" or press on the toolbar.

Since we made "Off Track Left" and "Left" shoulders they're activated (100% DOM) when the inputs are at the minimum (0 and 30 respectively).  In our model when "Off Track Left" and "Left" are "active" the "Sharp Right" rule is activated.

Go to any variable and move the tracker (the little pointer at the bottom of the variable), you'll see the DOM values, and probably active rules, change in the rule view.

When building rules having the "active" rules showing can be confusing.  To turn them off select "View | Active Rules" or press on the toolbar.  Now the only bolded rules will be the ones that are part of the currently pressed buttons.  This is the other way rules get bolded.

A rule is bolded if it involves the currently pressed buttons.  Pop up all the buttons in the rule view and turn off "Show Active Rules" (select "View | Active Rules" or press on the toolbar).  No rules should be bolded.  Now press the "Sharp Left" button.  ALL the rules that result in an output of "Sharp Left" are bolded.  Now click on the "Center" button for the "Facing" variable.  Now only the rules that result in "Sharp Left" as an output and involve "Facing Center" are shown.  This feature is very helpful when building and debugging rules.

Let's move on, first turn back on "Show Active Rules" (see above if you forgot how).  Each button in the rule view should now have the little rectangle below it.

Your buttons may be in a different order.  To move buttons you can "lasso" them by clicking the right mouse button on a non-button area and dragging to lasso the buttons you want to move.  After the buttons are selected, click on any of the selected buttons and you can move them around.

The following is a list of suggested rules, you're free to make up your own but we recommend you use these: 

Current Position Facing Steering Angle
Left Right Straight
Left Center Straight
Left Left Slow Right
Center Right Slow Left
Center Center Straight
Center Left Slow Right
Right Right Slow Left
Right Center Slow Left
Right Left Straight

If you think you've missed a rule, select "View | Missing Rules" or press the toolbar icon.  This will show any missing rules.  This "mode" acts just like the regular (show rules) mode, if any buttons are pressed, only the missing rules that INVOLVE those buttons will show.  To show ALL missing rules, make sure no buttons are pressed.

Note:  "Show Active Rules" has no affect when viewing missing rules.  Also, you will not see connections to the output variables because once there is a connection to an output set, that's a rule!

Save the model by selecting "File | Save" or pressing the toolbar icon. 


Integration

 

When integrating a Spark! model into any application, many of the Spark! API functions require the index of the variable  to be passed in (see functions like set_value() and get_value()).  This index does not correspond to the position of the variables in  Spark!  The index values should be obtained from the .h file that is exported by Spark!

For this tutorial, we've already written the integration code (see the robot code) so exporting the .h does nothing.  But we'll take the usual steps you would if you were starting from scratch.

Now, we need to export the .h file by selecting "File | Export .h File" or pressing the toolbar icon.  The .h file will be named (by default) steering.h, save this to:

C:\Program Files\Louder Than A Bomb! Software\Spark! Fuzzy Logic Editor\Example Files\rars075\robots


Congratulations!

 

You are now able to run RARS and see how your steering model works.  If you want to examine the RARS robot code, read on but if you followed the instructions above you don't need to modify the RARS robot code - it's already set up to use the steering model you just created.

To run RARS go to:

C:\Program Files\Louder Than A Bomb! Software\Spark! Fuzzy Logic Editor\Example Files\rars075

and run the vc_rars.exe program.  You'll see the following screen:

With only 1 car racing, RARS will default to the SparkTutorial01 car which you just wrote the steering logic for.  Press "Start Race" and watch your steering logic work!

Note:  If you leave Spark! running you can watch the fuzzy logic model work - in real time!  You can change rules, adjust sets, etc. and watch the changes in RARS without recompiling!
 

If you get an error message like:

You didn't save the model in the correct directory.  Make sure the model you just created is named "steering.spk" and it is in (assuming the default installation path):

C:\Program Files\Louder Than A Bomb! Software\Spark! Fuzzy Logic Editor\Example Files\rars075\rarsai 

The following is a list of (kinda) oval tracks - these are the easiest to navigate and you may want to use these first as you tune your ai:

  • Oval2 
  • Milwaukee 
  • Nazareth
  • Phoenix
  • Pocono 
  • Indianapolis   
  • Michigan  
     

RARS Code

 

Now we'll examine the inputs and output to RARS that we just created.  In the steering model we use Current Position and Facing.

Current Position

This input is a value from 0 to 100.  A value of 0 indicates the car is on the left edge of the track.  A value of 100 indicates the right edge of the track.  If the car is in the center of the track, Current Position will have a value of 50.

Facing

This input is the RARS vn variable.  It's the component of velocity which is perpendicular to the track edge.  This tells you if you are drifting toward a edge, and how fast.  You need to keep this from getting very large or very negative or you will go off the track soon afterward.  Negative means heading toward right wall.  See Tutorial 6 for more details and a great diagram showing this variable.

That's why the minimum for Facing is 30 and the MAXIMUM is -30.  

Steering Angle

The output from the Spark! model is the angle of the steering wheel in RADIANS.  

This variable has a minimum value of 1.57 and a maximum of -1.57.  Again, the negative value is the MAXIMUM.  This is just the way RARS does things.  So a positive value means make a right turn, a negative value means a left turn.

Degrees Radians
90° left 1.57
90° right -1.57

Quick Aside For Those Of Us Who Forgot What Radians Are

The size of a radian is determined by the requirement that there are 2 radians in a circle. Thus 2 radians equals 360 degrees. This means that 1 radian = 57.3 (180/) degrees, and 1 degree = 0.0175 (/180) radians

Spark! Integration

Now you're probably wondering how to "hook" in the model you just created to an application.  Keeping with the theme of this tutorial you can take a look at the code for the robot named SparkTutorial01.  This the "robot code" to run the car used in this tutorial.  For more in-depth integration information see the Spark! integration documentation.

That's it!  You now know enough to start building Spark! models on your own and creating better ai!