Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

2D LUA Based Robot Simulator

4.89/5 (26 votes)
14 Apr 2014Public Domain9 min read 135K   8K  
An article on designing your own robot simulator
Image 1

Introduction

Here, I would like to introduce a 2D mobile robot simulator. With this simulator, we can design how a robot will navigate in a 2D world by using a set of rules that we design. The rules are designed by using Lua script. Lua itself is a powerful, fast, lightweight, embeddable scripting language. Using Lua will offer us many benefits in designing algorithms for mobile robots. For the world editor, we use GDI Device Context programming. Users can create the environment for testing the robots by using the click and drag method. Here is a summary of the features:

  • Differential steering robot
  • Multiple-robot simulation
  • Sonar and laser beam type distance sensor
  • Embedded Lua script for the robot code
  • Graphical world editor
  • Code editor with syntax colorization and auto completion

Knowledge in Lua is also necessary. Lua is not something difficult to learn. You can check the Lua website.

The Robot Theory

The robot that we have here is a wheeled robot. It has two wheels. It navigates with a differentially steered drive system. A differentially steered drive system is like a wheeled chair. Steering a wheeled chair can be done by varying the speed of its wheels. If one wheel is rotating faster, the wheeled chair will make a curved path. If both wheels are on the same speed, it will make a straight path.

The Robot Mathematics

For details about mobile robot theory, you can refer the G.W. Lucas tutorial. To make it simple, here are the equations used to model differential steering behaviour:

Image 2

If the left wheel and the right wheel are at the same speed, the equation above cannot be implemented since it will result in division by zero error. Using L'Hospital's rule, it can be shown that the equation has limits approaching a straight line (check again the G.W. Lucas tutorial). So, when the left wheel and the right wheel are at the same speed, use this equation (please notice that dx/dt means the difference between the current x position and the previous x position):

Image 3

Image 4

To get the current position of the robot, we only need to input the time, left wheel speed, and the right wheel speed to the equation above. The robot angle is something that we also need to calculate. Here is the equation to calculate the robot angle:

Image 5

Finally, here is the implementation code for those equations:

C++
void CRobot::goRobotGo(double *t){
    if (canResetTime){
        *t = 0;
        canResetTime = false;
    }

    int plusFactor = m_robot.rWheelSpeed + m_robot.lWheelSpeed;
    int minusFactor = m_robot.lWheelSpeed - m_robot.rWheelSpeed;

    if (m_robot.lWheelSpeed - m_robot.rWheelSpeed != 0.0){
        m_robot.theta = m_theta0 + minusFactor * (*t) / m_robot.size ;
        m_robot.pos.x = ceil(m_pos0.x + m_robot.size / 2 * plusFactor / minusFactor
                        * (sin(minusFactor * (*t) / m_robot.size + m_robot.theta0)
                        - sin(m_robot.theta0)));
        m_robot.pos.y = m_pos0.y - m_robot.size / 2 * plusFactor / minusFactor
                        * (cos(minusFactor * (*t) / m_robot.size + m_robot.theta0)
                        - cos(m_robot.theta0));
    }
    else{
        m_robot.pos.x = plusFactor / 2 * cos(m_robot.theta) * (*t) + m_pos0.x;
        m_robot.pos.y = plusFactor / 2 * sin(m_robot.theta) * (*t) + m_pos0.y;
    }
}

All things related to the robot are put in the class CRobot in the files Robot.h and Robot.cpp.

The World Editor

The world editor is simply an implementation of GDI device context programming. We use simple graphs such as rectangle, ellipse, and line to create rooms and obstacles. With a little math, we can make those graphs selectable, moveable, and resizable. This world editor is based on my own previous work. I know it is very simple and also not good since I received several bad responses on it. I will make it better if I have time. All things related to the world editor are in CCanvas in the files Canvas.h and Canvas.cpp.

The Code Editor

For the code editor, I use the Scintilla library. With the Scintilla library, we can easily make an editor that supports syntax colorization. I learned about this library from an article I found on CodeProject. Check here and here. All things related to the world editor are in the files EditorDlg.h and EditorDlg.cpp.

The Embedded Lua

Lua is a very nice programming language. It is a light-weight, small-footprint programming language designed for extending applications. Here, I embedded several C++ functions to Lua by using the Lua script C++ wrapper created by RhicadS.

  • readsensor(integer index) accepts the sensor index; returns the measured distance of the active robot.
  • setspeed(integer left, integer right) accepts the left and right wheel speed of the active robot; returns nothing.
  • getangle() accepts nothing; returns the current angular position of the active robot (in radians).
  • getnumofrobots() accepts nothing; returns number of existing robots.
  • getposition() accepts nothing; returns x and y position of active robot.
  • gettarget(int index) accepts index of target; returns x and y position of selected target.
  • textline(string msg) accepts the message to be displayed; returns nothing.
  • setactiverobot(integer index) activates a certain robot.
  • stepforward() runs simulation one time step.

Basically, those functions are used to manipulate the robot. Lua itself has many internal functions that you can use to develop your algorithm. You can check the Lua reference manual to see the available functions such as: functions for math, string, or file manipulation.

How to Use

You can display the code editor window by clicking View >> Editor, or by clicking View code editor on the toolbar (Ctrl+E). A world file is saved with a *.wld extension, while the code file is saved with a *.lua extension. Loading and saving them are done separately.

Let's give a try. First, draw a big ellipse on the world editor. Then, draw another smaller ellipse inside the first ellipse (or you can load file doubled_wall.wld). Drag the robot inside the alley made by these two ellipses. Load the code editor and paste the following code. Run the simulation. When the robot disappears, click the menu Robot >> Reset Position.

function azolla.main(azolla)
    azolla:setspeed(20,20)
    while true do
        a = azolla:readsensor(1)
        b = azolla:readsensor(5)
        if (a - b > 2) then
            azolla:setspeed(30,20)
        end

        if (a - b < -2) then
            azolla:setspeed(20,30)
        end

        if( (a - b > -2)  and (a - b < 2) ) then
            azolla:setspeed(20,20)
        end
        azolla:stepforward()
    end
end

The above code is to make the robot move forward following the wall. See how it reads the sensor value. There are six sensors in the robot (by default). You can modify the number of sensors using the menu Robot >> Set properties. They are all laser beam type distance. As we know, there are also sonar type distance sensors. Take a look at the picture. Sensor numbering starts from the robot head, and the index increases in the clockwise direction.

Image 6

Let's try another. Within the demo, I included two files trinity.wrl and trinity.lua. Load the two files. Copy and paste the following code:

function azolla.main(azolla)
    azolla:textline("START...\n")
    while(true) do
        for i = 0, azolla:getnumofrobots() - 1 do
            azolla:setactiverobot(i)
            front = azolla:readsensor(0)
            left = azolla:readsensor(5)
            right = azolla:readsensor(1)

            if (front < 10) then
                azolla:setspeed(4,-4)

            else
                delta = 0.5 * (right - left)
                azolla:setspeed(4 + delta,4 - delta)
            end
        end
    azolla:stepforward()
    end
end

Let's take a closer look. function azolla.main(azolla) will always be first called. It's the main function. The function is always written with something like this: function azolla.function_name(azolla)<function_name(parameter_if_exist)>< />. In the code above, the robot will travel around the maze using simple P(proportional) algorithm. The robot will read input from left and right sensor. Control signal (delta) will be calculated based on the difference between left and right sensor value. This control signal will be used to correct the speed of both wheels.< />

Multiple Robot Simulation

Since version 1.0.2, Azolla now supports multiple robot simulation. We can add several robots and run all of them at the same time. To activate a certain robot, setcativerobot must be used. Take a look at the following code:

function azolla.main(this)
    azolla:setspeed(20,20)
    while true do
        --ACTIVATE THE ROBOT ONE BY ONE!!!
        for i = 0, azolla:getnumofrobot() - 1 do
            --This part is for wall following
            azolla:setactiverobot(i)
            a = azolla:readsensor(1)
            b = azolla:readsensor(5)
    
            if (a - b > 2) then
                azolla:setspeed(30,20)
            end
    
            if (a - b < -2) then
                azolla:setspeed(20,30)
            end

            if( (a - b > -2)  and (a - b < 2) ) then
                azolla:setspeed(20,20)
            end
        end
        azolla:stepforward()
    end
end

The above code is to control several robots so that those robots will move forward following walls in left and right side. It is the same as the first example (doubled_wall.wld). We can use the same code for wall following part. As we can see, before moving the robot, we should decide which robot we want to move. We can do iteration to move all the robots sequentially.

Limitations

Azolla is not a real time robot simulator. If we add more and more robots, the simulation will run slower. To make simulation faster, we can increase time step for simulation.

While for sensor reading, it is based on pixel reading of the screen. In this case, we must make sure that the simulation is run in the area of the main window. If the robot goes out of the main window, the sensor algorithm will read the wrong screen pixels. And also, if we have another window on top of the main window and that window can be reached by sensor of the robot, the sensor algorithm will also read the wrong screen pixels. For the next release, I plan to implement geometrical method for sensor instead of reading screen pixel values.

Points of Interest

I really hope you try this simulation software. There have been plenty of improvements I made since the first release. Previously, the simulation didn't work in a multi-core computer. That bug has been fixed. Excessive CPU usage issue has also been fixed. Overall, I can say it works very nicely. I hope you like it and it is helpful for you. You can read the History section to see the details of the improvements made. For further information, please take a look at the provided PDF file.

References

Future Work

For future work, I want to make this simulation software more reliable so it can be used for study and research purposes in the area of mobile robots. To reach that goal, there are many things that need to be done.

History

  • 1.0.0 February, 2009
    • Initial post
  • 1.0.0 March, 2009
    • Article updated
    • Minor bug fixes
  • 1.0.1 February, 2010
    • Article updated
    • Name changed to Azolla
    • Data type for simulation is changed from double to float
    • Fixed: Wrong kinematic equation, causing strange robot motion
    • Fixed: Bug on multithreading, causing excessive CPU usage, and simulation doesn't work on multi-core CPUs
    • Added: User can show/hide robot trail
    • Added: User can show/hide grid in world editor
    • Added: Sonar type sensor
    • Added: User can modify maximum, minimum, and cone angle of the sonar sensors (if zero is selected for the cone angle, the sensors will become laser-beam type sensors)
    • Added: User can apply Gaussian noise on sensor readings
    • Added: User can modify time step for simulation
    • Added: Auto completion in code editor
    • Added: "Find next" in code editor
    • Added: "Select all" in world editor
  • 1.0.2 February, 2010
    • Article updated
    • Fixed: Kinematic equation runs much faster
    • Fixed: Robot's front side looks better
    • Fixed: Glitch appears while running simulation
    • Added: Support for multiple robot simulation
    • Added: More icons on toolbar
  • 1.03 March, 2010
    • Fixed: Bug when showing trajectory
    • Added: Zoom in and zoom out function
    • Added: A color can be assigned to each robot
    • Added: Simple collision detection
    • Many other bug fixes and feature enhancements
  • 1.04 July 2010
    • Added: Log window and target mark
    • Added: Several new commands
    • Sensors now work using geometrical methods such as: intersection of line to line, line to rectangle and line to ellipse
    • Better collision detection
    • More informative error message
    • Many other bug fixes and feature enhancements

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication