I am an Engineer. I design Industrial Automation and Control systems. Back in college I had a little free time in my PLC class (PLC stands for Programmable Logic Controller), and my design team and I spitballed a few ideas to gain some extra class credit. One of the ideas we came up with was programming Pong for an HMI (HMI stands for Human-Machine Interface; It's the display for a PLC).
We never got it done. When we did sit back and get to programming we wound up in way over our heads and, frankly, didn't really know what we were doing.
About a year after graduation I was on a commissioning job that was not the busiest. My part of the project was last in line for final checkout and there was plenty of time to kill. I didn't have a wifi hotspot with me so I was stuck for an entire day with no internet and not a whole lot to do. To stay constructive, I fired up my PLC emulator and got to work on building Pong. It wasn't a very productive day, about all I had accomplished (before real work started) was making a few numbers change from negative to positive based on their value. But the ball was rolling.
The idea (and program) stuck with me. And in airports, hotels, and office downtime I slowly but surely honed in on the final product. Along the way, I wrote a quick and dirty HMI to display the thing since FactoryTalk just happened to be installed on my laptop. And just before Christmas 2014, I migrated my program off of the emulator, burned it to an Allen-Bradley CompactLogix PLC, hooked the whole thing up to a PanelView HMI display, and was able to play a fun game of Pong against my coworkers... using code running on an Industrial Automation Controller.
PLC Pong is built in an Allen-Bradley based architecture. The HMI runtime is based in FactoryTalkView ME v5.1 (developed in ME v7.00). The PLC code is written in RSLogix v20.01. All of the code is available below.
The HMI is 'dumb', in that it doesn't do any 'thinking' on its own. All of the gameplay math is done on the PLC. The PanelView app that was written has two main functions: It displays a few shapes' positions based on integer values in the PLC, and it provides the input interface to the PLC program via a keyboard (Analog Input controllers are on the permanent to-do list).
All of the PLC code is written in Ladder Logic. The goal was to keep the code as elegant as I could while keeping the PLC's scan time as quick as possible to ensure smooth gameplay. A quick scan time wound up being a moot point; I did the development with an emulator and the code wound up running at least 10 times slower on the emulator than it did on a real processor. Oh well.
For timing purposes, the routine running the code is periodic, set to repeat at 20ms intervals. This makes porting to other Allen-Bradley platforms (CompactLogix, ControlLogix) easy. I'd like to modify the vector math to handle game timing instead of using this workaround, but I haven't gotten that far (and probably never will).
The game is coordinate- and vector-based.
Short and sweet explanation: Each object on screen has a pair of x and y coordinates stored as integers in the PLC. On each scan of the PLC, depending on conditions, an integer vector (magnitude = value, direction = sign) is added to the objects' coordinates to change them. The HMI then displays these objects' positions via animations based on the coordinates. What results is a pretty fluid animation on the display.
Long and rambling explanation: The coordinate system is arbitrarily sized 800x600 (4:3 ratio) in the PLC program. The three moving things being drawn on the HMI (Left Paddle, Right Paddle, and Ball) are positioned via simple animations based on x and y coordinate values on this abstract 800x600 grid. Each paddle stays stationary along the x-axis and only the y-coordinate is modified. The ball has both an x- and a y-coordinate for movement in two dimensions. The values of the position coordinates are modified on each scan of the PLC program, and the modification value is based on movement vectors.
The magnitude of the vectors is an integer value, and the direction of the vectors is the integer's sign. A positive integer means movement left (x) or up (y). A negative integer means movement right (x) or down (y) On each scan of the program, the vector's magnitude is added or subtracted to the position coordinate to change that object's position. This happens every 20ms in a Periodic Task. The periodic task rate is decremented every time a "volley" happens, and resets to 20ms on a serve. If the ball touches both paddles and a point isn't scored, the period rate decreases to speed the gameplay up. Its a hacked together fix, I know, but until I figure out some hefty vector modification this will have to do.
The paddle vectors are constant, and are applied to the paddle's coordinates on each scan depending on if an up or down command is being sensed. This logic will be useless if Analog control is ever applied. But for now, its how the paddles move up and down the screen.
The ball's vectors are modified depending on if a 'collision' is detected. For instance: the ball colliding with a paddle, or the ball colliding with the top/bottom edges of the 800x600 grid. If one of the ball's coordinate vectors' magnitude is increased, the speed in that direction is increased. If the vector's sign is flipped, the ball changes direction. The vectors' value and sign are modified based on the location of the 'collision' on the Paddle/Grid Edges. A collision on the edge of a paddle will increase its vertical speed much more than a collision in the center. A collision with the center of the paddle will send the ball in a straight horizontal line. There are specific routines to handle the vector modification depending on where these collisions take place. This portion of the code is, by far, the nastiest.
Game Control logic is relatively straightforward. Point-scoring happens if the ball's x-coordinate extends beyond either paddle's fixed x-coordinate. Points are kept track of, when 10 points are scored by either side the game is over and a winner is declared. On a New Game, the scores are set to 0, the ball is put in the center of the screen, and initial vectors are applied to get the ball moving once again.
There is also a single-player mode with a rudimentary AI that automatically modifies the Right Paddle's y-vector based on the ball's position. I've been told that because the AI constantly tries to touch the ball with the edge of its paddle - to send the ball flying towards the opposite direction it came from - it makes the game too hard. It works, though.
Sorry, no link. Neocities will not allow free .zip hosting. Its on the todo list. (.zip containing RSLogix 5000 Program File and readme.txt).
This is the latest version of my PLC Pong program. Version 1.00 was saved with RSLogix5000 v20.01, so you'll need that (or newer) to open it.
Sorry, no link. Neocities will not allow free .zip hosting. Its on the todo list. (.zip containing FactoryTalk View ME Backup, FactoryTalk View ME Runtime,and readme.txt).
This is the latest version of my HMI application for the PLC Pong program above. Version 1.00 was saved with FactoryTalk View Machine Edition v7.00, so you'll need that (or newer) to restore the archive. Also included is a compiled runtime for FactoryTalk View Machine Edition v5.10, since this was the version my test PanelView was (a PanelViewPlus 600). The RSLinx paths in the runtime *probably* won't match anything but my bench setup, but I included it anyway.
I made PLC Pong strictly for my own research and enjoyment, and I am a supporter of open-source software. As such, when I was given permission by my then-employer to release Pong, I did so under the tongue-in-cheek "Beerware" license. Basically, you can do whatever you want with the code. It's yours. All I ask is that the license file accompany the code wherever it goes. It comes with no warranty, expressed or otherwise, and I can take no responsibility for any ill effects that come from using it.
Feel like dropping me a line? Be my guest: steve (at) cton.me
All rights to their respective owners.
Created in 2018 by Steve Acton. No copyrights or trademarks. Use as you wish.
CSS modified from W3.CSS