Skip to content
Steven Cozart edited this page Jun 1, 2021 · 77 revisions

Project Goal

Displaying a visual diagram (or legend) of how the in-game actions of the currently selected game are mapped to the hardware controls (buttons, joysticks, trackballs, spinners, etc) on my control panel.
Asteroids

Note: Although this project is intended to display control-map diagrams, it could easily be altered to display a dynamic marquee, box art, flyers, or any number of things. The software doesn't much care what image it's displaying.

Table of Contents

Introduction
Background
Design Decisions
Hardware Summary
Software Summary
Installing the software components
Testing and configuration

Introduction

The inspiration for this project came out of a desire to improve the user friendliness of my RetroPie arcade cabinet.

If you want to get started in retro gaming and are new to RetrioPie, I would encourage anyone to visit http://retropie.org.uk It is an excellent resource.

This project is more advanced, and is not for intended someone new to RetroPie and MAME cabinets. It assumes some basic knowledge of RetroPie, EmulationStation, RetroArch, SSH, and the linux shell. But, if you're building you own multi-player, multi-system gaming cabinet based on RetroPie, then I hope you find this helpful.

Note: This is still a work in progress, but I do have a prototype working.

Background

My cabinet is a two player system, with 1 joystick and 6 action buttons per player, a track-ball in the center, and pinball buttons on the sides. At the heart of my system is a Raspberry Pi 3B.

As you know, virtually every original arcade cabinet had a unique control layout, with different numbers of buttons. MAME cabinets are already a design compromise with buttons going unused in many games. My first step to improve user friendliness was to illuminate only the buttons that are active in any given game. I installed LED buttons, and a 16 channel LED driver from Ultimarc. The software to control the button LEDs is here: Poor-man's LEDBlinky with RetroPie and Pac-Drive. I recommend doing this as a first step before tackling a project like this.

Next, I wanted an easy way to remind myself what buttons cause what action, in any given arcade game. For console games, remembering the button functionality is less of an issue. The original consoles systems have fewer buttons, and one controller layout to deal with. However the project will easily display console diagrams too.

Solving this problem for arcade games on multi-game cabinets was the main inspiration of this project. After posting on the RetroPie forums, I was forwarded to an earlier thread with more-or-less the same objective. https://retropie.org.uk/forum/topic/21464/show-control-panel-layout-before-game-starts-in-retropie-just-like-arcade1up-does This thread has lots of great ideas on how to generate and display the button mapping.

Design Decisions

There are many decisions that need to be made when crafting a solution. In general, you have to choose:

Which controls to display

  • Just the buttons?
  • Joysticks too?
  • Trackballs and spinners?

Where to display the control map

  • Somewhere on a main display screen?
  • On a separate screen?

When to display the control map

  • Persistently, so it is always visible during game play?
  • Visible On-Demand?
  • Temporarily, at the beginning of game play ?

Where to get the control mapping information

  • What format is it in?
  • Since the is no such thing as a standard MAME cabinet layout, what tools are available to generate custom diagrams that match a specific cabinet's control layout?

My personal requirements

Your requirements might be different, and there's many different ways to solve a problem. This is just one such way.

  • I was concerned mostly with labeling the button actions.
  • I wanted the map to be persistent, yet non-intrusive. When the game is active, I want to be able to glance at the control map, and ignore it when I don’t need it.
  • I did not want a “transparent” map to obscure the main game area.

Display Options

  • In order to display a persistent button map on the main screen, and not obscure the game play area, the RetroArch overlay is the only place. While RetroArch can display some generic controls over the game video, I didn't find it useful. And RetroArch does not support multiple layers in overlay/bezel area of the screen.
  • Alternatively, a second, much smaller dedicated LCD screen could be used to display the button map. It would not impact the existing setup or overlay art. Some of the overlays I have collected are very beautiful, designed by much more talented artists than I will ever be. I felt it would be a shame to cover up a portion of their artwork. This is the route I chose.

Hardware Summary

My hardware setup consists of two Raspberry Pi devices, each with their own display. The main rRaspberry Pi (RPi1) runs RetroPie, and drives a 28" HDMI display in my cabinet. The buttonMap display is a 5” LCD display driven by a second Raspberry Pi (RPi2). It’s located under the large HDMI monitor, close to my Player1 controls. Down the road, I might extend the project to include multiple button map displays, one for each player.

(insert picture of final setup)

(insert closeup of button map)

Software Summary

The software consist of three main components

  1. Something to generate a set of button map images
  2. RPi1 must tell RPi2 what game is playing, and
  3. RPi2 must display the appropriate button map.

Initially I thought I could use a single RPi, and have the game run via the HDMI port and also have a static image displayed on the LCD port. However Raspian only has one frame buffer. You can drive the HDMI port, or the LCD port, but not both at the same time. This limtiation is how I arrived at using a second RPi for the button map.

1) Generating a per-game button map image

This section covers the scripts, directories and software the generates a custom diagram that matches the layout of the user's control panel.

  • Some notes on the scriptable image editing program named ImageMagick
  • primary_map.csv A text database, which associates the basename of a rom/game with button labels. Derived from the controls.dat v1.4.1
  • secondary_map.csv Additional button labels. Derived from gamesdatabase.org and arcade-museum.com.
  • custom_map.csv Optional database intended for personal label customization.
  • mame2003-plus.csv A database of parent/clone rom names.
  • button_map.sh A shell script that reads the CSV files, and generate and image.
  • A set of directories/folders were the action takes place.

Directory structure for building button images

  • ./SRC - A ./src directory is provided. It contains a black background image, and small set of arcade button image files, used to compose the final button map image.
  • ./TMP - The ./tmp directory is where all the intermediate images are kept during the compositing steps. Images that do not have corresponding button data end up in here.
  • ./ARCADE - The ./arcade directory is where the final button map images will be placed. Warning: This should not be the same directory where you keep your rom .zip files!
  • ./WHEEL - The ./wheel directory should contain a set of optional game logo images, which can be included the final button map image These logo files are not required, but it goes a long way to make the final image look nice.

button_map.sh

button_map.sh is a BASH shell script that does the all work to generate a custom image. It generates a single image at a time, and the script accepts only one argument. Namely: The basename of the image to be created. Note, this should be the exact same basename as the rom file being selected by EmulationStation.

USAGE
For example, to generate a button map for Asteroids (rom name: ateroid.zip), One issues the command:
./button_map.sh asteroid
Do not include the .zip extension. The generated image is named asteroid.png,and placed in the directory ./arcade directory.

OPERATION

  • The script searches for button label data in the following order 1st:custom_map.csv 2nd:primary_map.csv 3rd:secondary_map.csv data file. The script also determines if a rom is a parent or clone rom. Button labels from the parent are used only when there is no clone-specific button label data.
  • If no data is found, the script generates a place holder image, and leave it in the ./tmp directory.
  • If there is a match, an image is composed. Active buttons will have a green button icon, and inactive ones will have a darkened button icon. The buttons will be labeled with the text found in the _map.csv files.
  • The background image, and all the button icons can be found in the ./src directory. The user can customize these images, or add new buttons icons, as desired, to match your MAME cabinet.
  • The script searches for a logo image in the ./wheel directory. If one is available it will be added to composite image else the rom name is written along the top instead.
  • Finally the image is downsized, and saved to the ./arcade directory.

TIPS AND LIMITATIONS

  • Currently, button_map.sh assumes your control panel has a 2x3 button layout of:
    Y X L
    B A R
  • The script works well in a Mac/OSX, and Linux terminals. NOTE: I have not tested this in Windows..
  • The image composition is all done in high resolution, to retain image quality. Then final image is downsized to 800x480. This is resolution of the dedicated LCD display hardware I’m using my build. If you are using the images as a game launch image, it would make sense to change the resolution to 1920x1080 or whatever to match your display.

custom_map.csv, primary_map.csv, secondary_map.csv

These are a simple text databases which associate the basename of a rom/game with a set button labels for the final button map image. The files are read by button_map.sh, and should contain one line for every file image you want to generate.

  • primary_map.csv Derived from the controls.dat v1.4.1 data. Contains 1062 games.
  • secondary_map.csv An additional 1000 titles not found in primary_map.csv but happened to be individually documented on gamesdabase.org and arcade-museum.com.
  • custom_map.csv Optional database intended for personal label customization.

Each field is separated by a comma. The order of the lables are the standard MAME button order: P1_Button1, P1_Button2, P1_Button3, etc

Example contents of custom_map.csv:
#BASENAME_OF_ROM,Button1,Button1,Button2,Button3,Button,Button4,
default,Y,X,L,B,A,R
asteroid,Hyperspace,,,Thrust,Fire
dkong,Jump

NOTES:

  • The fields may contain spaces or other special characters if desired, just avoid the comma character.
  • It does much matter if the file contains lines you will never use. All lines are ignored except for the one matched.
  • If your game has only one or two buttons, you do not have to specify all field separators.
  • If your game does not use some of the buttons, AND you need to skip over some buttons; put two or more commas next to each other to indicate the unused buttons. Example: asteroid,Hyperspace,,,Thrust,Fire.
  • If you want a to indicate the button is active, but don't want a label, just use whitespace between the commas. Example: dkong, ,
  • The primary and secondary data is kept separate due to the different sources of the data. Perhaps these will be merged in the future.

TIPS

  • It is best to keep the button-action text as short as possible. A single word is preferred. The script will adjust the font size, but the text can get small for lengthy labels.

mame2003-plus.csv

This is a text database the associates parent and clone roms. It is used when a button map image for a clone is desired, but only the parent button label data is available.

ImageMagick

ImageMagic is the scriptable image editor, used to build up the final image, from all the pieces (background image, button images, logo image, and text labels). It's downloadable for various OS's from: https://imagemagick.org

Installing ImageMagic on the Raspberry Pi
sudo apt-get update
sudo apt-get install imagemagick

Installing ImageMagic on the Mac OSX
Follow the instructions at https://www.imagemagick.org/script/download.php
Then edit following line in the findCurrentOSType function, inside the button_map.sh script.
export MAGICK_HOME="$HOME/Documents/Hobby/Arcade/ImageMagick-7.0.8

Notes
This wiki is not intended to be a tutorial on ImageMagic. However I used the following features quite a bit:

  • -gravity ( which is immediately followed by: north, south, east, west, northwest, northeast, southeast, or southwest). -Example: -gravity south This places button image at the bottom center of the background image.
  • -geometry (which is always followed by a pair signed integer numbers, bunched up together form one string).
    Example: -geometry +50+100.
    The pair of signed integers forms an X,Y offset. It moves the image slightly up, down, left or right from the spot that the -gravity switch placed it initially. In the above example, +50 means move the image to the right by 50 pixels, and +100 upwards by 100 pixels. It gets slightly confusing because if you use -gravity north to initially place the image at center-top, then +100 would mean to move the image downwards by 100 pixels!
  • -annotate (which is always followed by a pair signed integer numbers, bunched up together form one string). -annotate does for text strings, what -geometry does for images. It works in conjunction with the -gravity switch to fine tune where the text will end up.

2) Pi-to-Pi communication

Communication between the two RPi's is done by establishing a TCPIP socket between the two computers. Instructions are sent by a client running the main raspberry pi (RPi1) to a server running on the second raspberry pi (RPi2). The server listens for socket connections, interprets the instructions, takes some action, and sends an acknowledge message back to the client. Note all communication is initiated by the client. The server only responds to the message, and takes some action.

The client is a Python script named: simpleClinet.py, which runs on RPi1
The server is a Python script named: simpleServer.py, which runs on RPi2

I use python3, however I believe the scripts also work with python2.7

Valid client instructions

  • "GET" - Used for testing. The sever will send a response back the the client "Yo, What's up".
  • "REPEAT some string of text" - Used for testing. The server will strip the keyword REPEAT, and echo the string that was sent.
  • "PATH subdirectory rom_basename" - Used for testing. Returns the full pathname of the image file residing on the server. Note this command does not display the image.
  • "OPEN subdirectory rom_basename" - This command instructs the server on RPi2 to display the image file returned by the PATH keyword.
  • "CLOSE" - This command instucts the server to kill the linux process that is currently displaying an image, but leave the server running.
  • "KILL" - Instruct the server process to terminate.

3) Display the corresponding button map

Image hierarchy

Emulation Station establishes an organized directory hierarchy for storing and accessing rom files. This project follows a similar directory structure for storing the control-map diagrams.

Namely: button map_root_directory / subdirectory / rom_basename+image_suffix

For Example: The rom being selected by EmulationStation on RPi1:
/home/pi/RetroPie/roms/arcade/pacman.zip
Corresponds to the control diagram image on RPi2:
/home/pi/button_map/arcade/pacman.png

  • The default button map_root_directory is /home/pi/button_map. If a different directory is desired, edit the image_dir variable near the top of the simpleServer.py file.
  • The subdirectory will be determined by EmulationStation. ES passes the system directory name to the run_command-onstart.sh script. The the subdirectory name is passed to client and finally to the server. Note: You must use the same directory structure on the server/RPi2 for images, as the client/RPi1 uses for roms, else the desired image won't be found.
  • The rom_basename is handled similarly to the subdirectory. ES passes the rom file name to run_command-onstart.sh where the suffix (.zip, .7x, etc.) is stripped off, leaving only the basename of the rom. The rom's basename is passed to client and finally to the server. Note: The image file on the server must have the exact same basename as the rom, else the desired image won't be found.
  • The default image_suffix is .png. However the user can change this by editing the image_type variable near the top of the simpleServer.py script. Other common extensions might be: .jpg, or -image.jpg

Image selection rules

If the corresponding image file is not found, the server program will look for alternative images to use. Here are the search rules:

  • If the rom-specific image is not found, look file an image file with the basename "default", inside the same subdirectory. Example: /home/pi/button_map/arcade/default.png This is convenient for console systems like Nintendo, Sega Genesis, etc. or the MAME defaults.
  • If the system default image is not found, look file an image file with the basename "default", inside the "button map_root_directory" folder. Example: /home/pi/button_map/default.png This is convenient for the generic RetroArch button names: A, B, X, Y, L, R etc.
  • If that file is not found, I have selected a generic image that should be on everyone's raspberry pi.
  • If none of the above is found, send a garbage string. Currently, this crashes the server process. I could use suggestion on how to make how to make this more stable.

Finally: Upon the ending a game, the client instructs the server to display the EmulationStation button mapping. The file must reside in the "all" subdirectory, and have a basename of "emulation_station". For Example: /home/pi/button_map/all/emulation_station.png

Installing the software components

  • First, get a copy of the project files. From the [Code] tab at the top of this page, Click on the green [Clone or Download] button, select [Download ZIP].
    download
  • Unpack this file somewhere on your computer.
  • Next, Download/Install ImageMagick. See ImageMagick section above.

Preparing to create images

The rest this section assume you will building the images right on the raspberry pi. If you are doing is elsewhere you need to adjust where the files go.

  1. If you do not already have a /home/pi/bin directory, create one:
    mkdir /home/pi/bin
  2. Copy the image building shell scripts to your /home/pi/bin directory, and make them executable:
    cp button_map.sh /home/pi/bin/.
    cp for_all_roms.sh /home/pi/bin/.
    chmod +x /home/pi/bin/button_map.sh
    chmod +x /home/pi/bin/for_all_roms.sh
  3. Create a working directory for image building:
    mkdir /home/pi/button_images
  4. Copy the source images to your working area:
    cp -r src /home/pi/button_images/.
  5. Copy the database files to your working area:
    cp *.csv /home/pi/button_images/.
  6. Create a temporary and an output directory for generated images:
    mkdir /home/pi/button_images/arcade
    mkdir /home/pi/button_images/tmp
  7. Build your first image:
    /home/pi/bin/button_map.sh 88games
  8. See the Testing and configuration section below.

For users interested only in image creation:

You may ignore or delete the following files:

  • simpleServer.py and simpleClient.py
  • run_command_on-start, run_command-onend.sh

For users who want the images to display on a separate raspberry pi

On the secondary RPi

  1. Install FBI. This is a comamnd line utility that display images to the raspberry pi's frame buffer.
    sudo apt-get update
    sudo apt-get install fbi
  2. Copy the images files to /home/pi/button_images/arcade
  3. Copy the server Python script to /home/pi/bin/simpleServer.py
  4. Start the server as a background process
    cd /home/pi/bin
    python3 ./simpleServer.py >> /dev/null &
    exit

On the primary RPi

  1. Copy the client Python script to /home/pi/bin/simpleClient.py
  2. Check to see if the run_comand files already exist:
    ls /opt/retropie/configs/all/run_command-on*.sh
  3. If they already exist, you will have to edit them and append commands inside my versions.
  4. Else copy both files files to /opt/retropie/configs/all/. Emulation Station will execute these scripts just prior to launching a game, and just after exiting a game.

(how to set up a daemon on RPi2 to auto-run the server)

Testing and configuration

Font issues

Once you have ImageMagick installed, its a good idea see what fonts are available on you system. Here are the commands:
convert -list font (Linux)
magick convert -list font (OSX)

Database issues

The primary and secondary map files containing button labels for over 2100 titles. If anyone knows of a better, more-official, more-complete database of button label information, please let me know. On my To-Do list is porting the data from lr-mame2003-plus project (instead of controls.dat, which has not been updated since ~2011).

Wheel data

You have to supply your own source of wheel data. I've included couple examples to illustrate how it works. If all your image files don't have wheel/logo art, this is why. Check/edit the LOGO_DIR pathname in the script.

The buttons locations don't match my cabinet

This has to be configured as best you can inside the script. Out-of-the-box, the mapping is like this:

MAME   RetroPad  CntrPnl
123  -->  YXL -->  123
456  -->  BAR -->  456

If your RetroPie and controls panel setup is different, you will have to edit one or more of the following functions in the code:

map_buttons_retro_pad ()
map_buttons_control_panel_6btn ()
gen_rom_button_map () 

Future support will include option for FBAlpha's button mapping,
and lr-mame2003-plus's 8-button & Modern FightStick layouts.

FBA    RetroPad  CntrPnl  
456  -->  YXL -->  123  
123  -->  BAR -->  456  

Modern   RetroPad       CntrPnl  
1237 --> Y X R  L  -->  1 2 3 4  
4568 --> B A R2 L2 -->  5 6 7 8  

8button  RetroPad       CntrPnl
1237 --> Y X L  R  -->  1 2 3 4
4568 --> B A L2 R2 -->  5 6 7 8 

(testing tips)