It’s been a year since my last article; shame on me as I’ve been busy working on some cool work and personal projects. I’m renewing my writing with this introduction to robot (bot) racing with The Open Race Car Simulator (TORCS) and how I developed a Node.js racing bot that uses a pure pursuit steering steering controller. If you want to jump ahead to the code here’s a link to the torc-node-client github repo.
To see this bot racing in action, here’s a short 2 min video of my pure pursuit bot on the TORCS Aalborg track.
About TORCS and Robot Racing
The Open Race Car Simulator is a 3D graphical race car simulation that has been ported to many OS’es. According to Wikipedia, TORCS has been around in some form dating back to the late ’90s. The simulator includes a number of race tracks and race cars that you can choose to race as well as introduce your own. Cars can be controlled using manual controllers such as as a keyboard, joy stick or steering wheel and autonomously via bot controllers.
I first became interested in developing a racing bot when the Simulated Car Racing Championship (SCR) emerged using TORCS as its simulation environment for racing bots. SCR’s enhances TORCS to participate as a server in a client-server architecture. In this mode TORCS distributes environment data such as individual car sensor data and relative race position to each race bot client process and processes and simulates each bot’s control commands. Racing bots and TORCS interact with one another by sending a well defined set of messages over UDP. The default IP port is 3001.
A TORCS clock tick simulates 20 ms. During a tick, TORCS sends sensor inputs (e.g., current speed and heading, track centerline error, range data, etc.) from each car to the car’s controlling bot and waits 10 ms for the bot to respond with a control message for the car. If a bot fails to reply within the allotted time the server applies the previous command from the bot to its car.
There are several approaches you can take for installing TORCS with the SCR enhancement (aka patch). The SCR manual provides installation and configuration instructions which I had success with an early version of TORCS 1.3 on Windows. More recently I’ve been running TORCS/SCR in a Linux VM in Virtual Box using this codebase.
The SCR manual describes two primary messages shared between TORCS and bots. The first is the sensor input message that TORCS sends to each bot describing the state of the bot’s car. The message fields are shown below.
The second message, shown below, is a command message that a bot sends to TORCS to control it’s car as well as a special field requesting the server restart a race.
Lastly, when bot-TORCS communication is established there is a handshake message that the bot sends to start a race. The details for this message and the handshake process are fairly simple and can be found in the torcs-node-client code.
Bot Control Basics
The sensor input message shown above provides a bot with a good perspective of its car’s state relative to the track and other cars competing in a race. The bot feeds the relevant sensor message details to it’s navigation, steering and speed control logic. Based on the bot’s architecture this can be one or more controllers. From the controllers the bot sends a control message to TORCS with the car’s steering angle and throttle, brake and gear settings.
The PurePursuitDriver class consist of 2 controller: a steering controller and a speed controller.
Pure Pursuit Steering Basics
The pure pursuit steering algorithm simulates the way humans drive. It involves looking ahead some distance down the track to a goal point, computes a curve to the goal point and inputs a steering angle that directs the vehicle to the point. The goal point continuously changes as the vehicle moves down the track resulting in the vehicle pursuing it with an ever changing steering angle.
The pure pursuit algorithm consist of the following steps:
- Get vehicle’s current location
- Look ahead and identify a goal point
- Compute a curve and steering angle to the goal point
- Move towards the goal point following the curvature set by the steering angle
- Go to step-2
Pure pursuit steering suffers from 3 common issues. The first is for large look ahead distances the vehicle has a tendency to cut corners. This can be resolved by reducing the lookahead distance. The second issue is the algorithm has a tendency to overshoot and oscillate about the ideal trajectory to the goal point when the lookahead distance is too short. This problem can be reduced by extending the lookahead distance. The last issue is that the algorithm has no knowledge of the vehicle dynamics or the track profile. To address this ad hoc biasing of the algorithm is sometimes employed.
Pure Pursuit Steering For TORCS
In my pure pursuit steering controller the target point is defined by the sensor range data with the greatest distance and its angle relative to the centerline of the car. This target point info, along with an estimated maximum car steering angle, i.e., steering lock, of 21 degrees and a variable bias based on the vehicle’s velocity are used to compute a steering angle that is scaled to a value between [-1,1]. The job of the bias is to prevent the algorithm from commanding a silly action like commanding the car to turn full left while at high speed.
What’s cool about using the greatest sensor range reading is that it serves as a variable lookahead distance. This greatly reduces the main issues of the pure pursuit algorithm with a fixed lookahead distance.
Because pure pursuit does not factor in the lateral track position of the car, the car can drift off the edge of the track resulting in a spin or worse a crash. To avoid such events an additional tweak to the steering angle is applied when the car is close to drifting off the track.
The speed controller uses a simple PD controller that takes a target speed as input and computes an acceleration value. The code for computing the target speed is shown below. Note the braking zone definition. When the car is within a braking zone the target speed is set to the maximum range sensor reading. This relationship holds until the target speed drops below a minimum acceptable speed (DEFAULT_MIN_SPEED). At that point the target speed is set to the DEFAULT_MIN_SPEED. Outside of a braking zone the target speed is always the maximum speed of the car, e.g., 250 kph.
let brakeZone = sensors.maxDistance < sensors.speedX / 1.5; let targetSpeed = brakeZone ? Math.max(DEFAULT_MIN_SPEED, sensors.maxDistance) : DEFAULT_MAX_SPEED;
The PD controller output is converted to accel, brake and gear change commands. For example a positive acceleration value is converted to an accel command between [0,1] and no brake command. For a negative acceleration value only a brake command between [0,1] is sent, i.e., no accel command.
The velocity difference between the average front wheel speed and back wheel speed is used to detect wheel spin or brake lockup. When either case is detected the acceleration and braking are adjusted to reduce and ultimately eliminate the situation.
Vechicle Damage and Auto-Restart
A car sustains damage when it collides with a wall or another vehicle. If a vehicle’s damage level is excessive the car can no longer function and TORCS terminates the car’s operation. The sensor input message sent to each bot includes the damage level of its car. When a car sustains damage that exceeds the maximum allowed damage level then the bot will automatically request TORCS restart the race. The default maximum damage level for all cars is 50. This limit can be adjusted using the commandline argument: damage.
Additionally, the car’s speed is continuously monitored in order to detect when it is stalled or blocked in such a way that prevents it from moving for more than 5 seconds. After 5 seconds of no movement, the car is assumed to be permanently non-raceable and the race is restarted.
Conclusion and Future Plans
I hope this article gets you interested in developing your own TORCS bot. If so, the torcs-node-client codebase provides a good starting point. In addition here’s a cheat sheet that I frequently reference for the primary sensor input and control values.
While the performance of the pure pursuit driver is a big improvement over early bots that I created using line following and PID based controller there is still room for improvement such as:
- Support overtaking other cars
- Improve cornering trajectory planning.
- Optimize speed management.
Until next time, code strong!
- TORCS website: http://torcs.sourceforge.net/index.php
- SCR Manual – https://arxiv.org/pdf/1304.1672.pdf
- SCR code repo – https://sourceforge.net/projects/cig/files/SCR%20Championship/
- TORCS with SCR Patch – https://github.com/fmirus/torcs-1.3.7
- Pure Pursuit Algorithm – https://www.ri.cmu.edu/pub_files/pub3/coulter_r_craig_1992_1/coulter_r_craig_1992_1.pdf
- The message description tables in this article were copied from the SCR manual.
- Martin Lundgren, “Path Tracking for Miniature Robots”