SNIS console Notes

The basic idea is that we can run many (but not all) of the Space Nerds in Space bridge stations on a Raspberry Pi, and have an arduino connected to the Pi, and connected to the arduino can be a load of potentiometers and switches and LEDs. These potentiometers and switches can be logically connnected to buttons and sliders within the game. The arduino can poll the state of the switches and potentiometers and report changes to the game via the USB serial back to a process on the the raspberry pi which can then feed these changes into the game via the interface provided by snis-device-io.h. Likewise, LEDS for warning lights, etc. can be controlled from the game via USB serial to to the arduino. In this way we can build a physical console for each of the stations to make the game seem a little more like a spaceship and little less like a computer game.

Why Arduino? Because arduino is accessible and open source. It's possible other people besides me may want to build something like this, and Arduino is the easiest, most well-known and popular thing in its class, and most likely to be something that other people will be able to work with.


Thu Feb 20 15:44:52 EST 2020 Received shipment of 200 white LEDs, 120 tactile switches, 5 12V power supplies, and 4 power strips,
Sat Feb 15 09:31:09 EST 2020

Some notes about the shift register:


       ---U---
   Qb -       - Vcc
   Qc -       - Qa
   Qd -       - SER   (DS)
   Qe -       - OE    (DE)
   Qf -       - RCLK  (ST_CP)
   Qg -       - SRCLK (SH_CP)
   Qh -       - SRCLR (MR)
  GND -       - Vcc
       -------

  Qa-Qh are outputs.
  OE is Output Enable.  It must be 0v to enable outputs. (tie to ground).
  SRCLR is Shift Register Clear, which clears the shift register
        when low.
  SER is the serial data input.
  SRCLK is the storage register clock
  RCLK is the register clock. I think this is a latch which makes this inputs appear
       on the outputs.  I *think* you can clock in 8 bits via SER and rising edge of
       SRCLK, then clock RCLK (rising edge) to have the outputs change all at once.
  SRCLR clears the shift register if low. I think I can just tie this to high.

Here is a circuit diagram (no guarantees of correctness):


Sat Feb 8 10:00:38 EST 2020

Got my aviation style 3d printed switch case thing working pretty well. Put it on Thingiverse.

The LEDs I'm using have a forward voltage of 3.0 to 3.2V. Current should be 15-18mA, and the power supply will be 12V DC. So for resistor, I need:

        R = (Vs - Vf) / If
          >= (12 - 3.2) / 0.018
          <= (12 - 3.0) / 0.015
          = 488.8-600 Ohm

    power = (12 - 3.0) *  0.018
          = 0.1628W (so, 1/4th watt resistor).
That's for 1 LED, for 2 LEDs in series:
        R = (Vs - Vf) / If
          >= (12 - 3.2 - 3.2) / 0.018
          <= (12 - 3.0 - 3.0) / 0.015
          = 311-400 Ohm

    power = (12 - 3.0 - 3.0) * 0.018
          = 0.108W (so, 1/4th watt resistor).
So, for single LED, I need some 600 Ohm 1/4W resistors, and for double LEDs in series, 400 Ohm 1/4W resistors.

Testing this out, it might be a little bright, so might need to up the resistor values, or put another resistor in series with all the LEDs to drop the voltage down a bit. Experimenting, 5V with two LEDs just barelly turns them on, 6V turns them on dimly, then the brightness ramps up as you crank the voltage up to 12V. Probably 8 or 9V is about right.


Sun Feb 2 09:13:43 EST 2020

It seems that powering the Arduino via the Raspberry Pi's USB is fine, however, there's not a lot of current available, so I will need to have another 5v power supply for powering LEDs.

For switches, the lighted Apollo mission type switches are called Tellite switches and they are prohibitively expensive. However, I might be able to come up with a reasonable facsimile using some cheap LEDs, laser cut acrylic and laser printed paper labels to fit over some cheap push buttons.

It seems I'm not the only one with approximately this idea:

Here is the pushbuttons design on thingiverse. Looks like he deleted the design files, but maybe something here: https://www.tinkercad.com/things/fQeSDCBttU3-push-buttons. However, I'd want to design my own anyway with OpenSCAD.


Sat Feb 1 11:04:55 EST 2020

Going through the screens, here are the switches and pots needed:

  1. Navigation:
  2. Engineering:
  3. 6 Damage Control (combined with engineering):
  4. Science:
  5. Comms

Totals:


Fri Jan 31 10:35:58 EST 2020

Was talking with Rob last night at HackRVA, and we are going to build a vacuum forming machine. This should help with building the cases for the consoles. I have a few ideas about how to paint them. One idea, vacuum form them from clear PETG, then paint the inside with silver paint. Should look like mylar, more or less. Not sure I like that idea. Another idea, put some HVAC tape on select edges, paint with black, dark gray, or hammered metal, then sand off a bit to expose some of the silver HVAC tape. I think I'll probably do the latter method.


Wed Jan 29 10:23:41 EST 2020

I changed the protocol used over the serial USB so that the '#' is replaced by the first letter of the station, so 'E' for engineering, 'C' for comms, 'W' for weapons, 'S' for science, 'D' for demon, 'N' for navigation. Only engineering is implemented yet. I'm using a #define to control which station the code compiles for.

Ordered 20 ULN2803 darlington arrays to drive LEDs from amazon, should be here in 2-4 weeks. Ordered some shift registers and male pin headers from futurlec, who knows when those will arrive. (I noticed there are some male pin heads lying around HackRVA though, so no need to wait for those, ha.)

Looking into building a vacuum forming machine to use for making the console cases.


Sat Jan 25 19:38:29 EST 2020

Made some progress, there's a new program in the space-nerds-in-space repo called snis_arduino that reads from the arduino and passes along commands from the arduino to snis_client. I updated the program which runs on the arduino itself (snis-console.c.ino) so it actually works. The main change I made was to switch to a text protocol from binary. This avoids de-syncing as I can look for a newline to delimit the commands. Now the commands from the arduino to the host (raspberry pi) are of the form: "#xxx=yyy\n", where xxx is the input number (0 - 31) and yyy is the value for that input. The values are only reported to the host if they differ from the previous sampling by more than 3.

Another change I made on the host side (snis_arduino) has to do with the problem I was seeing in which it would read a little bit then quit upon encountering EOF. It turns out that reading from /dev/ttyACM0 is apparently non-blocking, despite not opening it with O_NONBLOCK, which sort of surprises me. So I changed the code to simply wait for a few milliseconds and try again upon encountering EOF, and this seemed to make it work.

Video here: https://www.youtube.com/watch?v=51ljGNx3px4.


Wed Jan 22 11:36:04 EST 2020 Here is rough drawing for a circuit for a station. There are two 16 channel multiplexers allowing for 32 potentiometers or switches. The channels on the multiplexers are not selected independently, but in parallel. Two analog inputs on the arduino sample one channel from each of the two multiplexers.

On the output side, two daisy chained shift registers allow up to 16 LEDs to be controlled. Likely I will need to add NPN transistors to drive each of the LEDs to avoid drawing too much current from the shift registers.

Pseudocode for the arduino will be something along these lines:


	static int new_value[32] = { 0 };
	static int old_value[32] = { 0 };
	static int led_status[16] = { 0 };

	setup()
	{
		Set up 4 digital outputs D4 thru D7 for selecting the multiplexer channels.
		Set up 2 analog inputs for the multiplexer signals.
		Set up 3 digital outputs for the shift register controls
		set up interrupt handler for incoming serial data
	}

	select_multiplexer_channel(int n)
	{
		D4 = i & 0x01;
		D5 = (i >> 1) & 0x01;
		D5 = (i >> 2) & 0x01;
		D5 = (i >> 3) & 0x01;
	}

	sample_inputs_from_multiplexer(int new_value[])
	{

		for (int i = 0; i < 16; i++) {
			select_multiplexer_channel(i);
			new_value[i] = read_multiplexer(0);
			new_value[i + 16] = read_multiplexer(1);
		}
	}

	transmit_changes(new_value, old_value)
	{
		for (i = 0; i < 32; i++) {
			if (old_value[i] != new_value[i])
				transmit_value(i, new_value[i]);
		}
	}

	update_led_status()
	{
		/* Shift LED data out to shift register */
		for (i = 0; i < 16; i++) {
			set DS = 0;
			set ST_CP = led_status[i];
			set DS = 1;
		}
		set DS = 0;

		/* Latch LED data (need to double check this is how it works) */
		set SH_CP = 0;
		set SH_CP = 1;
		set SH_CP = 0;
	}

	serial_interrupt_handler()
	{
		/* still need to work out whatever the protocol is for LED data */
		/* Could be just pairs of bytes. */
		get_character_from_serial()
		decode_character();
	}

	loop()
	{
		sample_inputs_from_multiplexer(new_value);
		transmit_changes(new_value, old_value);
		memcpy(old_value, new_value, sizeof(old_value));
		update_led_status();
	}