2018年10月17日
每个人都喜欢80年代吧? 好吧,我当然会做-好吧,无论如何复兴。 当然,我不想再看到80年代的某些部分,但这是另一篇文章。 可以说,一些技术,风格和音乐正在以巨大的方式回归。 由于EMF Cybar和Nullsector即将来临,我决定在6月前后查看Nintendo Powerglove,以及在保持其完整性的情况下如何进行现代化。
- 每周更新,包括本周最热门的日本Nintendo Switch,3DS和移动新闻报道!
- 马里奥网球王牌中应该包含的字符
- 日常用户界面:Wii不想玩
- Wootini的每周动物穿越日记2/17/18
- 当您为他人赚取更多收益时,视频游戏如何显示所做的改进?
您可以在我的github页面上找到所有用于此的代码。 我还要感谢我的侄子山姆(Sam)在研究和协助研究方面非常勤奋! 😀

硬体

动力手套的设计可插入NES。 这意味着它实际上仅具有基本的NES控制板输入-A,B,开始,选择和8个方向。 手套系统实际上有两个部分。 手套本身和包含一组麦克风的框架状感应条。 镜架本身会从手套上拾取超声波脉冲,以弄清其运动方式。 因此,如果手套在此框架内并且已全部校准,则可以上下移动手以在控制器上生成相应的按钮推动。
黑客GIF –在GIPHY上查找和共享
与您认识的所有人发现并分享此Hacker GIF。 GIPHY是您搜索,共享,发现和创建GIF的方式。 giphy.com
通过GIPHY
我决定不看这部分,因为我想戴着手套在周围徘徊。 这些传感器内部的技术以及连接它们的盒子似乎大多是模拟的,这似乎也超出了我的范围。 据我所知,这里几乎没有数字组件。 一些巧妙的放大器电路以及这里没有发生的事情。
手套单元和框架的臂也插入主箱。 看一下这个盒子,里面似乎有一些放大器,移位寄存器,除了手套外的大部分连接都完全绕开了所有这些电路。 唯一看起来与手指无关的手指,我们将深入探讨。 手套的连接器是标准的DB9,它为我们提供了一个起点。
在https://tresi.github.io/nes/上有NES控制器协议的出色文章。 您还可以在http://mellottsvrpage.com/glove.htm上了解历史。
初始控制
第一步是查看哪些DB9引脚对应于哪个NES引脚。 查看主机箱,我们知道一些直接链接在一起,因此我们需要做的就是拿起万用表,并通过一些连续性测试来找到映射。
到目前为止,我在DB9连接器上找到的映射如下所示:
1-x(摆动?)
2-地
3-x(摆动?)
4-x(摆动吗?)
5-+ 5V
6-地
7-闩锁
8-时钟
9-数据
事实证明,我们可以使用Arduino和一些类似以下的代码轻松地创建NES控制器(感谢本文)
/*
================================================================================
File........... NES Controller Test Code
Purpose........ To demonstrate how to interface to an NES controller
Author......... Joseph Corleto
E-mail......... corleto.joseph @ gmail.com
Started........ 04/13/2016
Finished....... 04/14/2016
Updated........ --/--/----
================================================================================
Notes
================================================================================
- The NES controller contains one 8-bit 4021 shift register inside.
- This register takes parallel inputs and converts them into a serial output.
- This code first latches the data and then shifts in the first bit on the data line.
Then it clocks and shifts in on the data line until all bits are received.
- What is debugged are the button states of the NES controller.
- A logical "1" means the button is not pressed. A logical "0" means the button is
pressed.
- This code shifts the first bit of data into the LSB.
- The order of shifting for the buttons is shown in the table below:
Bit# | Button
--------------
0 | A
--------------
1 | B
--------------
2 | Select
--------------
3 | Start
--------------
4 | Up
--------------
5 | Down
--------------
6 | Left
--------------
7 | Right
--------------
- The NES controller pinout is shown below (looking into controllers
connector end):
__________
/ |
/ O 1 | 1 - Ground
| | 2 - Clock
| 7 OO 2 | 3 - Latch
| | 4 - Data Out
| 6 OO 3 | 5 - No Connection
| | 6 - No Connection
| 5 OO 4 | 7 - +5V
|___________|
- Please visit http://www.allaboutcircuits.com to search for complete article!
================================================================================
Updates
================================================================================
*/
//===============================================================================
// Header Files
//===============================================================================
//===============================================================================
// Constants
//===============================================================================
// Here we have a bunch of constants that will become clearer when we look at the
// readNesController() function. Basically, we will use these contents to clear
// a bit. These are chosen according to the table above.
const int A_BUTTON = 0;
const int B_BUTTON = 1;
const int SELECT_BUTTON = 2;
const int START_BUTTON = 3;
const int UP_BUTTON = 4;
const int DOWN_BUTTON = 5;
const int LEFT_BUTTON = 6;
const int RIGHT_BUTTON = 7;
//===============================================================================
// Variables
//===============================================================================
byte nesRegister = 0; // We will use this to hold current button states
//===============================================================================
// Pin Declarations
//===============================================================================
//Inputs:
int nesData = 4; // The data pin for the NES controller
//Outputs:
int nesClock = 2; // The clock pin for the NES controller
int nesLatch = 3; // The latch pin for the NES controller
//===============================================================================
// Initialization
//===============================================================================
void setup()
{
// Initialize serial port speed for the serial terminal
Serial.begin(9600);
// Set appropriate pins to inputs
pinMode(nesData, INPUT);
// Set appropriate pins to outputs
pinMode(nesClock, OUTPUT);
pinMode(nesLatch, OUTPUT);
// Set initial states
digitalWrite(nesClock, LOW);
digitalWrite(nesLatch, LOW);
}
//===============================================================================
// Main
//===============================================================================
void loop()
{
// This function call will return the states of all NES controller's register
// in a nice 8 bit variable format. Remember to refer to the table and
// constants above for which button maps where!
nesRegister = readNesController();
// Slight delay before we debug what was pressed so we don't spam the
// serial monitor.
delay(180);
// To give you an idea on how to use this data to control things for your
// next project, look through the serial terminal code below. Basically,
// just choose a bit to look at and decide what to do whether HIGH (not pushed)
// or LOW (pushed). What is nice about this test code is that we mapped all
// of the bits to the actual button name so no useless memorizing!
if (bitRead(nesRegister, A_BUTTON) == 0)
Serial.println("JUMP!");
if (bitRead(nesRegister, B_BUTTON) == 0)
Serial.println("PUNCH!");
if (bitRead(nesRegister, START_BUTTON) == 0)
Serial.println("DOOMSDAY ACTIVATED");
if (bitRead(nesRegister, SELECT_BUTTON) == 0)
Serial.println("WHY DON'T YOU MAP SOMETHING HERE?");
if (bitRead(nesRegister, UP_BUTTON) == 0)
Serial.println("...OR HERE?");
if (bitRead(nesRegister, DOWN_BUTTON) == 0)
Serial.println("PLAY WITH THE CODE ALREADY!");
if (bitRead(nesRegister, LEFT_BUTTON) == 0)
Serial.println("MAKE SOMETHING WITH THIS!");
if (bitRead(nesRegister, RIGHT_BUTTON) == 0)
Serial.println("GOOD LUCK WITH YOUR PROJECT ");
}
//===============================================================================
// Functions
//===============================================================================
///////////////////////
// readNesController //
///////////////////////
byte readNesController()
{
// Pre-load a variable with all 1's which assumes all buttons are not
// pressed. But while we cycle through the bits, if we detect a LOW, which is
// a 0, we clear that bit. In the end, we find all the buttons states at once.
int tempData = 255;
// Quickly pulse the nesLatch pin so that the register grab what it see on
// its parallel data pins.
digitalWrite(nesLatch, HIGH);
digitalWrite(nesLatch, LOW);
// Upon latching, the first bit is available to look at, which is the state
// of the A button. We see if it is low, and if it is, we clear out variable's
// first bit to indicate this is so.
if (digitalRead(nesData) == LOW)
bitClear(tempData, A_BUTTON);
// Clock the next bit which is the B button and determine its state just like
// we did above.
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, B_BUTTON);
// Now do this for the rest of them!
// Select button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, SELECT_BUTTON);
// Start button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, START_BUTTON);
// Up button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, UP_BUTTON);
// Down button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, DOWN_BUTTON);
// Left button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, LEFT_BUTTON);
// Right button
digitalWrite(nesClock, HIGH);
digitalWrite(nesClock, LOW);
if (digitalRead(nesData) == LOW)
bitClear(tempData, RIGHT_BUTTON);
// After all of this, we now have our variable all bundled up
// with all of the NES button states.*/
return tempData;
}
这将我们带到了那里,但有一个问题-嗯,实际上是两个! 食指和拇指!

手指
拇指和食指中有一些弯曲传感器,它们似乎分别转换为A和B按钮。 如果您喜欢,您可能会从中得到一个模拟读数并正确绘制手指位置。 但是,这实际上意味着要拆掉手套并添加额外的硬件,而我没有时间也没有意愿去做。 所以我想我只需要为每个数字打开/关闭输出即可。
问题是我根本无法使它们工作,当我偶然发现该解决方案时,它并不是最可靠的。 这是真正的黑客活动开始的地方–尝试所有可以想到的事情,直到获得所需的结果。
我尝试了所有我能想到的方法,但最后,似乎其中一条线上升到+ 5V然后又下降时会唤醒手指传感器,但是所有其他按钮都将返回随机值。 很奇怪! 如果有人把它放回地面,它仍然是随机的,但是偶尔,它会再次落下来。
因此,我添加了一条线,使DB9连接器上的端口1、3和4 摆动 ,这似乎是最一致的。 有时,A和B按钮会在不被按下的情况下被激活,但是在大多数情况下,代码中的这种摆动似乎效果很好。
校准和其他步骤
当您插入Powerglove时,它首先不会起作用。 您需要先按开始按钮,然后才能将数据发送回去。 据说,在按下开始之前,应该握紧拳头戴上手套,然后在按下之后松开,以进行良好的校准。 这似乎对正确注册手指按压有所帮助。
USB
过去,有一个非常方便且便宜的USB板,称为minimus。 几年前,我在一个类似的项目中使用了该板,以将megadrive板隐蔽到USB。 可悲的是,我认为没人能再握住它们了,所以我搬到了每个人最喜欢的基于Arduino的USB上来了,这就是teensy。 是的 这些小板既好又简单,如果您需要快速完成操作,则可以使用该板。 它们价格稍贵,但效果很好。
我购买了几个新的Teensy LC,因为它们是最便宜的,并具有我需要的所有东西。 我忘了注意的一件事是它只能在3.3V电压下工作! 这是一个问题,因为Powerglove的电压为5伏。 幸运的是,我周围有几个Sparkfun电平转换器,效果很好。 那使我无所适从。 我还有一个备用的Teensy 2.0,其耐受5V电压,因此我可以重建两副手套-一副给我,一副给我的朋友兼Cybar项目负责人Charles。

令人讨厌的是,我似乎无法将Teensy LC或2.0 仅仅设置为游戏手柄。 我需要去换一个飞行操纵杆。 这太过分了,但至少可以奏效。 通常,D-Pad采取帽子的形式-在精美的飞行杆上会看到一个颤抖的8向指示按钮。 当您运行模拟器时,X-Box和playstation控制器也是如此,因此至少是合理的。
全部焊接,添加USB延长线和吊杆! 您已经有了一个整洁的小单元,可以插入Powerglove的DB9和PC的USB插座。 我喜欢这个构建的地方是,您根本不需要弄乱PowerGlove的内部。 我所做的唯一内部更改是将带电的电线移至手套上的超声发射器。 它们有点噪音,而且由于我们不使用它们,所以我认为我们可以做到这一点。
测试中
测试电子手套的最佳方法是玩电子游戏《狂怒》。
