27 July 2016

NESPi - my Mini NES Classic Raspberry Pi games console

It was inevitable... I have a Raspberry Pi, I have a 3D printer, I'm a huge nerd...

At some point I was going to print a case for it in the shape of the old Nintendo Entertainment System.


In the end, this project turned into more of a love-letter to the NES than just printing a case.
I learnt a lot of new things about Linux, 3D design, wrote my first Python program and had a blast doing it...

The NES was the first console I had growing up. I've got strong memories of playing Nintendo games with my brothers when we were younger.

The ergonomics of the whole experience are something I still remember very clearly 20+ years later...
  • The front-loading game slot... lifting the door and inserting the cartridge
  • Pushing it down with that satisfyingly-sprung *click*.
  • The tactility and sound of the power button when you turned it on...
  • ...and of course blowing on the cartridges when they didn't work :)
Fond memories, and all of that is just as much part of my nostalgia for the system as playing the games themselves, and I had some ideas of how I could pay homage to it using the Raspberry Pi.

RetroPie. It's a collection of software that runs on the Raspberry Pi, integrating a bunch of retro gaming emulators into an easy-to-use package.


It's quite popular and loads of people have made some really great builds using it. Since I was just starting out with Raspberry Pi and Linux, I'd use RetroPie as the base software for my project.




Initial concept:

There are loads of models on Thingiverse of NES-shaped Raspberry Pi cases. Many of them distort the NES aspect ratio though, ending up with a kind-of super-deformed chibiNES.

Cute, but not exactly what I wanted.

So I dug out my old NES and took some measurements. I was going to design my case from scratch.
20-plus years in the loft has taken it's toll
To make the case as compact as possible, I scaled down the real NES dimensions to 40% of actual size.

This gave me just about enough room for the Pi to sit transverse, USB and network ports on the left, power and HDMI at the back.

I could make a cut-out for the microSD card and would relocate two of the USB ports to the front where the controllers would be on a real NES.
As I got further along with the design and started to model the top half, I wondered if I could do anything to make the cartridge slot functional.

At first, I thought about making a NES cart-shaped caddy to hold the microSD card.

A guy called wermy did that with the SD card on his RetroPie build the "Game Boy Zero". It turned out really nicely but ultimately I came up with another idea that I hadn't seen done before.

NFC.

A while ago I picked up an NFC reader based on the PN532 from NXP, intending to play around with an Arduino and some tags to control room lighting.

My plan here would be to make a little replica NES cartridge with a tag inside and have the Raspberry Pi launch a game when it reads the tag.

Cool idea right?
'artist's' impression
It wasn't quite as easy as it sounds. I'm not much of a programmer, I can ctrl-c/ctrl-v with the best of them but tend to rely on tutorials and pre-written libraries for the most part and that's where I had trouble.

NFC has been done on the Raspberry Pi but I couldn't find much information. Adafruit has a rather sparse article about getting libnfc compiled, but I soon found it a bit more complicated than I thought.

Firstly, there are different kinds of tags. The MIFARE Classic 1K, often bundled with NFC readers, aren't compatible at all with many Android phones including mine.

I wanted to be able to write to the cartridges with my phone, and then have them read by the Pi. This meant starting with a universally compatible tag.


The tags I bought to experiment with, are NTAG216s. These are NFC Forum Type 2 tags from what I've read they're compatible with all Android phones. They also have plenty of writeable memory, with 888 bytes available.

On my phone I use NFC Tools Pro. It's pretty good, you can read/write tags with things like WiFi and Bluetooth pairing info, contact details etc. and it's all nice and easy to use.

Eventually I found that I'd only need to write the console and rom name to the tag and could use that to lookup and launch the game on the Raspberry Pi itself.

The issue I had trouble to start with, was actually reading that information in the first place.

NDEF, the structure of the writeable data, is fairly transparent and simple to use on Android. But I couldn't find anyone that had read these NDEF records with a Raspberry Pi.

All the documentation I found on the subject was a bit over my head and whilst I could read the tag's ID easily enough, I couldn't get any NDEF data.

After some searching, I came across "NDEF Library for Arduino". With this, the plan would be to read the NDEF records with an Arduino, then send them to the Raspberry Pi.

Not the most elegant solution I know, but I was probably going to need to use an Arduino at some point to run a shut-down/power switch for the Pi, so... two birds I suppose.

Speaking of shutdown switches... because the Raspberry Pi doesn't have any sort of power switch people have designed their own but they're all pretty expensive.

Since I'd decided to use an Arduino to read the NFC anyway, I would just have a go at writing my own program to do the power management.




Code time ; )


The software for this project is in two parts. An Arduino sketch to read the NFC tags and manage the power switching, and a Python script running on the Raspberry Pi to launch the games.

The two communicate over serial. I could have used I²C, but I was already familiar with serial on the Arduino and could also use it for debugging.

Arduino:

I'll post my code here because I've always found it useful to read other peoples programs.

However I can't vouch for it's quality, it works and I've written comments where I could, but I'm no expert.

Warning. *lots* of code below, prepare to scroll...

/****************************************************************
    NESPi NDEF Reader/Power Controlller v0.1  [mike.g|jun2016]
 ****************************************************************/
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <math.h>
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>
#include <NfcAdapter.h>
#include <EEPROM.h>
#include "FastLED.h"

const int buttonPin = 2;       // input pin for the NES 'reset' button
const int powerPin = A2;       // output to MOSFET
const int piPin = A3;          // input for RPi status
const int ledPin = 5;          // front LED indicator

boolean bootState = 0;        // boot status variable
boolean tagToggle = true;     // toggle variable for tag reader
boolean buttonWasAsleep = 0;  // if we've just woken from sleep
boolean piVal;                // value read from piPin
boolean piLast;               // last value of piPin

#define NUM_LEDS 1      // number of LEDs(could expand?)
#define DATA_PIN A1     // pin for LED data
CRGB leds[NUM_LEDS];    // LED array
boolean ledEnable;      // led enable state

String piMsg;           // String to hold the serial data from the Pi
long resetTime;         // used to check if the Pi was reset or shutdown

PN532_SPI pn532spi(SPI, 10);              // NFC connected to the SPI bus
NfcAdapter nfc = NfcAdapter(pn532spi);    // PN532 'NFC MODULE V3' by elechouse
const int nfcPin = A0;                    // PN532 RSTPDN to sleep NFC reader when pulled LOW
boolean nfcWasAsleep = 0;                 // NFC reader sleep value

/*****************************************************************************************
 *****************************************************************************************/
void setup() {

  // start the serial port
  Serial.begin(9600);

  // start the NFC reader in power-down state by driving the PN532 RSTPDN pin LOW
  pinMode(nfcPin, OUTPUT);
  digitalWrite(nfcPin, LOW);

  // Set-up the RGB LED
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(255);

  // Set-up the button
  pinMode(buttonPin, INPUT_PULLUP);

  // Set-up the indicator LED and MOSFET outputs
  pinMode(powerPin, OUTPUT);
  digitalWrite(powerPin, LOW);        // ensure MOSFET is off when Arduino starts
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);

  // Read stored preferences from EEPROM
  ledEnable = EEPROM.read(0);

  // set  pull-up resistors on unused pins
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  for (int i = 6; i < 10; i++)pinMode(i, INPUT_PULLUP);

  // after setting up go to sleep to save power at idle
  go_to_sleep();

}
/*****************************************************************************************
 *****************************************************************************************/
void loop() {

  // restart the nfc reader after waking from sleep
  if (nfcWasAsleep) {
    digitalWrite(nfcPin, HIGH);      // set RSTPDN HIGH to enable NFC reader
    pinMode(nfcPin, INPUT_PULLUP);   // set input pullup resistor to limit current
    delay(100);                      // wait for NFC reader to settle
    nfc.begin();                     // initialise NFC reader
    nfcWasAsleep = 0;                // toggle the bit so we only do this once
  }


  // Get button event
  int b = checkButton();

  if (b == 1) nesReset();             // single button click
  if (b == 2) ledToggle();            // double-click
  if (b == 3) powerOn();              // press and hold
  if (b == 4) shutdownPi();           // press and long-hold


  // poll the piPin to detect a software shutdown of the Raspberry Pi
  // if piPin goes from HIGH to LOW, then the RPi has inititated a shut-down or reboot
  piVal = digitalRead(piPin);
  if (bootState == 1) {                                       // only check after boot-up
    if (piVal == 0 && piLast == 1) resetTime = millis();      // start a timer if piPin falling edge
  }
  piLast = piVal;
  // if piPin is still low after 12 seconds then the Pi has shut down not reset, and we can cut the power
  if (millis() - resetTime > 12000) if (digitalRead(piPin) == 0 && bootState == 1) powerOff();

  scanTag();
  readPi();

  // set the LED colour if the RPi hasn't started (button wasn't held long enough when waking up)
  if (bootState == 0)leds[0] = CRGB::DarkRed; FastLED.show();

}
/*****************************************************************************************
 *****************************************************************************************/
void nesReset() {

  // send 'reset' to the Pi to trigger a reset of the emulator
  Serial.print("reset"); Serial.print(", "); Serial.println(", ");

}
/*****************************************************************************************
 *****************************************************************************************/
void ledToggle() {

  // toggle the ledEnable bit
  ledEnable = !ledEnable;
  // save the setting to EEPROM
  EEPROM.write(0, ledEnable);

  // turn LED(s) off if we need to
  if (ledEnable == 0) leds[0] = CRGB::Black; FastLED.show();

  // set tagToggle to refresh the LED colour(read the tag again)
  tagToggle = 1;

}
/*****************************************************************************************
 *****************************************************************************************/
void powerOn() {

  if (bootState == 0) {

    // flash the RGB Led twice in white
    leds[0] = CRGB::White; FastLED.show(); delay(100);
    leds[0] = CRGB::Black; FastLED.show(); delay(100);
    leds[0] = CRGB::White; FastLED.show(); delay(100);
    leds[0] = CRGB::Black; FastLED.show();

    // turn on the MOSFET
    digitalWrite(powerPin, HIGH);
    // turn on the LED indicator
    digitalWrite(ledPin, HIGH);

    // wait for the RPi to finish boot before continuing, lazy, but prevents additional button triggers
    while (digitalRead(piPin) == 0) {
      // pulse the LED indictor slowly during boot-up
      float val = (exp(sin(millis() / 1500.0 * PI)) - 0.36787944) * 108.0;
      analogWrite(ledPin, val);
    }

    // boot-up has finished here
    // turn on LED indicator
    digitalWrite(ledPin, HIGH);
    delay(500);
    bootState = 1;

  }
}
/*****************************************************************************************
 *****************************************************************************************/
void powerOff() {

  // turn off the RGB LED
  leds[0] = CRGB::Black; FastLED.show();

  // pulse the LED indicator for 5 more seconds before cutting power to the Pi
  for (int i = 0; i < 500; i++) {
    float val = (exp(sin(millis() / 500.0 * PI)) - 0.36787944) * 108.0;
    analogWrite(ledPin, val);
    delay(10);
  }
  digitalWrite(powerPin, LOW);    // cut power to the Pi
  bootState = 0;
  pinMode(nfcPin, OUTPUT);
  digitalWrite(nfcPin, LOW);      // put NFC reader into shutdown state
  digitalWrite(ledPin, LOW);      // turn off indicator LED
  go_to_sleep();

}
/*****************************************************************************************
 *****************************************************************************************/
void shutdownPi() {

  // send shutdown message to Raspberry Pi
  Serial.print("shutdown"); Serial.print(", "); Serial.println(", ");

  // flash the RGB Led twice in red
  leds[0] = CRGB::Red; FastLED.show(); delay(100);
  leds[0] = CRGB::Black; FastLED.show(); delay(100);
  leds[0] = CRGB::Red; FastLED.show(); delay(100);
  leds[0] = CRGB::Black; FastLED.show();

  // could do a check/response over serial here?(can't be bothered)
  // wait for the RPi signal to go LOW before cutting the power
  while (digitalRead(piPin) == 1) {
    // pulse the LED a bit faster during shutdown
    float val = (exp(sin(millis() / 500.0 * PI)) - 0.36787944) * 108.0;
    analogWrite(ledPin, val);
  }

  // shutdown has finished here
  powerOff();

}

/*****************************************************************************************
 *****************************************************************************************/
void scanTag () {

  if (nfc.tagPresent(100))     // timeout=100, balance between reads and button responsiveness
  {
    if (tagToggle) {
      NfcTag tag = nfc.read();
      // Serial.println(tag.getTagType());
      Serial.print(tag.getUidString()); Serial.print(", ");    // print the UID to serial monitor
      if (tag.hasNdefMessage()) {
        NdefMessage message = tag.getNdefMessage();
        // get the first 2 records of the tag
        for (int i = 0; i < 2; i++)
        {
          NdefRecord record = message.getRecord(i);
          int payloadLength = record.getPayloadLength();
          byte payload[payloadLength];
          record.getPayload(payload);
          // force the data into a String (should be ok for plain text fields)
          String payloadAsString = "";
          // start 3 characters from the left to remove garbage(language characters?)
          for (int c = 3; c < payloadLength; c++) {
            payloadAsString += (char)payload[c];
          }
          Serial.print(payloadAsString); Serial.print(", ");    // print the NDEF record
        }
        Serial.println(" ");
        tagToggle = 0;
      }
    }
  }
  else {
    // when there's no tag present
    if (ledEnable && bootState) {
      leds[0] = CRGB::OrangeRed; FastLED.show();
    }
    if (tagToggle == 0) {
      Serial.print("cart_eject"); Serial.print(", "); Serial.println(", ");
      tagToggle = 1;
    }
  }
}
/*****************************************************************************************
 *****************************************************************************************/
void readPi() {

  // read data from the serial port into a string to check for messages
  if (Serial.available()) {
    piMsg = Serial.readString();

    // toggle the tag reader when prompted by the RPi... lets us start with a cart insterted
    if (piMsg == "ready") {
      tagToggle = true;
    }

    // change the LED colour depending on the message recieved from the Raspbeery Pi
    else if (piMsg == "ok" && ledEnable == 1) {
      leds[0] = CRGB::Green; FastLED.show();
    }
    else if (piMsg == "bad" && ledEnable == 1) {
      leds[0] = CRGB::Red; FastLED.show();
    }
  }
}
/*****************************************************************************************
 *****************************************************************************************/
void go_to_sleep() {

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // set the sleep mode
  sleep_enable();                         // enable sleep bit so sleep is possible
  attachInterrupt(0, wakeUp, LOW);        // attach pin 2 interrupt to wake up from sleep
  delay(100);
  sleep_mode();                           // go to sleep
  sleep_disable();                        // wake up here
  detachInterrupt(0);                     // detach the interrupt after waking up
}

void wakeUp() {

  // set toggle bits to let the main program know we just woke up
  nfcWasAsleep = 1;
  tagToggle = 1;
  buttonWasAsleep = 1;
  bootState = 0;
}
/*****************************************************************************************
 *****************************************************************************************/
/*=========================================================================================
    MULTI-CLICK:  One Button, Multiple Events
    By Jeff Saltzman
    Oct. 13, 2009

    http://jmsarduino.blogspot.co.uk/2009/10/4-way-button-click-double-click-hold.html
  ==========================================================================================*/

// Button timing variables
int debounce = 20;          // ms debounce period to prevent flickering when pressing or releasing the button
int DCgap = 250;            // max ms between clicks for a double click event
int holdTime = 1000;        // ms hold period: how long to wait for press+hold event
int longHoldTime = 2500;    // ms long hold period: how long to wait for press+hold event

// Button variables
boolean buttonVal = HIGH;   // value read from button
boolean buttonLast = HIGH;  // buffered value of the button's previous state
boolean DCwaiting = false;  // whether we're waiting for a double click (down)
boolean DConUp = false;     // whether to register a double click on next release, or whether to wait and click
boolean singleOK = true;    // whether it's OK to do a single click
long downTime = -1;         // time the button was pressed down
long upTime = -1;           // time the button was released
boolean ignoreUp = false;   // whether to ignore the button release because the click+hold was triggered
boolean waitForUp = false;        // when held, whether to wait for the up event
boolean holdEventPast = false;    // whether or not the hold event happened already
boolean longHoldEventPast = false;// whether or not the long hold event happened already

int checkButton() {

  /****************************************************************************************************/
  // hacky bit I added here :/ because I use the same button to interrupt sleep it would already be
  // pressed when we check it here, so that we can just keep it held down to power back up we want
  // buttonLast to be HIGH after waking from sleep so that this function acts as if it was pressed

  if (buttonWasAsleep) {
    buttonLast = 1;
    buttonWasAsleep = 0;
  }
  /****************************************************************************************************/

  int event = 0;
  buttonVal = digitalRead(buttonPin);

  // Button pressed down
  if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce)
  {
    downTime = millis();
    ignoreUp = false;
    waitForUp = false;
    singleOK = true;
    holdEventPast = false;
    longHoldEventPast = false;
    if ((millis() - upTime) < DCgap && DConUp == false && DCwaiting == true)  DConUp = true;
    else  DConUp = false;
    DCwaiting = false;
  }
  // Button released
  else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce)
  {
    if (not ignoreUp)
    {
      upTime = millis();
      if (DConUp == false) DCwaiting = true;
      else
      {
        event = 2;
        DConUp = false;
        DCwaiting = false;
        singleOK = false;
      }
    }
  }
  // Test for normal click event: DCgap expired
  if ( buttonVal == HIGH && (millis() - upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != 2)
  {
    event = 1;
    DCwaiting = false;
  }
  // Test for hold
  if (buttonVal == LOW && (millis() - downTime) >= holdTime) {
    // Trigger "normal" hold
    if (not holdEventPast)
    {
      event = 3;
      waitForUp = true;
      ignoreUp = true;
      DConUp = false;
      DCwaiting = false;
      //downTime = millis();
      holdEventPast = true;
    }
    // Trigger "long" hold
    if ((millis() - downTime) >= longHoldTime)
    {
      if (not longHoldEventPast)
      {
        event = 4;
        longHoldEventPast = true;
      }
    }
  }
  buttonLast = buttonVal;
  return event;
}

It uses the NDEF library that I found earlier to read the tag UID and the first two NDEF records, then sends it over serial to the Raspberry Pi.

We also control a WS2812 LED, lighting it in different colours depending on status messages received from the Raspberry Pi.

The NDEF data is sent in one line, like this: ["$UID", "$CONSOLE", "$ROM", \n]

Each part is separated by a comma and space ", " so that when I read it with the Raspberry Pi program, I can use the ", " to chop-up the string into the data I need.

I also use the "UID" field to send other information to the Pi, like if a cartridge is ejected and when to perform a shut-down.

The NES 'reset switch' operates a few functions; a single press sends a reset message to the Pi, a double-press, toggles the status indicator light.

Pressing and holding the reset switch turns the Raspberry Pi on, pressing and holding for a bit longer will shut it down and cut the power.

After the main power is plugged in, the Arduino goes into a sleep mode and turns off the NFC reader.

This is important because when it's running code, the Arduino draws around 30mA at 5V, the NFC reader takes another 80mA.

Granted that's not outrageous, but the Raspberry Pi itself is very low-power and only consumes about 300mA when running games, so more than 100mA when 'off' is not really acceptable.

In sleep mode, waiting for a button press to wake up, the total standby current is less than 10mA.

Raspberry Pi:

I chose Python because I hadn't used it before and wanted to try something new, also there's loads of on-line help to learn the basics.

I really like Python actually, it's very easy to write and after getting used to the indentation I got on quite well with it.

It's my first effort here so there are a couple of hacky bits, because I don't really understand Linux all that well yet.

Again I'll post the script, but like my Arduino programming, it's by no means exemplary code: *scroll time*

import os
import psutil
import re
import serial
import socket
import subprocess
import time
from gpiozero import Button, LED


#####################################
# NESPi Cart Reader v0.1 by mike.g  #
#        www.daftmike.com           #
#####################################


#############################################################################################
# Sends 'message' to port 55355 for RetroArch's network commands

def retroarch_command(message):
    sock = socket.socket(socket.AF_INET,
                         socket.SOCK_DGRAM)
    sock.sendto(message, ("127.0.0.1", 55355))


#############################################################################################
# Kills the task of 'procnames', also forces Kodi to close if it's running

def killtasks(procnames):
    for proc in psutil.process_iter():
        if proc.name() in procnames:
            pid = str(proc.as_dict(attrs=['pid'])['pid'])
            name = proc.as_dict(attrs=['name'])['name']
            print "stopping... " + name + " (pid:" + pid + ")"
            subprocess.call(["sudo", "kill", "-15", pid])

    kodiproc = ["kodi", "kodi.bin"]  # kodi needs SIGKILL -9 to close
    for proc in psutil.process_iter():
        if proc.name() in kodiproc:
            pid = str(proc.as_dict(attrs=['pid'])['pid'])
            name = proc.as_dict(attrs=['name'])['name']
            print "stopping... " + name + " (pid:" + pid + ")"
            subprocess.call(["sudo", "kill", "-9", pid])


#############################################################################################
# Safely shuts-down the Raspberry Pi

def shutdown():
    print "shutdown...\n"
    subprocess.call("sudo shutdown -h now", shell=True)


#############################################################################################
# Returns True if the 'proc_name' process name is currently running

def process_exists(proc_name):
    ps = subprocess.Popen("ps ax -o pid= -o args= ", shell=True, stdout=subprocess.PIPE)
    ps_pid = ps.pid
    output = ps.stdout.read()
    ps.stdout.close()
    ps.wait()
    for line in output.split("\n"):
        res = re.findall("(\d+) (.*)", line)
        if res:
            pid = int(res[0][0])
            if proc_name in res[0][1] and pid != os.getpid() and pid != ps_pid:
                return True
    return False


#############################################################################################
# Check if the console we read from NDEF Record #1 is valid, by checking against a list of supported emulators

def check_console(console):
    emulators = ["amiga", "amstradcpc", "apple2", "arcade", "atari800", "atari2600", "atari5200", "atari7800",
                 "atarilynx", "atarist", "c64", "coco", "dragon32", "dreamcast", "fba", "fds", "gamegear", "gb", "gba",
                 "gbc", "intellivision", "macintosh", "mame-advmame", "mame-libretro", "mame-mame4all", "mastersystem",
                 "megadrive", "msx", "n64", "neogeo", "nes", "ngp", "ngpc", "pc", "ports", "psp", "psx", "scummvm",
                 "sega32x", "segacd", "sg-1000", "snes", "vectrex", "videopac", "wonderswan", "wonderswancolor",
                 "zmachine", "zxspectrum"]
    if console != "":
        if console in emulators:
            print "NDEF Record \"" + console + "\" is a valid system...\n"
            return True

        else:
            print "Could not find \"" + console + "\" in the supported systems list"
            print "Check NDEF Record 1 for a valid system name(all-lowercase)\n"
            ser.write("bad")  # Tell Arduino there was a cart read error
            return False


#############################################################################################
# Return the path of the emulator ready to be used later

def get_emulatorpath(console):
    path = "/opt/retropie/supplementary/runcommand/runcommand.sh 0 _SYS_ " + console + " "
    return path


#############################################################################################
# Check that the rom is valid by looking for the file, tell the cart slot light green if good, red if bad

def check_rom(console, rom):
    # get full rom path and check if it's a file
    romfile = "/home/pi/RetroPie/roms/" + console + "/" + rom
    if os.path.isfile(romfile):
        print "Found \"" + rom + "\"\n"
        ser.write("ok")  # Tell Arduino the cart read was successful

        return True
    else:
        print "But couldn\'t find \"" + romfile + "\""
        print "Check NDEF Record 2 contains a valid filename...\n"
        ser.write("bad")  # Tell Arduino there was a cart read error
        return False


#############################################################################################
# Return the full path of the rom read from NDEF record #2 on the NFC tag

def get_rompath(console, rom):
    # escape the spaces and brackets in rom filename
    rom = rom.replace(" ", "\ ")
    rom = rom.replace("(", "\(")
    rom = rom.replace(")", "\)")
    rom = rom.replace("'", "\\'")

    rompath = "/home/pi/RetroPie/roms/" + console + "/" + rom
    return rompath


#############################################################################################
# If the cartridge is valid when the button is switched on then we can launch the rom

def button_on():
    if cartok:
        procnames = ["retroarch", "ags", "uae4all2", "uae4arm", "capricerpi", "linapple", "hatari", "stella",
                     "atari800", "xroar", "vice", "daphne", "reicast", "pifba", "osmose", "gpsp", "jzintv",
                     "basiliskll", "mame", "advmame", "dgen", "openmsx", "mupen64plus", "gngeo", "dosbox", "ppsspp",
                     "simcoupe", "scummvm", "snes9x", "pisnes", "frotz", "fbzx", "fuse", "gemrb", "cgenesis", "zdoom",
                     "eduke32", "lincity", "love", "alephone", "micropolis", "openbor", "openttd", "opentyrian",
                     "cannonball", "tyrquake", "ioquake3", "residualvm", "xrick", "sdlpop", "uqm", "stratagus",
                     "wolf4sdl", "solarus", "emulationstation", "emulationstatio"]
        killtasks(procnames)
        subprocess.call("sudo openvt -c 1 -s -f " + emulatorpath + rompath + "&", shell=True)
        subprocess.call("sudo chown pi -R /tmp", shell=True)  # ES needs permission as 'pi' to access this later
        time.sleep(1)
    else:
        print "no valid cartridge inserted...\n"


#############################################################################################
# Close the emulator when the button is pushed again ("off")

def button_off():
    ser.write("ready")
    if process_exists("emulationstation"):
        print "\nemulationstation is running...\n"
    else:
        procnames = ["retroarch", "ags", "uae4all2", "uae4arm", "capricerpi", "linapple", "hatari", "stella",
                     "atari800", "xroar", "vice", "daphne", "reicast", "pifba", "osmose", "gpsp", "jzintv",
                     "basiliskll", "mame", "advmame", "dgen", "openmsx", "mupen64plus", "gngeo", "dosbox", "ppsspp",
                     "simcoupe", "scummvm", "snes9x", "pisnes", "frotz", "fbzx", "fuse", "gemrb", "cgenesis", "zdoom",
                     "eduke32", "lincity", "love", "alephone", "micropolis", "openbor", "openttd", "opentyrian",
                     "cannonball", "tyrquake", "ioquake3", "residualvm", "xrick", "sdlpop", "uqm", "stratagus",
                     "wolf4sdl", "solarus"]
        killtasks(procnames)


#  I check if ES is running here because if it *is* then any running game was launched from within ES
#  and we don't want to quit it when the button is pressed. But if the game was launched from a cart
#  then ES will not be running in the background and we *do* want to quit the emulator.

#############################################################################################
# Set BCM 4 HIGH... the arduino reads this to determine if the Raspberry Pi is running

led = LED(4)
led.on()

# If we do a manual shutdown from within ES then our program will be stopped and the pin
# will return to a LOW state, the arduino can read this and cut the power when appropriate

#############################################################################################
# Assign the NES 'power' button to the button functions
onbtn = Button(2)
offbtn = Button(3)
onbtn.when_pressed = button_on
offbtn.when_pressed = button_off


#############################################################################################
# Assume the cart is not valid until we've checked it in the main loop
cartok = False

# Setup the serial port and tell arduino we're ready (allows us to start with a cart already inserted at power-on)
ser = serial.Serial("/dev/ttyAMA0", 9600, timeout=None)
ser.write("ready")

# Main Loop
while True:
    try:
        line = ser.readline()
        if line != "":
            records = line[:-1].split(', ')  # incoming data looks like: "$$$, $$$, $$$, \n"

            uid = records[0]  # 'uid' is read from the NFC tag, also used for shutdown, reset and cart eject
            console = records[1]  # 'console' is NDEF Record #1
            rom = records[2]  # 'rom' is NDEF Record #2

    except IndexError:
        print "NDEF read error...\n"
        ser.write("bad")  # Tell the Arduino there was a cart read error

#############################################################################################
# Check serial data for a command message in the 1st field
    if uid == "shutdown":
        print "shutdown command received...\n"
        shutdown()

    if uid == "cart_eject":
        print "cart ejected...\n"
        cartok = False

    if uid == "reset":
        print "reset button pressed...\n"
        retroarch_command("RESET")

#############################################################################################
# Check the console and rom data for validity
    if console != "":
        if check_console(console):
            if check_rom(console, rom):
                emulatorpath = get_emulatorpath(console)
                rompath = get_rompath(console, rom)
                cartok = True

The program listens to the serial port to find the console and rom information sent by the Arduino.

We look up the console name in list of valid emulators, then look for the rom to see if there's a file with the correct name stored on the SD card.

If it finds one, then when the power button is pushed down, it launches the emulator and game. If it doesn't then it tells the Arduino to light the indicator in red to show a read error.

In order to manage the power, on boot-up, it will set a GPIO pin HIGH. This is monitored by the Arduino so that it can tell if the Pi is running by checking the status of that pin.

The program also checks the serial port for a shut-down message and will safely shut-down the Pi when it hears one.

This means I can shut-down the Pi normally through software or by long-pressing the 'reset switch' and after it's finished shutting down the Arduino will detect it, and cut the power safely.



3D design:

I've used Tinkercad to design stuff in the past. For this project I'd 'graduate' to 123D Design. It's has a few more features, yet is still simple enough to get to grips with if you've got limited CAD experience like I do.

I started by blocking out the rough shape, transferring my scaled dimensions over to the computer.

I tried to keep as much of the design in proportion to the real NES. But made some concessions with details like the front switches being a bit larger than scale for ergonomic reasons.

One thing I was quite pleased with, is the snap-fit feature I incorporated. Noé Ruiz from Adafruit made a video that shows a really cool way to have a case snap closed.

You can see the little triangle-shaped tabs on the lip between the case halves. They click quite nicely and hold the case together really well, it means I don't have to waste space building in screw posts.

Because of the small design I was going for, I'd have to remove the USB sockets from the Raspberry Pi board in order to include the cartridge slot and keep all the proportions correct.

Since I intended to move two of them to the front anyway this wouldn't be too much of an issue.

For the final case I wanted to use filament match the colours. Faberdashery have a wide range of colours available, and their Monotone Mix Pack looked ideal to match the NES' shades.

Since that filament was a bit more(4x) expensive than the eBay PLA I normally use. I made all my test prints with cheap-o plastic.
Comically, I didn't have a screwdriver of the right size that was long enough to reach all the screws. So I couldn't take my own NES apart to see how the cart slot worked.

From tear-down photos though, I could see the original cartridge latch mechanism would be too difficult to 3D print on a small scale and have work reliably.

After some idle searching of eBay, I uncovered an odd yet perfect solution.

Bin lids...

Apparently the latches on them wear out, and there are people selling cheap replacements on eBay. It turns out they're just about the right size to use as a latch for my cartridge slot.

This will clip into a mount on the bottom of the case and accept a peg attached to the cartridge tray.

It turned out, the spring in the latch itself is strong enough to lift the cart mechanism, and that makes the rest of the design much simpler.

Next... the front switches.

The kind I used, latching push switches, are the same type as the power switch on the original NES. This sort of button has a spring inside and a pin that keeps the switch closed.

The blue plunger has notches that trap an L-shaped pin (you can see the pin through the little window on the bottom) It keeps the switch on until it gets pressed again.

For the power switch, I left the pin in place so I had the clicky on/off feel. For the reset switch I removed it, to make a normal momentary button, just like the reset switch on the original NES.

I printed the rest of the bits of the case to check the dimensions and adjust the model where necessary.
the translucent plastic is hard to photograph
The test case fits everything nicely (although the clear plastic does look a bit weird in photos).




Electronics:


I designed the connections between the Arduino and Pi to use the top ten GPIO pins so I could mount the Arduino directly to the Raspberry Pi using a 2x5 header.

All the electronics would then sit in the case behind the USB ports.
The NFC reader mounts underneath the cartridge tray connected to the Arduino with a piece of flat cable.
There's enough length on it for the case halves to be splayed apart if I need to dismantle the unit and the Arduino 'lump' unplugs from the Pi so I can update the 'firmware'.

I did order some FFC cables and connectors but got impatient waiting for them to arrive and just soldered everything together.

When they do get here though, I might make a PCB to mount it all, but until then I'm happy enough.




3D Printing:


I printed the final case parts using that lovely Fasberdashery filament. 'Storm Grey' for the bottom half, 'Architect's Stone' for the top, with trim pieces and the cartridge tray in 'Classic Black'.

Printing all the parts took around 6.5 hours with all the colour changes.


Assembly:

I attached the black pieces with super-glue and apart from the screws holding the Raspberry Pi itself in the case, everything else snapped together.

The wiring for the switches wraps behind the cart slot and the NFC cable needs to be folded up into the roof of the case to allow it to move freely.

The front lid hinge is a couple of short lengths of filament. I printed a cosmetic piece to cover the opening and match the lines on the original NES.



The cartridges:

I'd make these at the same 40% scale as the rest of the case. I simplified some of the features but kept as true as I could to the originals, with indents for the labels on the front and back of the cart.
They're designed to be printed in two halves, this meant no support material was needed and both visible sides would have a consistent surface finish.


I need more practice shooting time-lapse :/

The carts are lined-up with little pegs and super glued together with an NFC tag embedded in the middle.

I printed the labels on slightly thicker than normal, 120g/m² paper. I 'laminated' them with clear packing tape and stuck them in place with super glue.




Controller:


Seeing my little replica next to it's full-scale counterpart, I couldn't help thinking about the controller.

The NES controller is a truly iconic piece of design. The silhouette alone pretty much represents video-games entirely by itself. I wanted to make one.

So I fired-up 123D again and plugged some scale measurements into it. Serendipitously, an Arduino Pro Micro knock-off, fits perfectly inside a 40% scale NES controller.
10 seconds of googling, and I found this library. I couldn't resist if it was going to be that easy...

/************************************************************************************
*             NESPi NES Controller USB Gamepad v0.1 [mike.g|june2016]               *
*                                [daftmike.com]                                     *
*************************************************************************************/
// Adapted from 'JoystickButton' example
// by Matthew Heironimus
// 2015-11-20
// https://github.com/MHeironimus/ArduinoJoystickLibrary

#include <Joystick.h>

void setup() {
  for (int i = 2; i < 10; i++) pinMode(i, INPUT_PULLUP);  // set pullups on pins 2-9 for the buttons
  Joystick.begin();       // initialise Joystick library
}
const int pinToButtonMap = 2;      // start from pin 2
int lastButtonState[8] = {0, 0, 0, 0, 0, 0, 0, 0, 0};   // last state of the button

void loop() {

  for (int index = 0; index < 8; index++)  // go through the loop 8 times, once for each button
  {
    int currentButtonState = !digitalRead(index + pinToButtonMap);  // read the pin and store in variable
    if (currentButtonState != lastButtonState[index])    // if the button state has changed
    {
      Joystick.setButton(index, currentButtonState);    // write the button state to the joystick
      lastButtonState[index] = currentButtonState;    // save state to compare for the next loop
    }
  }
  delay(50);
}

Just 20 lines of code and the software was done. Since the buttons would get mapped in RetroPie anyway, it didn't matter which key presses the controller generated. This made the program very neat and tidy.

At such a small scale, finding room for everything in the controller would be tricky. I did have some small tactile switches on hand that would work, just 1.5mm high.

To accommodate them, I etched a simple little PCB to mount the buttons to the Arduino. This was easier than chopping up bits of perfboard to try and get the right spacing laid out.

Not the prettiest thing. To keep the proportions correct I even had to cut legs off some of the switches so it's definitely a bit ugly on the inside.

Initially, I transferred some graphics to the controller and they looked great, but I accidentally damaged the finish with an acetone thumbprint that marked the surface underneath.

I didn't have any more 'Architect's Stone' filament to make a replacement so I printed the graphics on sticker paper, laminated it with packing tape and used that to cover it up.

The USB plug cover was modelled after the shape of the original NES connector and recessed so it'd sit flush with the case.

It's even surprisingly playable. I won't be doing any marathon playthroughs with the dinky little pad, the tiny buttons are a little stiff, but it is perfectly serviceable and turned out to be one of my favourite parts of the build.




Conclusion:


This project took longer that I first thought, but I enjoyed it immensely. It sharpened up my Arduino coding, I learned some Python and used Linux properly for the first time.

I also really improved my 3D printing ability, both in CAD and the printing process itself.

In the end I'm very pleased with how this project turned out. I met all of my initial goals and finished with a cool, functional piece of hardware that's pretty unique*.

the finished article...




* Addendum:


D'oh. I've been working on this for weeks, and even wrote-up most of this post before this was announced...

I was thinking of making a few more units to sell. Oh well never mind, gg Nintendo.

Mine's a bit smaller than Ninty's though ;)

*Update videos with some more details:



162 comments:

  1. make kits and sell the kit so i can make one myself! lol id buy that

    ReplyDelete
    Replies
    1. +1 for having a kit to make. Would love to make this regardless of also wanting the Nintendo one.

      My inner childneeds these :D

      Delete
    2. I too would go for a kit. :D

      Delete
    3. +1 for a kit. Without the raspberry pi.

      Delete
    4. PLEASE I implore you to make kits available for sale!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      I would gladly buy one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

      Delete
    5. Please let me know if you decide to sell a complete system. Badwolf2014inc@gmail.com

      Delete
    6. I agree please sell these in kits. or release the cad files so we can print our own.

      Delete
    7. Make the kit, or release instructions and drawings so we can copy. I wanted to do the same thing but would happily clone your design. I've been looking for a NES case for the Pi but only found 3D-printed stuff. Awesome project, great work!

      Delete
    8. I can't afford an investment as big as a 3d printer or the tools needed to put all the technical parts together (at least not for a single project that won't bring me any income) but I would pay handsomely for a kit for this! to get the parts premade and just be able to piece it together with my own hands, would be a dream come true!

      +1 for a kit!

      Delete
    9. I want to buy a kit as well. I'd love to put it together with my son. Also if there is anyway I'd also like to have a normal size controller to play longer with him. Want this so bad!

      +1 for a kit

      Delete
    10. Would buy one from you. Nintendo had us limited to 30 games and don't even have a Dragon Warrior/Quest game on it... I would buy a kit and the complete collection of Dragon Warrior on mini cartdridge haha :).

      Delete
    11. Would totally buy this if it were available.

      Delete
    12. This comment has been removed by the author.

      Delete
  2. Would absolutely buy a kit if one were available. Amazing work

    ReplyDelete
  3. you should totally make a kit and sell it! oh, btw, what other emulators can the raspberry Pi run?

    ReplyDelete
  4. What would it cost if you ever sell one? I like this better than ninty' effort

    ReplyDelete
  5. I'd buy one, with a couple of spare cartridges :-)

    ReplyDelete
  6. This is seriously impressive. If you ever plan on making more to sell, please let me know.

    ReplyDelete
  7. May I ask if you put your schematics up for your prints? I'd like to build one of these guys

    ReplyDelete
  8. How much would you sell one for? I think this is better than Ninty's

    ReplyDelete
  9. Seconding the inquiry about your 3D print files... I could do all the rest of the work, but while I've got access to the printer, the precision modeling is probably beyond me at the moment.

    ReplyDelete
  10. Thirding the inquiry regarding the 3D print files. Would love to use them to build the case!

    ReplyDelete
    Replies
    1. I'm down with that also, already have a distorted one this one is a work of art hope you share.

      Delete
  11. Far superior to Nintendo's effort, since one could add games if they want, and even emulate other consoles (or use it as a computer), since its a Raspberry Pi. I'm sure you'll still find plenty of buyers if you sold these, or even better sell kits with instructions.

    ReplyDelete
  12. Make them PLEASE. I want yours. Those tiny carts make it. I am willing to purchase it immediately.

    ReplyDelete
  13. I can see you put way more thought into this than Nintendo did. You sir have a customer sitting here, waiting, and ready to buy one directly from you if you do decide to make a kit for this!

    ReplyDelete
  14. Great project Mike, I'd like better to have this than nintendo's effort. Do you plan to release the 3D files?

    ReplyDelete
  15. Please i want to buy one.. alcon.621@gmail.com

    ReplyDelete
  16. I prefer this over the nintendo one, I want one please. xavier.mike@gmail.com

    ReplyDelete
  17. Want

    How Much ;)

    ReplyDelete
  18. Any chance you'd share the model for the case? I was going to do one myself, but your design is fantastic. Great work either way, this is quite impressive.

    ReplyDelete
  19. What paypal account do I send my money to?

    ReplyDelete
  20. Hey man, make a facebook page...your blog is awesome.

    ReplyDelete
  21. Please please do the 3d printing for me. I've been looking for a case just like this for a long time I hate how distorted the others have become.

    ReplyDelete
  22. This is absolutely awesome! Amazing work.

    ReplyDelete
  23. Please let me know if you decide you want to sell this. I would happily buy it :)

    ReplyDelete
  24. This is absolutely awesome! Amazing work.

    ReplyDelete
  25. Great job, please sell kits¡¡¡¡¡or guide to make my own.

    ReplyDelete
  26. I would be interested in buying one as well!

    ReplyDelete
  27. If you made a kit... I'd buy a few.

    ReplyDelete
  28. Oooh. I'd go in for a kit of this. It mimics my interest in making a Raspberry Pi and NFC powered tape deck with custom playlists.

    ReplyDelete
  29. Let me know if you make a kit for the pi3

    ReplyDelete
  30. I would be interested in buying a kit. (i would skip the controller though) What could you do for $60.00?

    ReplyDelete
  31. I would also be interested in a kit. tlhme53atyahoo.com

    ReplyDelete
  32. Would seriously buy this in a heartbeat - not at all interested in the official Nintendo one due to the lack of upgradability. If you do decide to run a few please sign me up - alistairkirkland[at]gmail.com

    ReplyDelete
  33. Looking through your Python code I noticed that there were redundant lines. If you would be willing to post the code on GitHub I can help clean up the code and submit a pull request.

    ReplyDelete
    Replies
    1. haven't posted anything to GitHub before so I'm not too au fait with how it works, just signed up and started a repository:

      https://github.com/imdaftmike/NESPi

      Delete
    2. Cool, I don't know why it listed me as Anonymous for my first post, but I'll go through and help clean up the code this weekend.

      And because I forgot to mention it in my first post.. Awesome job with the project. As soon as my 3D printer arrives I may try my hand at one.

      Delete
    3. I forgot to let you know earlier, I've submitted a pull request with the changes. There were some other things I'd like to go back and double check but unfortunately I don't have all of the hardware I would need, like the NFC reader lol

      Delete
  34. I'd love to own one of these. Any plans to reproduce and sell?

    ReplyDelete
  35. Yes I think you should sell these. I'd say the demand is high enough. The price point is what important. Please reply to your commenters.

    ReplyDelete
  36. If you do decide to run a few please sign me up - m.i.zafar[at]gmail.com

    ReplyDelete
  37. That is impressive and cool as hell. You sir are badass! Your version is much more desirable. I echo the desire to have one of these. Nicely done.

    ReplyDelete
  38. I think you can clearly see you've got something on your hands man. If you want to. There are a lot of others for sale, but yours by far is the best quality. Please let me know if you are up for it. warfidem@gmail.com

    ReplyDelete
  39. This is pretty sweet, Mike! In all honesty, I think the learning process from all this would make it a perfect project for those of us starting to make things with 3D printing, arduino and the like. If you ever feel like publishing the 3D print files, I'd love to try and make my own here in Barcelona :D

    ReplyDelete
  40. Hi Mike,
    This is awesome!
    Hit me up if you decide to make a tutorial.
    I'd be willing to pay for it :D

    Cheers from Amsterdam!

    ReplyDelete
  41. I was going to do this exactly as you did. Minus the NFC stuff. Just needed to put some time in modeling the case. Was even going to do the mini carts as well - just non functioning. But you beat me to it and clearly went the extra mile. Are you planning on adding the 3d files to the git repository? I would much appreciate not having to design it from scratch my self, since you have already done such a good job. Thanks

    ReplyDelete
  42. Make the controller full size and games built in. Maybe add games for SNES and N64. Pitch it to nintendo. You will sell many. My money is ready to buy this...

    ReplyDelete
  43. Wow! I am so soo waiting to buy those if you'd sell it! Or i'll try to make my own

    ReplyDelete
  44. How much would you charge for one of these?

    ReplyDelete
  45. I need this in my life! Please make these kits!

    ReplyDelete
  46. Just to add my voice to the chorus, please sell these! Whether as an easy-to-assemble kit or pre-made, I would buy it in a heartbeat! It's much better than Nintendo's offering, since it can play many systems and is upgradeable and whatnot. Though if you do, I'd personally prefer one utilising the RPi 3, though would still buy it if it used an RPi 2.

    And I'd also buy some of those cartridges too! Perhaps a generic one for any game, and then a few of the classics too, if they were available. :)

    ReplyDelete
  47. Don't make a kit. As you said you enjoyed the project and learnt a lot from doing it. If any one else wants one they should put in the same amount of effects as you did. Not to mention that Nintendo would sue you ass off if you tried to sell these.

    ReplyDelete
  48. This comment has been removed by the author.

    ReplyDelete
  49. If you don't want to sell them, can you put the plans online so others can print them? Great work it looks amazing and is getting me thinking how I can use NFC for mine.

    ReplyDelete
  50. Take my money. Awsome work. I was going to hack the new nintendo comming out but damn yours is way better

    ReplyDelete
  51. Just let me know how much and im in. Great work. John.doidge82@gmail.com

    ReplyDelete
  52. I want one. Please, email me with the prize: luismiguelfb@hotmail.com

    ReplyDelete
  53. Work of art, I also echo the desire to be able to share the stl files so we can all try to take on this challenge and enjoy your masterpiece.

    ReplyDelete
  54. Make it a kickstarter ;) then you will for sure sell many units.

    ReplyDelete
  55. Great project! Good trick to use NFC and opevt together retropie. Congratulations!!!

    ReplyDelete
  56. Absolutely amazing work! I would definitely be interested in a kit. Judging by the response here I think you'd sell quite a few! And a big thank you for going in to such great detail in this blog. A really good read :-)

    ReplyDelete
  57. I liked your work you did to the raspberry, you sell the product as finished samples

    ReplyDelete
  58. Great write-up mike. I'd love the stl files. Would you be willing to release them on thingiverse under the non-commercial license?

    ReplyDelete
  59. 3d plans available for download?

    ReplyDelete
  60. Quiero una cual es su precio?

    ReplyDelete
  61. Please please please post these 3D files. This is the best Nintendo case design I've seen. It's not overly complicated and it works very well!

    ReplyDelete
  62. In line waiting for the 3D files ;-)
    You did a great job !!

    ReplyDelete
  63. Your work was amazing! I would absolutely love one of these. If you consider selling them, please let me know!
    arturo.concepcion@gmail.com

    ReplyDelete
  64. I also want one! <3 carlost.tdf@gmail.com

    ReplyDelete
  65. Wow!!! O_O That's brilliant! Sod the Nintendo thing, I want YOURS!! Pleeease offer a kit, I instantly would buy it for sure!!!

    ReplyDelete
  66. I'm interested in buying your model as is the price and where can I buy

    ReplyDelete
  67. how to buy this!?....please!!! i love this job!!

    ReplyDelete
  68. I'd be willing to pay good money for one of these if you do decide to make more! Kiwisoup@gmail.com

    ReplyDelete
  69. If you plan to make and sell these as a kit, I will gladly buy one. If not, I'd be willing to pay you for the print files. Thanks!

    ReplyDelete
  70. Amazing project. I have been thinking about doing the exact same thing for months. But have not been able to work out the NFC side of things. What kind of arduino are you using? Is that a custom board underneath? Would love to try to replicate your work. But I cannot quite figure out what you did there;-)

    Anyway, great writeup and great work. Love it when people include their code, so that others might have a look, and learn something in the process:-)

    ReplyDelete
    Replies
    1. Also, I have been thinking about using a cheap usb nfc reader/writer. Would that even work?

      Delete
  71. Do you have the 123d file of the nes ? Impressive !

    ReplyDelete
  72. I would really like to own one. I can of course pay you. Hope it doesn't cost me a bomb but i would love to have one with some games. Please. My email is keithh8r@gmail.com if you would be making any more. Thanks a lot and such fantastic work.

    ReplyDelete
  73. This is one of the best Raspberry Pi blog posts I have ever read. Great project, great information, great photos.

    ReplyDelete
  74. How is the power to the RPi being managed by the Arduino? From the look of the photo the USB power plugs directly into the RPi, if that's the case how does the Pi not power on as soon as its plugged in and how does the Arduino cut it off?

    ReplyDelete
    Replies
    1. Good eye... I removed the fuse F1 from the Raspberry Pi board and intercepted the 5v from the micro-USB input and routed it to the Arduino. It then controls the 5v to the RPi with a high-side MOSFET switch.

      Delete
  75. I would definitely buy an already made one, but a kit would also do the trick. Great job and an amazing ideia.

    ReplyDelete
  76. Hi Mike, It would be really awesome if you would release your design on thingiverse, but if not, I would totally be willing to pay for the design as well. This is by far the best nes pi case I have seen.

    Another possible option would be to put in on shapeways.com so people can get it printed, but then still offer the stl's for free. Anyway, major props to you for this awesome project.

    Hopefully you will release the stl's soon so I can build my own. I will totally be contributing back to the github python code as soon as I can get the time to start building the hardware to use it on.

    ReplyDelete
    Replies
    1. Just saw your update. Cheers mate. Looking forward to the 3d design files when you get around to publishing them.

      Delete
  77. Like so many above me I'd buy a kit or the full thing if you were willing to do it. I love the idea of the NES mini but I like yours so much more because of the ability to add my own games outside of the preloaded on the mini as well as being able to emulate other consoles.

    ReplyDelete
  78. Fucking awesome, i need this!!!!

    ReplyDelete
  79. OMG, I need this so bad to replace my decaying NES from 1986.

    ReplyDelete
  80. Hello! Let me start by saying that this build is fantastic! Great work! I'll also throw my hat in the "make a tutorial" ring because this is fantastic!

    Seeing your build really made me want to make a mini SNES, and after watching your update video, it makes me happy to see you have the interest as well. Was curious if you wanted any help at least with the NA version. I would love to help out in some way. (coding skills are not perfect, but my modeling skills are very good! =D) Let me know!

    ReplyDelete
  81. Great work! Would love to build my own. Please do a build guide and kit for the electronics! That would be fantastic.

    ReplyDelete
  82. I would love one of these too. How much would you charge to make one and ship it to California. rejhill@hotmail.com

    ReplyDelete
  83. I'd gladly pay for a kit!

    ReplyDelete
  84. Sounds like Nintendo stole your idea and did a half ass job compared to you. This is so much better than what they are releasing. The only thing I'd want would be a full size controller.

    ReplyDelete
  85. Sounds like Nintendo stole your idea and did a half ass job compared to you. This is so much better than what they are releasing. The only thing I'd want would be a full size controller.

    ReplyDelete
  86. I would ask for the 3d files to print the pi case. And the cartridge. Only to keep the lid open and show one inside.

    ReplyDelete
  87. Thanks for this webpage about it. I watched your Video of it super job.

    Did you know super glue will not stick after about 10 years! People keep using it. I guess hot glue would be better but not sure.

    Thank you for sharing this.

    All you need to do is tell other how to make it in a nice step-by-step way.

    ReplyDelete
  88. Great job you did here !
    Do you plan on sharing the 3D model ? Maybe upload it to thingiverse ?

    ReplyDelete
  89. Excellent build. I am impressed with how well thought out this is. I built a similar project of the SNES with a raspberry pi 2 running retropi and mine turned out really nice but its nothing more than a case for the pi. A friend pointed me to your video and said i should check it out. I would love to see a complete build guide for this including a parts list and your custom code for the arduino. However you decide to proceed, I tip my hat to you.
    Norm

    ReplyDelete
  90. Amazing build! I would buy that without missing a beat. Very cool. I love the carts.

    ReplyDelete
  91. Yes please post the files and a parts guide. Your work is incredible. Also, yes id like to see how you handle a snes case.

    ReplyDelete
  92. This is a fantastic build! I appreciate the time you've spent creating this, as well as the time spent documenting it for us to drool over. I have a few questions I hope you are able to answer, given the flood of traffic and comments. Thanks for sharing the video and code that you have so far!

    1.) Do you have a compiled BOM? (bill of materials) I'm interested in seeing what things roughly ran to get a budget in mind for attempting this as well.

    2.) Do you have a template for the cartridge labels? They turned out extremely well.

    3.) This is probably the biggest request you've been getting... I'd love to get a copy of the .stl or .obj files. Like others have asked, have you considered uploading the a site like thingiverse? I know you put some time into this, and would be willing to "license" the files from you. My modelling skills are not up to snuff, I'm great at printing and assembly though...

    Again this is so cool. Even in light of the NES Classic coming, I'm still really, really wanting to make one of these. Congrats daftmike, this is well done!

    ReplyDelete
  93. Saw the updated video. If you can, please post the 3d files for the cases and carts. I actually would love to try building one my self and even pushing it to see if I can't get a zipped full games stored into an RF Tag or similar tech (I do have coding/hw skills so I can resolve that end of it)

    ReplyDelete
  94. Please make a kit out of it or sell the cad file. I'm willing to pay for it!!!

    ReplyDelete
  95. I can buy a kit too, i'm so interested on making this project. :D

    ReplyDelete
  96. Please let me know if you would sell a finished product. My email is loceysgw@yahoo.com i was gonna get a nes classic but i'd much rather get this if possible

    ReplyDelete
  97. same. Let me know much would you sell for a finished product. I don't need the controller, just the set alone and build with raspberry pi 3 if possible. My email is zenus81@yahoo.com.

    ReplyDelete
  98. I like buy it, please. This is a dream. Please contact me, if u like sale it.

    argonien@gmx.de

    The NES was my first console and this is the best.

    I will buy it,please.

    Greats from Germany

    ReplyDelete
  99. +1 For a Kit without Pi! Amazing work

    ReplyDelete
  100. I seriously want to buy one from you!!!

    ReplyDelete
  101. OMG. It 's Amazing. I'm traveling on time. Old fantastics Memories. I will buy one if is possible.

    ReplyDelete
  102. For the love of god, sell kits!

    ReplyDelete
  103. Yes, sell it :). Kickstart it if possible.

    ReplyDelete
  104. C'MON!!! Sell the kid now before Nintendo!

    ReplyDelete
  105. Your version of Mini-Nes is better than the official, because of the USB controller ports AND the cartridges. It would be amazing if nintendo could release classic games on tiny cartridges, people certainly would buy lots of it.

    ReplyDelete
  106. How much would you charge to build one - I can supply the raspberry pi :)

    r934@rocketmail.com

    ReplyDelete
  107. Hello daftmike! Your work for your Mini NES is pure genius! Can you make a portable version of your Mini NES? I know there has been lots of portable NESes nowadays, but your cartridges is about the same size as the Game Boy Color cartridges, only slightly bigger, and they can work well for portables.

    ReplyDelete
  108. Hey Mike, I'm completely new to 3d printing. I'm looking into getting a printer to make this my first project. How do I see what size the print will be to make sure I get a printer large enough? What is the minimum print area this project would require?

    ReplyDelete
    Replies
    1. The largest part of the print would comfortably fit inside a 120 x 100mm build area.

      Delete
  109. Thanks for the work you have put into this blog

    ReplyDelete
  110. Seem's I'm just adding to the chorus here, but I'd buy one of these if they were for sale. Doubtful I have the skills or access to the equipment to create on on my own. Wondering what the legal ramifications would be in selling something like this? Without the Rasberry Pi, seems it's just another case. But in this sue happy world, wonder if Nintendo would get peeved about something like this for sale. In any case, count me in if you ever decide to market these things.

    ReplyDelete
  111. This comment has been removed by a blog administrator.

    ReplyDelete
  112. Just ordered the kit and I can't wait to get everything put together. Got the case already printed and have the raspberry pi 3 ready and waiting with retropie. Your kit is cheaper than buying the parts individually, plus I don't have to spend the time soldering everything together.

    Do you plan on making your tiny nes controller available for people to make? I think that would be awesome!

    ReplyDelete
    Replies
    1. That's great Tom, hope you enjoy it.

      A couple of people have asked about the controller now, so I might make a mini-kit for it once the main project is finished.

      Delete
  113. does this setup work with any system roms or just NES roms?

    ReplyDelete
    Replies
    1. Nes snes game boy it works with all systems

      Delete
  114. où puis-je acheter votre kit la France a besoin de toi XD please!!!!!!!

    ReplyDelete
    Replies
    1. consulter cette page le lundi: http://www.daftmike.com/p/nespi-electronics-kit.html

      Delete
  115. Hi greatz Work
    Im from Germany pls make a Kit ��

    ReplyDelete
  116. I would do the same thing but with a USB floppy drive. how did you issue a software? thanks

    ReplyDelete
  117. J'ai fabriquer pratiquement le meme systeme mes avec un lecteur disquette au lieu de rfid.
    Envoyer moi un email pour en savoir plus
    jeromest_gelais@hotmail.com

    ReplyDelete
    Replies
    1. Do you have some tutorial in a blog? World be nice!

      Delete
  118. Bonjour,

    Ou acheter le KIT ?
    mickael.heintz@gmail.com

    ReplyDelete
  119. HOLA. QUIERO UNA. PERO CON USB. NO QUIERO WIFI DIREC. MI GMAIL ES: jasidelviento@gmail.com
    TENGO UN AMIGO QUE HABLA INGLÉS. ASÍ USTED ME DICE COMO PUEDO COMPRAR SU CONSOLA. SOY DE ESPAÑA.

    ReplyDelete
  120. Shut up and take my money!!! I would buy this instead of Nintendo's... That's amazing!!! Please, sell them in eBay, I need it!!!

    ReplyDelete
  121. I created a facebook page for us to coordinate further discussion on this project.
    https://www.facebook.com/groups/miniNESbuilders/

    I recommend posting questions there.

    ReplyDelete
  122. Can I buy just the case?

    ReplyDelete
  123. I want to buy too. just name the price

    ReplyDelete
  124. It's a good idea to print such things! )) I want to try to print them too! Do you like to play roms? Yesterday I found site with free roms https://romsmania.com/ I have already downloaded some great games from it.

    ReplyDelete