NGALAC/Subsystems: Difference between revisions

From Noisebridge
Jump to navigation Jump to search
Rando (talk | contribs)
No edit summary
 
(39 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Games]]
[[Category:Game]]
{{nga}}
[[Category:Maker Faire]]
[[Category:Maker Faire]]
[[Category:NGALAC]]
 
 
----
----
== Subsystems ==
[[File:Component-Diagram.png|center|640px]]
== Power ==
== Power ==
[[File:Power_Connections-final.png|center|none|480px]]
=== Streaming PC ===
=== Streaming PC ===


'''BIOS setting for Auto-on with power-on (e.g. from switch)'''
'''BIOS setting for Auto-on with power-on (e.g. from switch)'''


[[File:ngalac_bios1.png|none|340px]] [[File:ngalac_bios2.png|none|340px]]


=== Audio ===
[[File:ngalac_bios1.png|left|center|border|340px]] [[File:ngalac_bios2.png|none|center|border|340px]]


Gainclones are a DIY version of a $3000 audio system called the GainCard. 


NGALAC possesses a LM3886TF based dual supply amp which requires a split rail +28/-28 DC supply
== Audio ==


[https://www.amazon.com/LM3886TF-Amplifier-BGEKTOTH-Stereo-Assembly/dp/B07BD2V5HL/ref=sr_1_15?ie=UTF8&qid=1521921616&sr=8-15&keywords=LM3886tf Amazon Link]
[[File:Audio-system.png|center|480px]]


[[File:Ngalac_audio_amp-r.png|none|thumb|LM3886TF based gainclone amp]]
== Electrical ==


* Ground everything and very well, especially anything the human touches.


'''Example DIY circuits which are easy to build with clear instructions'''
== Control Model ==
[[File:user-experience.png|center|480px]]


[http://www.decdun.me.uk/gainclone6.html Example Circuits]


[[File:snub_reg_psu.png|Snubbed regulated PSU]]
=== Start/Stop streaming ===


[http://www.decdun.me.uk/gainclone_psu.html Example PSU design]
The streaming PC uses OBS to stream, and there is a python websockets library which can control it. This library and a serial command interface known as CmdMEssenger is used to communicate with an Arduino Mega so the Mega can indicate signals to control OBS through a small python script. CmdMEssenger implements a messaging protocol to trigger functions via commands sent over Serial.


<pre style="color: red">DIY PSU price is very high, will compare to purchase options</pre>
The Arduino Mega is effectively a slave to a python server on the streaming PC.  The Arduino will set and clear bits in an array which is communicated to the streaming server via the server polling the Mega.  The server is continuously polling the Mega and performs actions based on it's state and the information in the status array.


<pre style="color: red">Using computer PSU may be possible after boosting +/-12 to +/-28, however, current on -12V line may not be enough to rate maximum wattage</pre>
A user pushed a green button on the cabinet front panel to start (or stop) streaming.  The Mega debounces and latches the button press and sets status bit 11.  The stream server reads this bit which determines is a button press occurred.  If the machine is streaming, the steam will be stopped (and the scene in OBS changed to "Not Live").  If the machine is not streaming, the stream will be started and the scene in OBS switched to "Live".


=== Standby Loop ===
A script that controlls the lights, makes sure that the stream is off and goes into attract mode by showing a screen saver on the rasperry pie. Script is as follows:
// TODO fill out how this works
=== Player Activity ===
A PIR sensor is attached to the cabinet under the player controls.  The sensor feeds data back to the Arduino Mega which monitors the signal for movement.  As movement occurs, a timer is reset and status bit 12 is set to 1.  If the timer is not reset within 15ms, the Mega sets status bit 12 to 0, which tells the stream server to stop the stream
=== Emulation Station Customizations ===
//TODO fill out how this works


{| class="wikitable"
|+ Possible DIY Design
|-
! Qty
! Short Name
! Price
! Part
! Link
! Part Total
|-
| 1
| Transformer Dual 28V secondaries, 4.6A Max current
| $28.00
| VPS56-2300
| [https://www.digikey.com/product-detail/en/triad-magnetics/VPS56-2300/VPS56-2300-ND/7318278 Digikey]
| $28.00
|-
| 16
| Diode
| $1.00
| MUR860
| [https://www.digikey.com/product-detail/en/on-semiconductor/MUR860G/MUR860GOS-ND/919926 Digikey]
| $16.00
|-
| 4
| Linear Voltage Regulator
| $2.10
| LM338T
| [https://www.digikey.com/product-detail/en/texas-instruments/LM338T-NOPB/LM338T-NOPB-ND/212669 Digikey]
| $9.00
|-
| 8
| Rectifier Diode
| $0.20
| LM4002
| [https://www.digikey.com/product-detail/en/on-semiconductor/1N4002/1N4002FSCT-ND/1532743 Digikey]
| $1.60
|-
| 4
| 1200uF Radial Aluminum Electrolytic Caps
| $1.00 - $6.00 (depending on current)
| EEU-FS1J102B
| [https://www.digikey.com/product-detail/en/panasonic-electronic-components/EEU-FS1J102B/P123412TB-ND/8567301 Digikey]
| $24.00
|-
| *
| Various Caps and Resistors (1W)
| $10.00
| *
| *
| $10.00
|-
! scope="row" colspan="2"| Total
|
|
|
| $95.00
|}
----


=== Electrical ===
=== Exit script ===
A script that automatically exits the game correctly. Then goes back into attact mode. Script is as follows:
//TODO add script here


* Ground everything and very well, especially anything the human touches.   
=== Activity timer ===
A timer that counts down when no one is active to not be stuck in a game but go back to attract mode.   
//TODO fill in more technical details


== OBS automation ==
== OBS automation ==
Line 104: Line 66:


[https://stackoverflow.com/questions/9344235/how-to-restart-program-automatically-if-it-crashes-in-windows Guardian Process] - Windows OBS restart automatically on fail strategy
[https://stackoverflow.com/questions/9344235/how-to-restart-program-automatically-if-it-crashes-in-windows Guardian Process] - Windows OBS restart automatically on fail strategy
Windows Task Scheduler starts the stream server automatically on the stream pc.
Windows-r to bring up run dialog
tasksched.msc
look for Launch NGALAC server task
Task should run automatically but if not, can run manually with right-click run or the green play button on bottom right panel.  If it asks you to close all instances, say yes




Line 130: Line 102:
Query and send commands to OBS from python (can theoretically control everything)
Query and send commands to OBS from python (can theoretically control everything)


<nowiki>
'''credentials'''
import asyncio                                                                 
from obswsrc import OBSWS                                                     
from obswsrc.requests import (ResponseStatus,                                 
                              StartStreamingRequest,                           
                              GetStreamingStatusRequest                       
                              )                                               
from obswsrc.types import Stream, StreamSettings                               
                                                                               
                                                                               
async def main():                                                             
                                                                               
    async with OBSWS('localhost', 4444, 'password') as obsws:                 
                                                                               
        response = await obsws.require(GetStreamingStatusRequest())           
                                                                               
        print("Streaming: {}".format(response.streaming))                     
        print("Recording: {}".format(response.recording))                     
                                                                               
                                                                               
loop = asyncio.get_event_loop()                                               
loop.run_until_complete(main())                                               
loop.close()


</nowiki>
credentials for the stream websocket interface are required.


Output:
'''rtmp server setup'''
<nowiki>
Streaming: False
Recording: True
</nowiki>


Event Listener
[[NGALAC/Subsystems/RTMPserver|RTMP server configuration]]


<nowiki>
== Arduino ==
The arduino code is located in c:/Users/NGALAC-LIVE/projects/ngalac/prod


import asyncio                                                                 
The main file is arduino_controller.ino, and lights.cpp controls the lights only.
import logging                                                                 
import sys                                                                     
                                                                               
from obswsrc import OBSWS                                                     
from obswsrc.logs import logger                                               
                                                                               
                                                                               
# We will output logging to sys.stdout, as many events might raise errors         
# on creation (that's because protocol.json is not perfect) - such errors         
# are logged by obs-ws-rc automatically, we just need to see them             
logger.setLevel(logging.ERROR)                                                 
logger.addHandler(logging.StreamHandler(stream=sys.stdout))                   
                                                                               
                                                                               
async def main():                                                             
                                                                               
    async with OBSWS('localhost', 4444, "password") as obsws:                 
                                                                               
        print("Connection established.")                                       
                                                                               
        # We will receive events here by awaiting for them (you can await for 
        # an event of a specific type by providing `type_name` argument to       
        # the obsws.event() method)                                           
        event = await obsws.event()                                           
                                                                               
        # Awaited event might be None if connection is closed                 
        while event is not None:                                               
            print("Awaited for '{}' event!".format(event.type_name))           
            event = await obsws.event()                                       
                                                                               
        print("Connection terminated.")
 
loop = asyncio.get_event_loop()                                               
loop.run_until_complete(main())                                               
loop.close()
</nowiki>
 
Output:
<nowiki>
Awaited for 'TransitionBegin' event!
Awaited for 'SwitchScenes' event!
Awaited for 'RecordingStarting' event!
Awaited for 'StreamStarting' event!
</nowiki>
 
== Arduino ==


* [https://www.arduino.cc/en/Tutorial/Debounce Debounce buttons]
* [https://www.arduino.cc/en/Tutorial/Debounce Debounce buttons]
Line 221: Line 122:
Arduino code using CmdMessenger library for talking through serial port to python orchestrator
Arduino code using CmdMessenger library for talking through serial port to python orchestrator


<nowiki>
Python code to pair with CmdMessenger
#include "CmdMessenger.h"
 
First 3 states are switches set high or low
 
Last 3 are LED states (or anything else)


/* Define available CmdMessenger commands */
Can trigger LED strips or whatever else as we wish, run pre-defined patterns, etc.
enum {
    ping,
    pong,
    player,
    lights,
    get_state,
    ret_state,
    error
};


unsigned long debounce[3] = {0, 0, 0};
[[File:NGALAC_control_boards.jpg|center|640px]]
unsigned long btn_state[3] = {LOW, LOW, LOW};
unsigned long bounce_delay = 75;


int input_pins[3] = {2, 3, 4};
[[File:NGALAC-arduino.png|center]]
int pressure_btn = 0;
int stream_btn = 1;
int pin = 0;
int output_pins[3] = {5, 6, 7};
int light_state = LOW;


/* Initialize CmdMessenger -- this should match PyCmdMessenger instance */
== Software ==
const int BAUD_RATE = 9600;
<nowiki>
CmdMessenger c = CmdMessenger(Serial,',',';','/');
Arduino IDE 1.8.1+
* CmdMessenger
Python 3.5.4+
* vitualenv, virtualenvwrapper-win, PyCmdMessenger, obs-ws-rc
Git
</nowiki>


/* Create callback functions to deal with incoming messages */
Please see https://github.com/noisebridge/NGALAC for all relevent code


void do_pong(void){
== Webcam Adjustment ==
    c.sendCmd(pong, "pong");
}


void is_player(void){
Using a servo hooked up to the Leonardo to move adjust the webcam height via some kind of potentiometer.
    c.sendBinCmd(player, (int)btn_state[pressure_btn]);
}


void blink_lights(void){
right now servo is a radio [s]hack 08A14.
    light_state = ~light_state;


    for(pin=0; pin<3; pin++) {
pinout:
        digitalWrite(output_pins[pin], light_state);
[[File:radio-hack-servo.png|none|480px]]
    }
}


void send_state(void){
== Config Files ==
    c.sendCmdStart(ret_state);
    for(pin=0; pin<3; pin++) {
        c.sendCmdBinArg(digitalRead(input_pins[pin]));
    }
    for(pin=0; pin<3; pin++) {
        c.sendCmdBinArg(digitalRead(output_pins[pin]));
    }
    c.sendCmdEnd();
}


void on_unknown_command(void){
== Controllers ==
    c.sendCmd(error,"Command without callback.");
}


/* Attach callbacks for CmdMessenger commands */
* evtest to check inputs from the IPAC-2 on rpi
void attach_callbacks(void) {
    c.attach(ping, do_pong);


    c.attach(player, is_player);
* add player 2 keys to retropi retroarch config
    c.attach(lights, blink_lights);
    c.attach(get_state, send_state);
    c.attach(on_unknown_command);
}


void read_btns(void) {
maybe physically generate a plug/unplug signal via detection to arduino and trigger this:
    int reading;
https://zedt.eu/tech/linux/restarting-usb-subsystem-centos/


    for(pin=0; pin<3; pin++) {
arduino triggering done by detecting various grounding or other (is there a power?  must be.) for each controller, then sending that to arduino, then to pi.
        reading = digitalRead(input_pins[pin]);
        if (reading != btn_state[pin]) {
            debounce[pin] = millis();
        }
        if ((millis() - debounce[pin]) > bounce_delay) {
            if (reading != btn_state[pin]) {
                // Do something for that button, need butotn handlers
            btn_state[pin] = reading;
            }
        }
    }
}


void setup() {
usb stuff - polling on rpi
    Serial.begin(BAUD_RATE);
    attach_callbacks();
    for(pin=0; pin<3; pin++) {
        pinMode(input_pins[pin], INPUT);
        pinMode(output_pins[pin], OUTPUT);
        digitalWrite(output_pins[pin], LOW);
    }
}


void loop() {
full jsx linux system
    c.feedinSerialData();
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/Documentation/input/joydev/joystick.rst
    read_btns();
 
}
==notes==
 
keep alives for obs, obs restart on power on, rpi watchdog, faulover OBS instance, switched by obswsrc cannot connect.  how will this work with auto start, and how to select which instance is stealing?


</nowiki>


Python code to pair with CmdMessenger
[http://www.switchdoc.com/2014/11/reliable-projects-using-internal-watchdog-timer-raspberry-pi/ rpi watchdog]


<nowiki>
static electricity on case
import PyCmdMessenger                                                         
                                                                               
arduino = PyCmdMessenger.ArduinoBoard("/dev/ttyUSB0", baud_rate=9600)         
                                                                               
commands = [['ping', ''],                                                     
            ['pong', 's'],                                                     
            ['player', 'i'],                                                   
            ['lights', ''],                                                   
            ['get_state', ''],                                                 
            ['ret_state', 'i*'],                                               
            ['error', '']]                                                     
                                                                               
c = PyCmdMessenger.CmdMessenger(arduino, commands)                             
                                                                               
c.send('ping')                                                                 
msg = c.receive()                                                             
print(msg)                                                                     
                                                                               
c.send('player')                                                               
print(c.receive())                                                             
                                                                               
#  Turn On Lights                                                             
c.send('lights')                                                               
                                                                               
c.send('get_state')                                                           
msg = c.receive()                                                             
print(msg)                                                                     
                                                                               
#  Turn off Lights                                                             
c.send('lights')                                                               
c.send('get_state')                                                           
msg = c.receive()                                                             
print(msg)                                                                     
                                                                               
controls = msg[1]                                                             
if controls[0] != 0:                                                           
    print("Start Stream!")
</nowiki>


output from running python controller
Arduino COM port detection on streaming PC in python


<nowiki>
Do we want to record and stream?
Connecting to arduino on /dev/ttyUSB0... done.
('pong', ['pong'], 1522043014.6538415)
('player', [0], 1522043014.6666553)
('ret_state', [1, 0, 1, 1, 1, 1], 1522043014.704131)
('ret_state', [1, 0, 1, 0, 0, 0], 1522043014.744068)
Start Stream!
</nowiki>


First 3 states are switches set high or low


Last 3 are LED states (or anything else)
Hwinfo for monitoring streaming PC?  whyzit shuttin dwn.


Can trigger LED strips or whatever else as we wish, run pre-defined patterns, etc.




== Software ==
4/7/18
<nowiki>
added obs to restart on crash and moved lauch_obspy to restart_obs.bat
Arduino IDE 1.8.1+
* CmdMessenger
Python 3.5.4+
* vitualenv, virtualenvwrapper-win, PyCmdMessenger, obs-ws-rc
Git
</nowiki>


==notes==
'''add rpi input detection and set timer to tell stream PC to stop streaming (probably through Arduino or API call)


evtest to check inputs from the IPAC-2 on rpi
udev rules


add player 2 keys to retropi retroarch config
ACTION=="add", SUBSYSTEMS=="usb", KERNELS=="6-5:1.0", SYMLINK+="input/joy"


swap out audio receiver for car amp thing
udevadm test -a /sys/path or /dev/path


test autio streaming with mic, cabinet audio, and stream audio
udevadm test /dev/thing i think


found a woofer to test with (tbd)
udevadm info  --name /dev/thing  --query=property


usb shit - polling on rpi
udevadm info --a --name= /dev/thing


keep alives for obs, obs restart on power on, rpi watchdog, faulover OBS instance, switched by obswsrc cannot connect.  how will this work with auto start, and how to select which instance is stealing?
udevadm trigger --verbose -dry-run --type=devices --subsystem-match=usb


impedance matching circuit
udevadm monitor  --kernel, --udev, or --subsystem-match=usb


[http://www.switchdoc.com/2014/11/reliable-projects-using-internal-watchdog-timer-raspberry-pi/ rpi watchdog]
== Networking ==


static electricity on case
* Raspberry Pie not auto-connecting to net by default.  Should it?
* nginx w/ rtmp to restream


Arduino COM port detection on streaming PC in python


Do we want to record and stream?
== Neuro ==
http://www.psychiclab.net/IBVAmanual/QCgraph.html

Latest revision as of 23:43, 9 July 2019


Noisebridge | About | Visit | 272 | Manual | Contact | Guilds | Stuff | Events | Projects | Meetings | Donate E
Guilds (Volunteer) | Maintainers | Meta | Code | Electronics | Fabrication | Games | Sewing | Music | AI | Neuro | Philosophy | Funding | Art | Security | Ham | WGs E
Games Guild | Arcade | VRBridge | Gaming Archivists
Gamedev Events | Gamebridge Gamedev Wednesdays | Gamedev Coworking Sun-Tue | Blender | GDC
Gaming Thursdays | Indiebridge 1st Thur | Tablebridge 2nd Thur | 10MinsOfGame Talks 3rd Thur | Songbridge 4th Thur
Game Engine Saturdays: Unitybridge 1st Sat | Unrealbridge 2nd Sat | Godot Meetup 3rd Sat | Graphicsbridge 4th Sat
Noisebridge Games | NB Adventure | Noisebridge Against Humanity | Simbridge | BBS
Game Jams | GameJamCamp | Global Game Jam
E
Noisebridge Gaming Archivists | NGALAC Arcade Cabinet | NGA Identity V · T · E



Subsystems

[edit | edit source]

Power

[edit | edit source]

Streaming PC

[edit | edit source]

BIOS setting for Auto-on with power-on (e.g. from switch)



Audio

[edit | edit source]

Electrical

[edit | edit source]
  • Ground everything and very well, especially anything the human touches.

Control Model

[edit | edit source]


Start/Stop streaming

[edit | edit source]

The streaming PC uses OBS to stream, and there is a python websockets library which can control it. This library and a serial command interface known as CmdMEssenger is used to communicate with an Arduino Mega so the Mega can indicate signals to control OBS through a small python script. CmdMEssenger implements a messaging protocol to trigger functions via commands sent over Serial.

The Arduino Mega is effectively a slave to a python server on the streaming PC. The Arduino will set and clear bits in an array which is communicated to the streaming server via the server polling the Mega. The server is continuously polling the Mega and performs actions based on it's state and the information in the status array.

A user pushed a green button on the cabinet front panel to start (or stop) streaming. The Mega debounces and latches the button press and sets status bit 11. The stream server reads this bit which determines is a button press occurred. If the machine is streaming, the steam will be stopped (and the scene in OBS changed to "Not Live"). If the machine is not streaming, the stream will be started and the scene in OBS switched to "Live".

Standby Loop

[edit | edit source]

A script that controlls the lights, makes sure that the stream is off and goes into attract mode by showing a screen saver on the rasperry pie. Script is as follows: // TODO fill out how this works

Player Activity

[edit | edit source]

A PIR sensor is attached to the cabinet under the player controls. The sensor feeds data back to the Arduino Mega which monitors the signal for movement. As movement occurs, a timer is reset and status bit 12 is set to 1. If the timer is not reset within 15ms, the Mega sets status bit 12 to 0, which tells the stream server to stop the stream

Emulation Station Customizations

[edit | edit source]

//TODO fill out how this works


Exit script

[edit | edit source]

A script that automatically exits the game correctly. Then goes back into attact mode. Script is as follows: //TODO add script here

Activity timer

[edit | edit source]

A timer that counts down when no one is active to not be stuck in a game but go back to attract mode. //TODO fill in more technical details

OBS automation

[edit | edit source]

inputs -> Arduino/RaspberryPi <-> CmdMessenger <-> Serial port <-> USB <-> streaming CPU <-> PyCmdMessenger <-> obs-wc-controller <-> obs


Guardian Process - Windows OBS restart automatically on fail strategy

Windows Task Scheduler starts the stream server automatically on the stream pc.

Windows-r to bring up run dialog

tasksched.msc

look for Launch NGALAC server task

Task should run automatically but if not, can run manually with right-click run or the green play button on bottom right panel. If it asks you to close all instances, say yes


OBS Web Socket Plugin Sets up a websocket API for OBS
obs-wc-rc Python library to interface with OBS websocket API
PyCmdMesssenger Python library for CmdMessenger using serial port
CmdMessenger for Arduino Arduino CmdMessenger library to communicate with PyCmdMessenger on server via serial port

OBS websocket plugin

Tools -> Websocket Plugin Tools -> Websocket Plugin

obs-wc-rc

Query and send commands to OBS from python (can theoretically control everything)

credentials

credentials for the stream websocket interface are required.

rtmp server setup

RTMP server configuration

Arduino

[edit | edit source]

The arduino code is located in c:/Users/NGALAC-LIVE/projects/ngalac/prod

The main file is arduino_controller.ino, and lights.cpp controls the lights only.

Arduino code using CmdMessenger library for talking through serial port to python orchestrator

Python code to pair with CmdMessenger

First 3 states are switches set high or low

Last 3 are LED states (or anything else)

Can trigger LED strips or whatever else as we wish, run pre-defined patterns, etc.

Software

[edit | edit source]
Arduino IDE 1.8.1+
* CmdMessenger
Python 3.5.4+
* vitualenv, virtualenvwrapper-win, PyCmdMessenger, obs-ws-rc
Git

Please see https://github.com/noisebridge/NGALAC for all relevent code

Webcam Adjustment

[edit | edit source]

Using a servo hooked up to the Leonardo to move adjust the webcam height via some kind of potentiometer.

right now servo is a radio [s]hack 08A14.

pinout:

Config Files

[edit | edit source]

Controllers

[edit | edit source]
  • evtest to check inputs from the IPAC-2 on rpi
  • add player 2 keys to retropi retroarch config

maybe physically generate a plug/unplug signal via detection to arduino and trigger this: https://zedt.eu/tech/linux/restarting-usb-subsystem-centos/

arduino triggering done by detecting various grounding or other (is there a power? must be.) for each controller, then sending that to arduino, then to pi.

usb stuff - polling on rpi

full jsx linux system https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/Documentation/input/joydev/joystick.rst

notes

[edit | edit source]

keep alives for obs, obs restart on power on, rpi watchdog, faulover OBS instance, switched by obswsrc cannot connect. how will this work with auto start, and how to select which instance is stealing?


rpi watchdog

static electricity on case

Arduino COM port detection on streaming PC in python

Do we want to record and stream?


Hwinfo for monitoring streaming PC? whyzit shuttin dwn.


4/7/18 added obs to restart on crash and moved lauch_obspy to restart_obs.bat

add rpi input detection and set timer to tell stream PC to stop streaming (probably through Arduino or API call)

udev rules

ACTION=="add", SUBSYSTEMS=="usb", KERNELS=="6-5:1.0", SYMLINK+="input/joy"

udevadm test -a /sys/path or /dev/path

udevadm test /dev/thing i think

udevadm info --name /dev/thing --query=property

udevadm info --a --name= /dev/thing

udevadm trigger --verbose -dry-run --type=devices --subsystem-match=usb

udevadm monitor --kernel, --udev, or --subsystem-match=usb

Networking

[edit | edit source]
  • Raspberry Pie not auto-connecting to net by default. Should it?
  • nginx w/ rtmp to restream


Neuro

[edit | edit source]

http://www.psychiclab.net/IBVAmanual/QCgraph.html