Developing Robotic Behaviors
Developing a robotic behavior often involves activities such as brainstorming, testing, evaluation, innovation, etc. One of the biggest problems associated with such endeavors can be determining why algorithms fail. This article explores these activities while developing and perfecting a simple — yet interesting — behavior using a simulator.
One of the joys of hobby robotics is finding ways to make a robot solve problems and accomplish goals in — at least what appears to be — an intelligent manner. In order to address the development process for a robotic behavior in an article format, we need a problem that is simple enough to be explored in a few pages, yet complex enough to need a trial-and-error approach. After some thought, an appropriate project came to mind.
Assume our robot’s environment is a cluttered room and our goal is to have the robot explore that room in a manner that makes it venture into all areas of the room on a fairly equal basis.
This is a much different behavior than a robot just wondering randomly while avoiding objects.
One easy way of viewing this difference is to utilize a simulation. RobotBASIC will be used since it’s a free language that includes an integrated robot simulator (download from www.RobotBASIC.org).
Figure 1 shows a partial program that moves the simulated robot randomly through a cluttered room.
while not rFeel()
amount = -45+random(90)
dir = -1
dir = 1
Figure 2 shows the environment and the path taken by the robot over a short period of exploration. Of course, since the robot’s behavior is randomized, the path taken will be different each time the program is run.
This example is typical though, in that the robot can easily get stuck in a partially enclosed region of the environment for an extended period of time. Even if the robot escapes (as it finally did in Figure 2), it’s unlikely that the robot will explore all of its environment in any reasonable time.
Simulations are very helpful for developing algorithms. If a real robot was used to perform this procedure, not only would you have to create a suitable test environment, but the time taken for a physical robot to move around can be far longer than a simulated one, which can greatly extend the development process.
The important point though, is that we need a much better algorithm for controlling the robot’s behavior.
Before improving our code, let’s examine the algorithm in the Explore module of Figure 1.
The Explore module consists of an endless loop that moves the robot forward as long as none of the robot’s perimeter proximity sensors (accessed by the simulator’s rFeel function) detect a nearby object.
If something is detected, the robot turns to a random heading between -45° and +45°. While this does move the robot around its environment, the quality of its movements (as we have seen) is not ideal.
Obviously, a totally random movement is not a good choice.
Improving the Original Algorithm
One simple way of improving the algorithm would be to change the size of the random turns the robot makes. This could easily be tested with the simulation to try to find acceptable parameters before testing the program with a real robot.
Unfortunately, even if you find parameters that work reasonably well in one environment, they will probably fail in a different one.
That’s the nice thing about simulation. You can easily test a variety of environments with different parameters to see if you can find something that will always work.
Let’s try to improve on this program using a different approach. Before reading further, consider this problem and think about how you might change the robot’s behavior to get better results.
A Better Algorithm
One option is to create an entirely new algorithm. Instead of just making the robot make completely random turns, we need a way for it to turn to a more reasonable heading. Such a decision could be made in many ways.
One simple idea that might work would be to have the robot look for the largest open area near its current heading.
Before we start developing this algorithm on a simulator, we should consider the real robot we will eventually want to use.
Since we’re using RobotBASIC to develop the algorithm, it makes sense that we use a robot capable of executing the same programs used for the simulator. The RROS Tab on the RobotBASIC webpage offers a free 200 page download to help you build RobotBASIC compatible robots. This topic was also addressed in the January 2018 issue of SERVO in an article titled “RobotBASIC Robots for Beginners.”
Additionally, the March 2018 issue discussed how the Parallax Scribbler S3 could be expanded and controlled with RobotBASIC. For purposes of this article, we will assume the algorithms will eventually be utilized on a Scribbler S3 as shown in Figure 3.
The modified S3 robot utilizes PING))) ranging sensors which have a much wider beam than the simulated IR rangers on the RobotBASIC simulation. In addition, the S3 only has three rFeel sensors compared to five on the simulator.
For these reasons, additional code will be used to make the simulation act more like the S3 to help ensure that the final algorithm developed on the simulation will control the real robot in a similar manner.
Implementing the New Algorithm
Figure 4 shows a new version of the Explore module and the subroutines TurnToOpenArea and FindLeftRightDist. Together, these modules use the ranging sensors to turn the robot either left or right depending on which area appears to be the most open (longest diagonal range reading).
// use only three rFeel Sensors
while not (rFeel()&14)
rTurn 50 // right is more open
rTurn -50 // left is more open
LeftDist = 1000
for a=-35 to -65 step 5
if rRange(a)<LeftDist then LeftDist=rRange(a)
RtDist = 1000
for a=35 to 65 step 5
if rRange(a)<RtDist then RtDist=rRange(a)
Analyzing the Problem
Unfortunately, this algorithm only works for a short period of time before the robot gets stuck as shown in Figure 5. The reason for this problem is easy to find on the simulation by stepping through the code or by having the program display the values of the left and right rangers when the problem occurs.
Doing so reveals that the robot often sticks in a corner when the robot wants to turn towards an open area, when both the left and right ranging distances are small.
We can fix this problem by having the robot turn to a random heading between -90° and +90° whenever the distances detected by both rangers is small (less than 50 in this example). The program should also initiate this random turn about 5% of the time regardless of the sensor readings to further ensure that the robot does not get stuck in an unusual situation.
The code to implement this is shown in the new version of TurnToOpenArea in Figure 6.
// turn away from a
// stuck situation
and RtDist<50) or
until LeftDist>50 or
// right is more open
// left is more open
Unfortunately, even though the new code of Figure 6 prevents the robot from getting stuck, the robot’s movements (see Figure 7) don’t really seem very natural (when comparing them to how a human might move). As you can see from the figure, the robot always moves in a straight line and doesn’t seem to be moving with any real intent.
Creating More Natural Movements
One idea for creating a more natural movement would be to make the robot try to remain in open areas as it moves (not just when it collides with something as in the previous program).
This can be done by having the robot (while moving) constantly check to see if the area is more open to the left or right. This can be done as shown in Figure 8.
// use only three rFeel
while not (rFeel()&14)
The new code in Figure 8 simply checks to see if the range distance to the left or right is larger, and then turns slowly in that direction while still moving forward.
This simple change causes the robot to always turn slightly toward open spaces as shown in Figure 9. This new behavior certainly makes the robot seem to move more intelligently.
Problems Still Exist
Unfortunately, even though the robot of Figure 9 seems to have found its way to all areas of the room (in this running of the program) with more natural-looking movements, the robot gets stuck in a pattern moving between the upper left and lower right corners.
This can be corrected by giving the robot a little curiosity by adding a little randomness to its exploratory movements.
Figure 10 shows a new version of the Explore subroutine that adds such randomness. During normal movement, it causes the robot to turn away from (rather than toward) open spaces 50% of the time.
// use only three rFeel Sensors
while not (rFeel()&14)
// turn away half the time
d = 1
It also turns a random amount as it moves in the exploratory mode. This produces the motion shown in Figure 11.
Overall, the robot now explores all areas of its environment on a fairly equal basis. It does seem to move toward open spaces, but not always. There is just enough randomness to ensure that all areas of the environment are visited.
If a robot used this algorithm to search its environment for a dime on the floor, it could certainly find it (as long as it had sensors that could detect the dime).
A variety of programming changes have shown how a robotic problem can be analyzed and developed using a simulation.
The final program solves the stated problem and can be used to control the Scribbler S3. For information on using the program with the S3, refer to the March 2018 SERVO article mentioned earlier. Readers are encouraged to download RobotBASIC and implement their own ideas to improve upon these algorithms and/or to create and develop robotic behaviors of their own.
Beware, though, a simulator can make testing and developing algorithms for robotic behaviors so fast and easy that you might find it addictive. SV