Motion Detection on Raspberry Pi

One of the most common projects for the Raspberry Pi is a surveillance camera with motion detection. It should be no surprise, then, that there are several application options to choose from. Here are some that I found:

  • Kerberos Motion
  • PiCam
  • Motion – motion packages doesn’t yet work with the Raspberry Pi camera. You’ll instead have to use a special binary, called “motion-mmal”, specially created for the Raspberry Pi by a community member.
  • Motion-mmal
  • MotionEye (or MotionEyeOs)
  • ZoneMinder
  • PiKrellCam

Of these, I found the most positive remarks about PiKrellCam. Motion is probably the most popular, but it’s old, from what I’ve read, and it’s not as efficient as PiKrellCam – it tends to overheat the CPU and drop frames. It does work with USB webcams though, but since I have a Pi camera module, I don’t care. I read also that PiKrellCam takes advantage of some of the features of the Pi camera.

On the down side, PiKrellCam isn’t exactly for newbies. The download, install, and configuration I found to be more complicated than it needs to be.

You can also turn off the camera red LED by adding this line to /boot/config.txt:
Make everything wired. The broadcom wifi chip is too unstable for this. Also if you can, run the master motioneye os on something a bit beefier than an Rpi.
The biggest cause for false positives I found was noise in dark rooms. when an area is well lit with high resolution – I hardly had any false alerts

From a post: “I like MotionEye. Just tried out after seeing this post, and the interface looks really nice, but each instance can only run 1 camera. One installation of MotionEye can view multiple cameras and has more options for connecting to and using them.
Zoneminder is too intensive for the pi I found. I swapped to motioneyeos and never looked back.”

I went with the PiKrellCam.


How to Upload AVI or MP4 Movie Files from Raspberry Pi to Google Drive

This was way harder than it looked. I used the script written by this guy at Jeremy’s Blog. What I like about it is its  simplicity – it uses a single Python script – you don’t have to download a ton of files that you don’t know what they do. You can look at the script and see what it’s doing. The hardest part was getting the Google Authentication, because the instructions on Jeremy’s Blog are WRONG WRONG WRONG. So here’s how to do it, as of today.

Note that this script is designed to be used with the “Motion” security/surveillance module, which I don’t use. I intend to use it with PiKrellCam – hopefully I can get the two working together.

Set Up Google API Authentication

You can use the first part (Step 1) of this guide by Google, or follow along. Since it sounds like Google changes their authentication process every so often, these instructions might go out of date. What you really want is to get Google to set up and generate an authentication JSON file for you to download.

  1. Log in to the Google account that you’re going to use as a repository.
  2. Go to the Google API page.
  3. At the top of the page, click the dropdown and select Create Project. Name the project: Uploader.
  4. Click Dashboard (left menu), if you’re not already on it, and click Enable an API at the top of the page. It will enable the API and automatically send you to the Library tab.
  5. Under Google Apps APIs, click Drive API. The Drive API details displays.
  6. Click the Create credentials button.
  7. Click Client ID, and then click skip this.
  8. Click Configure consent screen.
  9. In the Product name shown to users, enter Uploader. Leave all other fields blank.
  10. Click Save. The Create client Id page displays.
  11. Select/Enter the following:
  12. Application type: Other
  13. Name: Uploader
  14. Click Create. The OAuth client popup displays your authentication details – you don’t need to copy these, but you can if you want.
  15. Close the popup. You will see your API authorization in a list. On the right side of the Uploader line, click the Download icon. It displays a download file dialog box – change the file name to client_secrets.json and put it somewhere like /home/pi/motion-uploader.

OK – that was hard enough. Jeremy’s instructions helped me hobble along, but they were so far off that I blindly felt my way through the process. I hope I captured all the steps, but I might not have. The rest of Jeremy’s instructions are pretty close.

Download Script and Python Client

Go to your home directory.

$ cd /home/pi/

Get the from github.

$ git clone

Update/install Google Python API:

$ sudo pip install --upgrade google-api-python-client
$ cd motion-uploader

Make executable:

$ chmod a+x

Configure Script

If you used the git clone command you’ll find the example uploader.cfg file in the motion-uploader directory. Edit it.

Make sure the folder is set to where you put the client_secrets.json file and where the script has write credentials. I put mine in /home/pi/motion-uploader/.

Under [docs], set the name of the folder on your Google Drive where you want the videos to be saved and where you want photos to be saved. I created a folder in Google Drive called Motion to match this.

$ sudo nano  uploader.cfg

folder = /home/pi/motion-uploader/

# GMail account credentials
name = Joe Shmo
user = joshmo
password = dh4Kfufus0f654qmdk
sender =

# Recipient email address (could be same as from_addr)
recipient =

# Subject line for email
subject = Motion detected

# First line of email message
message = Video uploaded

# Folder (or collection) in Docs where you want the videos to go
folder = motion
snapshot-folder = public

# Delete the local video file after the upload
delete-after-upload = true

# Send an email after the upload
send-email = true

Initial Authentication

You need to be logged in to your Google account for this. So open a browser and log in to the target account. Keep that browser open.

The initial authentication script will look like it failed. Get a test.AVI file from somewhere, or just touch test.avi to create a fake one. I used a renamed JPG I had laying around. Note that it will fail if it isn’t an AVI.

From the command line run the script from the /home/pi/motion-uploader/ directory.

$ cd /home/pi/motion-uploader/
$ ./ /home/pi/uploader.cfg /home/pi/test.avi

A bloody error message displays some text about copying a URL. DO THAT. It also says: enter the Auth Code or something like that. Copy the URL in the error message, and paste it into the browser where you are already logged in to Google as the correct user. A web page displays two lines of text – the second line is the authentication code. Copy that code, go back to your terminal, and paste the auth code – press Enter. It will be happy.

This will authenticate you and create a credentials file which will be used for future logins (uploader_credentials.txt).

For me, it failed the first time, because I tried uploading a file that was NOT an AVI. But when I ran it the second time, with an AVI, it worked – and it didn’t ask for credentials.

Does It Upload MP4s?

But YES! The hippopotamus!

./ /home/pi/motion-uploader/uploader.cfg _

Well, that’s a relief. I was expecting to have to modify the Python to allow it. Fortunately, video files all have some level of similarity – it can use the AVI MIME type for MP4s.

Next Steps

Add the upload script to the PiKrellCam script to upload after a movie file is created. Or maybe, since PKC sends me a photo of the relevant video, I don’t want it to upload the video. I would rather have a manual step there.

  1. Motion detected.
  2. Movie captured, photo emailed to me.
  3. I view the photo – if it’s a bird, I don’t do anything. If it’s a bad guy, I send a command to upload the movie to Google Drive.

I’ve been considering a way to send commands to the Pi without opening up a port to my home network. I have an idea where I set a cron job on the Pi to monitor a text file on my web server (read txt every minute). The file is writeable by me and is empty by default. I can write a PHP script to add a command to the text file. When the Pi detects a command, it kicks off a process. For example, after I get a suspicious photo as an email attachment:

  1. Go to my PHP page.
  2. Enter upvid, which adds “upvid” to my text file (or maybe just the name of the file, like manual_2017-03-25_10.10.55_0).
  3. Pi reads that there’s a command in the text file, and logs that it read it (so it doesn’t execute it twice).
  4. Pi runs the script and uploads the file to Google Drive.

I think it will work.

Copied from Jeremy’s Blog:

Motion comes with a feature to periodically take a snapshot regardless of whether motion has been detected. This is a nice feature if you want to have a web site with the latest view from your webcam. You can use Google Drive to host this image rather than installing a web server on your Pi and opening firewalls etc.

  1. Create a public folder in your Google Drive:
    • Create a new folder called ‘public’
    • Double click on it
    • Go to the sharing menu (person icon with + sign)
    • Click “Advanced” and then “Change…”
    • Set it to “On – Public on the Web”
  2. Configure your uploader.cfg so docs/snapshot-folder is set to this folder ‘public’.
  3. Configure motion.conf to take a snapshot every n seconds named lastsnap.jpg and upload it:
    • snapshot_interval 300
    • snapshot_filename lastsnap
    • on_picture_save /home/pi/motion-uploader/ /home/pi/uploader.cfg %f snap

To find the public URL that you can bookmark and embed in other pages run the command line with the ‘snapurl’ option:

./ /home/pi/uploader.cfg /home/pi/lastsnap.jpg snapurl

It will print something like this:

Scripts and Methods to Upload Files to Google Drive from Raspberry Pi

[UPDATE] After considering all the options below, I went for Jeremy’s Python Script. It looked like the simplest method – if it worked (and it did!). Here are the detailed instructions I wrote for getting it to work. Jeremy’s Blog got the Google Authentication steps wrong, because Google changes their processes without notice.

So Many Options

There are some options to consider. One is Grive, which, if you believe the Internet, doesn’t work anymore.

However: “There was previously an open-source command-line tool named Grive and a graphical counterpart named Grive Tools. However, Grive has been abandoned and is no longer functional due to changes in the Google Drive API. Instead of updating the old open-souce application, the developers created a new application named overGrive and are selling it for $5” (HowToGeek).

A Command-line Tool by a Google Drive Developer, “Drive”

If you’re more of a Terminal geek, “drive” is a small command line program that runs on both Linux and macOS. It’s open-source and written in Google’s “Go” programming language. You need to install the GO programming language. This program was originally written by Burcu Dogan, aka rakyll, a Google employee who has worked for Google Drive’s platform team. It’s even copyrighted by Google.


This one is a contender. Synchronizes a directory between the Pi and Google Drive. So if you delete a file from one, it will delete from the other, etc. You can’t independently upload/download.

Motion Google Drive Uploader

This one looks promising. It’s a python script that was written for Motion.


I’m a little skeptical of thise, due to the amount of setup it requires and that you need to refer to a .ru site for information.


A paid application. $5.

Upload Idea

I can create a file on my web server that I can write to via PHP. Have the Raspberry Pi monitor that file for content, and if it finds content, execute a BASH script.

For example, I write to my file at, and I add “uphoto” to that text file. The Ra spi reads that file, and if it has “uphoto” in it, it executes a BASH script to upload the contents of a photo directory to Google Drive. I then overwrite commands.txt with “dphoto” that tells the Raspi to delete all the photos.


PiKrellCam at RaspberryPi Forum

PiKrellCam at GitHub

Reducing Power Consumption

This is a work in progress. There’s not much “easy” about PiKrellCam.

Pseudo code for a Python script to watch for external commands, then execute them.

while true
    pause for 5min
    go read the text file
    set setEmail = n
    if text file line says "emailme" and sentEmail != y
        send email
        set sentEmail = y
    if text file line says "delsent" and sentEmail == y
        set sentEmail = n
end while

Start PiKrellCam from command line:

$ cd pikrellcam
$ pikrellcam  motion_enable on &

Use ampersand to get back to the prompt.

Create a shell script to delay start.

$ sudo nano

sleep 3m
/home/pi/pikrellcam/pikrellcam motion_enable on



I installed PiKrellCam last night, and it didn’t exactly go smoothly. It would help if I read through the 1000+ posts on the Pi Forum, but I didn’t have the patience. Instead, I followed the directions from the PiKrellCam Git Page, which says:

$ cd /home/pi
$ git clone
$ cd pikrellcam
$ ./

Note that this will only work if you’re logged in as user: pi. It seems that the installer is configured for only a very specific circumstance, so don’t expect to install it somewhere else or use a different user. This may no longer be the case, according to later forum posts, but if you want the simplest installation, use the pi account.

At first, I wanted to download the file to my ~/Downloads directory, so that’s what I did. The problem is that when I installed it, it installed to that same directory, which is probably why it failed.

During the install, I specified a unique port and created a password. The install seemed to go well, but when I accessed the web page, it displayed: “No preview jpeg”. I tried starting the service using the Start button, but it didn’t do anything.

So then I followed the install directions exactly (logged in as pi and at /home/pi/), and it still didn’t work right at first. At the web page, it refreshed about three times per second and still did nothing – just jumped and jittered. I tried clicking the Start button – actually I started clicking all the buttons, but it was unresponsive. Then after a few minutes, I got an error page saying that my camera was being used by another application (no it wasn’t). (In retrospect, I think I probably clicked the Start button and didn’t wait long enough for it to engage.)

I rebooted and tried the web page again. This time, it displayed the preview and worked! Yay? I don’t like it when things break then just work.

To provide context, I was doing all this while being constantly interrupted by family. I suggest doing this in a quiet, secluded area when you have plenty of time to troubleshoot.

Questions I had/still have:

  • Where are the web pages stored?
    • ~/pikrellcam/www/
  • Does the install also install NGINX? or was it already there?
  • Is PHP installed already? I need to check.
  • How do I uninstall it?
  • How do I update it? – There’s an Update button on the web page.
  • How do you know what applications are installed, like mpack, ssmtp, php?


The application pages are written in PHP and JQuery.

I’m playing with it now. Let me say that the Motion Regions function is extremely useful. To view the saved motion regions, click List. By default, you will see only “default” that’s all there is.

To toggle the motion regions off, click Preset.

The documentation says to edit the ~/pikrellcam/pikrellcam.config file to add your email address, but there’s more to it than that. You need to first install SSMTP.

Change the Default File Save Location

Because PiKrellCam is going to write to a drive a lot, you will want to set up an alternate location for it. You want your OS micro SD card to last as long as possible, so you want to read and write to it as infrequently as possible.


Go get ourself a good-sized USB drive. I used a 16GB Sandisk.

From your Pi home directory:

$ cd .pikrellcam
$ sudo nano pikrellcam.conf

Search for the media_dir line and change it to a location on your USB drive.

media_dir /media/pi/SANDISK-16/PKC

When PiKrellCam first writes to that location, it creates a file structure:


Don’t forget to add an entry for your new USB drive in the Samba config file.

$ sudo nano /etc/samba/smb.conf
$ sudo /etc/init.d/samba restart


Notes from the Raspberry Pi Forum

To view errors:

Changing saturation on the NoIR, edit at-commands.conf and add in:
daily sunrise-5 “@saturation 99”
daily sunset+5 “@saturation -99”

I’ve only been able to get improvement by setting the video fps low at night (around 6 fps)

Those that want to change frame fps at night can put lines like this in ~/.pikrellcam/at-commands.conf:
# sunrise/sunset or dawn/dusk (times are reported in the log file)
# Motion is detected and preview updated at video_fps/mjpeg_divider so
# mjpeg_divider should be changed when video_fps is changed. Also change
# video_mp4_box to track video_fps or mp4 will be slow or fast motion.
# Adjust camera parameters in the evening: sunset{+-offset}
daily sunset “@exposure_mode night”
daily sunset+10 “@video_fps 4”
daily sunset+10 “@video_mp4box_fps 4”
daily sunset+10 “@mjpeg_divider 1”

# Adjust camera parameters in the morning sunrise{+-offset}
daily sunrise-10 “@video_fps 24”
daily sunrise-10 “@video_mp4box_fps 24”
daily sunrise-10 “@mjpeg_divider 4”
daily sunrise “@exposure_mode auto”

I do have it succesfully emailing me via the preview save script????

This doesn’t work – I tried to edit the pikrellcam.conf file and set media_dir to
media_dir /mnt/cam
A: can you check the symlink under /home/pi/pikrellcam/www – you should find media -> /mnt/cam
A: check to make sure you have write permissions.

After a reboot I have no preview of the camera in the webinterface
A: Go to the web UI System and push the Start button

To update:
cd ~/pikrellcam
git pull origin

Or just use the Update button on the web page.

If you ever run git and get an error like:
$ git pull origin
Updating e78deba..a6929d1
error: Your local changes to the following files would be overwritten by merge:
Please, commit your changes or stash them before you can merge.
Just delete www/index.php and www/media.php and run again: git pull origin.
Any change to a file made in ~/.pikrellcam will not be overwritten by an update.
Likewise, any edit or adding of a file in pikrellcam/scripts will not be overwritten.
Worst case would be you have to clean up and start over with a git clone. Every config file in ~/.pikrellcam/ will be safe and you can leave them alone if you have to do a new git clone.

How to kill
killall -9 pikrellcam

Email uses “mpack” an email application. To get the emailing you have to edit preview-save in the scripts directory and not the one in the scripts-dist directory. In the preview-save script uncomment the two lines:
mpack -s pikrellcam@$HOSTNAME $PREVIEW_JPEG $MY_EMAIL
echo “mpack -s pikrellcam@$HOSTNAME $PREVIEW_JPEG $MY_EMAIL” >> $LOG_FILE

and make sure the MY_EMAIL line has your correct email address. Finally, in pikrellcam.conf, this line must be set and not commented out:
on_motion_preview_save $C/preview-save $F $m $P $G

In case you want to save just the still image instead of the video to a remote site, you can do something like this:


# construct still filename from video filename
F=$(basename $VIDEO_FILE .mp4).jpg
curl -T /home/pi/pikrellcam/media/stills/$F$F –user USERNAME:PASSWORD

Parameters for motion_vectors_dimming and motion_area_min_side
The dimming is the percent to dim the jpeg stream when the show of motion vectors is enabled. If you want more contrast between the image and drawn motion vector squares, set the dimming lower. Set it higher if you want to see the image better, but less contrast is available for the vectors.

If motion vector count limit is set low, the size of the detected object can be very small and the blow up of that detected area for a thumb can be grainy or even missed since there can be some skew. Setting a minimum to the motion area side compensates for that. The units of the minimum is pixels.

Neither of these affect actual motion detection.

Web page password protection is now changed to use htpasswd.

Labels: Turn ON: Setup->Motion->Settings->Preview_Clean

Now there is a git “Upgrade” button on the web page for one click upgrades.

To directly email the still, you can use mpack like so ($s is last saved still):
on_still_capture mpack -s pikrellcam-still@$H $s

The media_dir is configured in ~/.pikrellcam/pikrellcam.conf and you can have an automatic mount enabled in ~/pikrellcam/scripts/startup
For my setups, I leave the .pikrellcam.conf media_dir at its default of “media” and I edit the startup
script so that MOUNT_DISK=sda1
I have a USB stick plugged in which appears as /dev/sda so the startup script mounts /dev/sda1 on ~/pikrellcam/media and so all my video files are stored on the USB stick.

# crontab file
0 0 * * * find /home/pi/pikrellcam/media/archive -mtime +7 -exec rm {} \;

Recommended for low light (added these lines at at-commands.conf):
daily dusk “@brightness 50”
daily dusk “@video_fps 4”
daily dusk “@mjpeg_divider 1”
daily dusk “@mp4_box_fps 4”
daily dusk “@exposure_mode night”
daily sunrise “@brightness 50”
daily sunrise “@video_fps 24”
daily sunrise “@mjpeg_divider 6”
daily sunrise “@exposure_mode auto”


On and off at terminal ?:
echo ‘motion_enable on’ >> /home/pi/pikrellcam/www/FIFO
echo ‘motion_enable off’ >> /home/pi/pikrellcam/www/FIFO

Some thoughts about security:
1. the .htpasswd shouldn’t reside inside the www root
auth_basic_user_file /home/pi/pikrellcam/www/.htpasswd;

2. the access to the .htpasswd should be denied by nginx configuration:
# deny access to .ht* files, if Apache’s document root
# concurs with nginx’s one
location ~ /\.ht {
deny all;


echo motion limits 12 12 > ~/pikrellcam/www/FIFO
echo motion burst 500 4 > ~/pikrellcam/www/FIFO

#If you want to configure a custom motions regions also:
#echo motion load_regions windy > ~/pikrellcam/www/FIFO

And when the weather gets back to normal, run something like this:

echo motion limits 5 4 > ~/pikrellcam/www/FIFO
echo motion burst 200 3 > ~/pikrellcam/www/FIFO
#echo motion load_regions default > ~/pikrellcam/www/FIFO

I have a python program which monitors a sensor and then calls a shell script which does:
echo “still” > /home/pi/pikrellcam/www/FIFO
echo “record on 4 4” > /home/pi/pikrellcam/www/FIFO

so I get a still image as well as a video showing before and after the trigger. There is about a half-second gap in the video right at the trigger, as the camera changes modes for the full-res still frame, but I think that’s a limitation of the GPU firmware and nothing to do with PiKrellCam.

jbeale’s complete pikrellcam.conf file:

Archive script
and a later version:

Mount windows drive

How to change media location

I’m not sure about mpack usage of port 25, but /etc/ssmtp/ssmtp.conf needs to be setup to send to a mailhub that works with mpack.

If the mounting is done by pikrellcam by editing the ~/pikrellcam/scripts/startup script or by however you are doing the mounting, a umask should be specified for the mount.

For example, if you want pikrellcam to do the mounting of a FAT32 filesystem on /dev/sda1, uncomment the MOUNT_DISK=sda1 line in the startup script and change this line:


sudo mount -t vfat $DISK_DEVICE $MEDIA_DIR -o rw,user,umask=0002

Otherwise, however you are mounting the nas, you need the umask to be set.

Check if pikrellcam is running:
ps -e | grep pikrellcam

Check nginx:
sudo service nginx status

nginx.conf is now in /etc/nginx/

There are many ways to do this. What I do is have the Pi save files on the SD card short-term, then at some schedule (hourly, daily…) I use ‘rsync’ to copy the local Pi files to the remote server (could be another Pi or any other machine). Then I have separate ‘cron’ jobs on each machine that delete the oldest files to maintain a certain % disk usage or certain number of days. This is standard Unix/Linux file stuff, nothing specific to RPi. For example usage of ‘rsync’ try … d-examples or some other pages google will show.

The only trick here is that you need to set up the Pi to be able to ssh into the remote server without using a password, but that is easy to set up as explained here: … h-copy-id/

on_motion_begin $C/motion_send_alarm

What do you have configured for media_dir and archive_dir in pikrellcam.conf?
It looks like you should have:
media_dir /home/pi/shared/mount/pikrellcam/media
archive_dir /home/pi/shared/mount/pikrellcam/archive

The pikrellcam.conf values force the www directory links and manually changing them will not work. Pikrellcam tries to mount only if the MOUNT_DISK line in scripts/startup is uncommented.

Test www-data read/write access. Log in as root, then:
runuser -u www-data touch /home/pi/NAS/pikrellcam/media/testfile

add your NFS shares as
192.168.nfs.nfs:/shared /shared nfs defaults,noatime,x-systemd.automount 0 0

When I tried command line mpack it failed because ssmtp was not installed on this Pi.
A: ssmtp is just one way of configuring email sending in the console. There are other possible software like exim4 or postfix but i think ssmtp is a very easy way.

Make sure you are using an adequate power supply and a good USB cable

If you are running headless and don’t need the HDMI circuitry powered up, you can reallocate about 30mA to other resources by adding this line to your /etc/rc.local file:
/usr/bin/tvservice -o

You can also gain another 10mA by disabling the PIs power and act LEDs by adding the following to your /boot/config.txt file
# Disable the ACT LED.

# Disable the PWR LED.

Also disable the sound in your /boot/config.txt file since you aren’t really using it and it just uses more power and memory that the pi can use elsewhere.

After running several PiKrellCam devices for more than a year (starting when it was released in July 2015) I have come to the conclusion that flash memory (both microSD card, and USB stick) will likely become unreliable and fail after about a year of regular use recording motion video clips.

I moved /tmp and /var/log to a ramdisk because these are the most frequent written directories for the native linux system.

How to set these to RAM disk:

PiKrellCam will randomly spring into life for a while then stop
A: Could be inadequate power source.



Secure the Raspberry Pi

Install Fail2Ban

Fail2Ban prevents brute-force attacks against your SSH port, so a script can’t try a zillion username/password combinations – they can only try 3 at a time before being banned.

$ sudo apt-get update
$ sudo apt-get install fail2ban

The initial settings are located at /etc/fail2ban/jail.conf. However do not edit any of these settings in your /etc/fail2ban/jail.conf file. Instead, edit the /etc/fail2ban/jail.local file and add your configurations there.

Create a new file, /etc/fail2ban/jail.local:

$ sudo nano /etc/fail2ban/jail.local

And add the following:

enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
bantime = 900
banaction = iptables-allports
findtime = 900
maxretry = 3

It’s enabled. It’s watching the SSH port. Ban time is 15min. Three tries.

Restart the service:

$ sudo service fail2ban restart

At this point Fail2Ban is configured. Note that all bans will be cleared upon restarting Fail2Ban or rebooting your server. If you ban yourself, you can simply restart your Raspberry Pi.

You can check your IPTables list with the following command to see all your banned IP Addresses:

$ sudo iptables -L -n --line

Compile MAME

This is the tutorial I used to compile. I compiled it primarily to remove the nag screens. Below is a re-creation of that tutorial, in case it gets wiped.

This is to compile MAME starting with version 0.155 through 0.158.

Build the MinGW compiling environment

Download the appropriate compiling package of files from the MAMEDev webpage under the Easy Way section.

  • mingw-mame-w64-20140905.exe if you are running a 64-bit version of Windows
  • mingw-mame-w32-20140905.exe if you are running a 32-bit version of Windows

Double-click on the file that you downloaded

Extract to: C:\MinGW.

Build the MAME Source Tree

Download the current source from the MAMEDev website.

Inside this zip file is another zip file named

Extract the contents of to where you plan on keeping your MAME source tree (The rest of this page is going to assume C:\mamesrc).

You should now have a folder that looks like the following:


DIFFs, Extra Files, and Stuff

In order for the nag screens to go away, you need to include the DIFF files. Go here and select the DIFF file for your version.

Extract DIFFs to your C:\mamesrc folder.

As an option, download this file here.

This ZIP contains the following files:

  • PatchMAME.bat – a batch file to help run patch.exe
  • MakeMAME.bat – a batch file to help compile MAME
    cmd.bat – a batch file that runs a command prompt window at your source folder, with Administrative rights (to fix issues with “patch.exe”)

Extract to C:\mamesrc

You should now have a folder that looks similar to the example here.


This example shows the main source tree, the first five updates for MAME 0.146, and the three batch files.

If necessary, edit MakeMAME.bat:

Right-click on the file, and choose Edit. This will open the file in Notepad.

  • If you extracted MinGW to a different folder, change the red area to the correct path
  • If you are building a 32-bit version of MAME, change w64 to w32

Do the same for PatchMAME.bat.

Apply the “u” Update DIFFs

If you are just compiling the main source code, then you can skip this section.

  • Double-click the command prompt shortcut to open a command-line window.
  • The actual command to patch with a DIFF file is:patch -p0 -E <0155u1.diff

(in this example, using 0155u1.diff)

The batch file makes it a little easier to type; you can use the command:

patchmame 0155u1

(in this example, using 0155u1.diff)

You will see a window similar to the one shown. These are all of the source files that are changing.

When applying DIFFs, make sure to apply them in order (0146u1, 0146u2, 0146u3, etc.)

Create the MAME Executable

At the command prompt, type makemame, then wait, as it’s going to take a bit. You’ll see a bunch of lines of code scroll by. That’s the compiler doing its work.

When the code is done compiling, go back and check your mamesrc folder. You will have a shiny new MAME:

The 32-bit version will be named mame.exe; the 64-bit version (shown here) will be named mame64.exe

Copy to whichever folder you use for MAME.

If you also want a copy of the various tools that come with MAME, use the command make -all

CONGRATULATIONS!! You have now entered the world of compiling! You can now stay up to date within the world of MAME on your own, without having to wait for another website to upload a pre-compiled version.

MAME for Newbies

Here are some thoughts on setting up MAME for the first time, especially with an X-Arcade controller. Getting started with X-Arcade – yes the information is there in the manual, but it’s not explained very well. Here’s my take.

Go to [your favorite rom site] and download the latest MAME32 version for Windows – currently v0.90. MAME is really a DOS program, but MAME32 lets you play it easily in Windows.

Unzip the file to a directory on your PC, such as C:\MAME\.

Go to [or your favorite rom site] to find some roms that you like. Save only the MAME files – not the others – I really don’t know what those are for. Save the roms in the same directory where you unzipped MAME32, in the subdirectory named /roms. DON’T UNZIP THEM. Keep them in ZIP format.

Launch MAME32.

On the right hand side, click Available. You will see the games in your /roms directory – and a few others.

Double click on a game. If it displays sideways, exit the game, and click Options > Default Game Options > Advanced and check “Switch resolutions to fit” AND “Switch color depths to fit” -or- uncheck “Stretch using hardware”. This will prevent the games from displaying sideways. If you uncheck “Stretch using hardware” it will display correctly but won’t use your entire monitor real estate – but it WILL display the 16 bit looking pixellated games, which looks more authentic.

If you’re using a computer keyboard, you will be disappointed. If you don’t want to build an interface yourself, X-Arcade makes good controllers.

X-Arcade, or any controller, will need to be set up in MAME. This is critical for getting the best performance out of your controller. When you launch a game, press the TAB key to open the configuration. Note that there are two different configs here (input general) and (input this game). (input general) is for ALL games and (input this game) is for just the game you’re playing. You want to change the one you’re playing – (input this game).

Okay. Let’s step back a minute here. Before you go any further, do you remember how the original game buttons were configured? Did the original Asteroids arcade controls use a joystick and two or three buttons? You need to find out. Google it, find the button layout, and then do your best to map out that layout on your controller – mentally at first – then you will configure your buttons for THIS GAME ONLY – (input this game).

Now, back to the TAB key and the config menu – this will take some trial and error, so take your time. And don’t worry – you can easily reset the config file back to default. How? Well, when you change a configuration for a specific game, a new file is created in a subdirectory called /cfg in the main MAME directory. If you’ve never done this, the /cfg directory will be empty. If you make any modifications, a new file is created with the name of the game, for example /cfg/asteroids.cfg. This is a simple text file with XML in it that specifies your custom configuration. If you want to go back to the default config, just delete this file for the specific game, and it will revert to the MAME controller config. Easy, eh? Keep in mind that MAME itself has a cfg file too in the /ctrlr subdirectory, so if you change the default config for ALL games, it is stored in the Xarcade.cfg file (or whatever your device is). So before you go monkeying with your default config (input general), you might want to make a copy of that file for backup. That way, if you mess up, just restore the Xarcade.cfg (or whatever) file to get it back to default.

When you configure your game, how do you remember what buttons were mapped to what function? Paper. Yes, the old two dimensional medium – or a gif or whatever. You will want to write down which button is fire and which is hyperspace, for example.

So you’re in the config menu, and suddenly you have four buttons assigned to one functiion! Here’s what you do. Move away from that function (using your up/down keys), then go back and assign it a single button. If you keep pressing Enter and pushing another button, it will assign all the buttons you press – rather than replace them – if you don’t move away from that function first.

Why does playing Pac-Man with X-Arcade suck? Because Pac-Man requires a 4-way joystick. A 4-way joystick has only four directions that you can point to – up/down/right/left. An 8-way has those four and also all the diagonals between them – hence, 8-way. Both 4-way and 8-way joysticks have only 4 switches in them, but the 8-way allows you to press two at the same time – so you can go up/left or up/right, etc. X-Arcade ships with their joystick set to 8-way, so if you’re old school Pac-Man, Donkey Kong, Joust, Phoenix, like me, you’re not going to like it. It will work, but not well. Fortunately, you can switch the joystick from 8-way to 4-way by opening up the box and turning a plastic “actuator” (black cylinder) upside down – look on the X-Arcade website for instructions. It’s easy. But don’t do it with the controller box on your lap, like they say; put it on a table, resting on the joysticks – they’re sturdy and can take it. If you do it on your lap, the joystick will drop to the floor, along with two other pieces – ask me how I know.

And this is where having the dual joystick model works well – beause you can keep one joystick 8-way, for games like Gyruss, and set the other to 4-way for Pac-Man and Frogger.

Other notes:

For Snaps: or

Good ROM site
and put in /mame/roms/
keep them zipped

and put in /mame/snaps/

Or get snaps here:
Links 1, 2, 3
download all 3, install 7z program, then extract them all. you need all of them.

Compiling MAME with hiscore and no nag screens
use the DIFF files to allow hiscore and no nag

DIFF Files
use to modify mame before compiling it



Get Marquees here:
and put in /mame/marquees/

Artwork. Don’t use it. Go here: download the mirror!
and put in /mame/artwork/
keep them zipped

Board 1:
1. Yellow => 5v [J7]
2. Red => [J5]
3. Black => [J5]
4. Green => [J7 Ground]

Board 2:
1. Purple => 5v [J7]
2. Red => [J5]
3. Black => [J5]
4. Blue => [J7 Ground]

Controller Info

1943 – 8way + 2 button (button on right)
Asteroids – 5 button
Battle Zone – 1 2way + 1 2way with fire
Berzerk – 8way + 1 button (button on right or left)
Centipede – Trackball
Defender – 1 2way + 5 button. or 1 8way + 4 button
Dig Dug – 4way (button on right or left)
Discs of Tron – 1 spinner + 1 8way with 2fire
Donkey Kong – 1 4way (button on right)
Frogger – 1 4way
Galaga – 1 2way + 1 button (button on right)
Galaga 88 – 1 2way + 1 button (button on right)
Galaxian – 1 2way + 1 button (button on right or left)
Golden Tee Golf – Trackball + 3 button
Gorf – 1 8way with fire
Gyruss – 1 8way + 1 button (button on right)
Joust – 1 2way + 1 button
Lunar Lander – 1 2way + 2 button (2 potentiometers and 3 buttons)
Mario Bros – 1 2way + 1 button (button on right)
Missile Command – Trackball + 3 button (volcano)
Moon Patrol – 1 2way + 2 button (button on right or left)
Ms Pac Man – 1 4way
Omega Race – spinner + 2 button (button on right)
Pac Man – 1 4way
Phoenix – 4 button
Pleiads – 4 button
Pole Position – spinner + 3 buttons (spinner + 2 pedals + 1 shifter)
Red Baron – 1 8way with fire
Scramble – 1 8way + 2 button (button on right or left)
Sea Wolf – spinner or 2way + 1 button (periscope with button)
Space Invaders – 1 2way + 1 button
Star Castle – 4 button
Super Breakout – spinner + 3 buttons?
Tempest – spinner + 2 button (fire and zapper to left of spinner)
Tetris – 1 4way + 1 button (to spin blocks)
Time Pilot – 1 8way + 1 button (spinner works well here) (button on right)
Tron – 1 8way with fire + spinner
Vanguard – 1 8way + 4 buttons (in diamond shape on right)
Xevious – 1 8way + 2 button (button on right or left)
Zaxxon – 1 8way with fire + 1 button (button on right or left)


How to Enable HTTPS on the Raspberry Pi Apache Web Server

Note that this enables only “self-signed” certificates. I followed these directions but invariably encountered problems that were not addressed. Running Wheezy on a Raspberrry Pi B v1.

As usual, update first.

$ sudo apt-get update

Then make sure Apache and OpenSSL is installed:

$ sudo apt-get install apache2 openssl

If it is already installed, like it was on mine, then you will see:

Reading package lists... Done
Building dependency tree
Reading state information... Done
apache2 is already the newest version.
openssl is already the newest version.
openssl set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 4 not upgraded.

Your external certs are installed in /etc/ssl/certs. You won’t put these certs there.

Create a new directory for local certificates (-p means no error if existing, make parent directories as needed):

$ sudo mkdir -p /etc/ssl/localcerts

The next line starts the certificate generation. The cert is good for 365 days – you can change that.

$ sudo openssl req -new -x509 -days 365 -nodes -out /etc/ssl/localcerts/apache.pem -keyout /etc/ssl/localcerts/apache.key

The result of this command is:

Generating a 2048 bit RSA private key
......., etc.

Next, you will enter the answers to the following questions. This is where I effed up, so don’t you do it too. the FQDN name is the name of your Apache web server. For me, since I’m just running it locally, that would be the server name, like “raspberrypi” – if you kept the default. That server name is mapped to an internal IP, like or something.

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Francisco
Organization Name (eg, company) [Internet Widgits Pty Ltd]:PaynsName
Organizational Unit Name (eg, section) []:SysOpsProgFest
Common Name (e.g. server FQDN or YOUR name) []:raspberrypi_orwhatever
Email Address []

When that is done, you will have two new files in this directory: /etc/ssl/localcerts

Then chmod those files:

$ sudo chmod 600 /etc/ssl/localcerts/apache*

Enable SSL:

$ sudo a2ensite ssl

Now you need to edit the ssl configuration file in the /etc/apache2/sites-available directory.

$ cd /etc/apache2/sites-available 
$ ls -l

See what’s in there. For me, it looked like this:

-rw-r--r-- 1 root root 692 Jul 19 2016 default
-rw-r--r-- 1 root root 7461 Mar 18 14:51 default-ssl

Copy the default-ssl to a new file named the same name as your FQDN name above – for this example:

$ sudo cp default-ssl raspberrypi_orwhatever

Then edit it:

$ sudo nano raspberrypi_orwhatever

Change this line:

 <VirtualHost _default_:443>

to this:

 <VirtualHost raspberrypi_orwhatever:443>

and change these two lines:

SSLCertificateFile    /etc$
SSLCertificateKeyFile /etc$

to this (your new key location):

SSLCertificateFile /etc/ssl/localcerts/apache.pem
SSLCertificateKeyFile /etc/ssl/localcerts/apache.key

Save, close, then do:

$ sudo a2ensite raspberrypi_orwhatever

The link above says to enable port 443 in /etc/apache2/ports.conf, but mine already had it enabled with these lines:

<IfModule mod_gnutls.c>
    Listen 443

So I didn’t modify that file.

Now restart Apache:

$ sudo service apache2 restart

And what you should get is a browser error, telling you that the site is not secure. That means it’s working! Because you didn’t pay a service to generate a validated certificate, you have to take your own word for it that it’s valid.



Click on I Understand the Risks, then click on Add Exception….

Next click on Get Certificate, and finally Confirm Security Exception to bypass SSL warning in FireFox.



Click on Advanced, then Proceed to (unsafe) to bypass SSL warning in Chrome.

Internet Explorer


Click on Continue to this website (not recommended) to bypass SSL warning in Internet Explorer.


Math is Hard: Orange you glad you’re not in fifth grade?

Here’s the answer to a problem that I admit that I cheated on. I got thrown by the idea that giving three oranges away means subtract – that’s where visualizing the transaction helps.

Shomika was helping her family pick oranges in their grove. She took some oranges home to share with her three friends. She gave 3 more than half to Jennifer. Angela got half of the remainder and 3 more. She gave Josie half of the remainder plus 3. When she got home, she only had 10 oranges left. How many did she have when she left the grove?

Start from the bottom and work your way up. For example, to be left with 10, she had to have had 26 when she met Josie, because she gave half away (26-13=13) then three more (13-3=10). And 26 is half of 58, etc. It’s the same problem with three iterations. So once you figure out the first problem – how many did she have before she met Josie – you apply the same logic to the rest.

The answer, if you don’t want to try it yourself:

In order for Shomika to be left with 10, she had to have had 26 when she met Josie, because she gave half of the 26 to Josie, which left 13, then she gave Josie 3 more, leaving her with 10.

26/2 - 3 =
  13 - 3 =

In order for Shomika to be left with 26, she had to have had 58 when she met Angela, because she gave half of the 58 to Angela, which left 29, then she gave Angela 3 more, leaving her with 26.

58/2 - 3 =
  29 - 3 =

In order for Shomika to be left with 58, she had to have had 122 when she met Angela, because she gave half of the 122 to Angela, which left 61, then she gave Angela 3 more, leaving her with 58.

122/2 - 3 =
   61 - 3 =

Therefore, Shomika had 122 oranges when she left the grove. We can also infer that Jennifer is her BFF, and Shomika has strong arms. If an average orange weighs 6oz., then 122 oranges would weigh 45.75lbs (6 x 122)/16 = 45.75.

I started going down the algebraic route but stopped, because this was a question for a fifth-grader, who hadn’t had algebra yet. But this is the solution I would have gone for.

Another Way to Look At It

Since you’re going backwards, you just reverse the operations. Shomika had 10 after subtracting 3 and halving the prior amount. So to get to the prior amount, you add three then double that amount.

Or another way to look at it – what if Shomika wanted her oranges back? Her “friends” had posted a mean message on Facebook that she wasn’t supposed to see – but she did! Because Shomika is good friends with Tangiers, who is friends with Angela on Facebook, and he can see all her posts! And both Angela and Josie “liked” it!

So Shomika went to Josie’s house and took the extra 3 from her (now Shomika has 13), then doubled that amount, and now she has 26. Then she went to Angela and asked for the 3 back (now she has 29), then doubled that, and she has 58. Josie wasn’t home when Shomika got to her house, so she sneaked in to her kitchen through the back door (because she knows the back door is always open so the dog can go out and poop). She grabbed the flowery pink bag (that’s just like Josie!) of oranges next to the kitchen sink and ran. It was hard going, because she was already carrying around 22lbs of oranges in a paper bag. When she got home, she pulled three oranges out of the flowery bag (now she has 61), and counted double that to make sure she got all 122 oranges back. She didn’t though. Josie ate one. Josie is fat and picks her nose!

Or algebraically:

1/2x - 3 = 10
   x - 6 = 20
       x = 26


1/2x - 3 = 26
   x - 6 = 52
       x = 58


1/2x - 3 =  58
   x - 6 = 116
       x = 122

A Simpler Version

The question is a lot simpler if you don’t include the plus-three. This much easier example will give you an idea for how to solve the problem:

Bellybop helped her family pick oranges in their grove, and afterwards, she took some oranges home to share with her friends. She gave half of the total oranges to Pollysnack. Silipsity got half of what was left of that. And she gave Hesponda half of what was left after that. When she got home, she only had 10 oranges left. How many did she have when she left the grove?

Working backwards from 10:

She had 20 when she met with Hesponda, who took 10.    (20 – 10 leaves 10).
She had 40 when she met with Silipsity, who took 20.       (40 – 20 leaves 20.
She had 80 when she met with Pollysnack, who took 40.  (80 – 40 leaves 40).

It’s a bit harder when you add the plus-three variant.

A Funner Version

Annabelle works for Apple Computer, and she was blackmailed into stealing iPads from the warehouse by three mafioso. The first guy, Guy (pronounced “Gee”), got half of the loot, plus seven extra to sell on eBay under the handle: “FlyGuy”. The next fella, Rosie, got half of what was left, plus 1. He wanted to post on Youtube a video of someone diving into a pool with a brand new iPad with the extra one (yeah, that was him!). Donny, the last guy, got half of the remainder, plus an extra 2 for his kids. Annabelle was left with 1, so if they got busted, she’d be holding the hot merch, too. How many iPads were stolen?

Work it backwards. The first calculation is for Donny:

1/2x - 2 = 1
   x - 4 = 2
       x = 6

Then Rosie:

1/2x - 1 = 6
   x - 2 = 12
       x = 14

And finally, Guy:

1/2x - 7 = 14
  x - 14 = 28
       x = 42

Next: English lesson on “had to have had”. Shomika had to have had had a lot of oranges. Also, why is it “backwards” as an adverb and “backward” as an adjective?

RealVNC Small Resolution Problem on Raspberry Pi

Because nothing is easy on Linux. If it were not for the staggering amount of user supplied support, wrestling with Linux would be as frustrating as ever. Fortunately, the answers are out there, due to the common denominator of the Raspberry Pi.

I set up VNC Server (RealVNC) on the Pi while it was connected to my HDMI monitor, whose resolution is set to 1080p (aka 1920 x 1080). When I logged in with the VNC Client from Windows, it gave me full resolution. Later, when I had shut down and restarted without the monitor attached (running headless), the Windows client gave me some horrid size like 480 x 320 – something minuscule.

Apparently, when you run headless, it defaults to the lowest possible resolution. To fix this:

$ sudo cp /boot/config.txt /boot/config.backup
$ sudo nano /boot/config.txt

and uncomment/edit:


Now reboot:

$ sudo shutdown -r

Had it not been for stackexchange and the raspi forum, I would have been lost. Instead, I got the glorious 1080p as I had expected. Actually, I had expected the client to allow me to set this value, but I suppose it makes sense that it has to be configured at the server.

Remember to revert to the backup config.txt file if you want to connect with some other monitor.

You can also set it to a lower resolution of 1024×768 at 60Hz by:

$ sudo cp /boot/config.txt /boot/config.backup
$ sudo nano /boot/config.txt

and uncomment/edit:


You can view more screen resolutions at