The Programmable Stick/Pad Thread!

http://img30.imageshack.us/img30/3903/cimg0657d.th.jpg

Uploaded with ImageShack.us

Started work on my Round 3 stick.
Aim is to have a 2P programmable stick all in the HRAP3. Switch/button to control 1P/2P or both.
LCD screen where the turbo functionality etc. lived. PS360s so dual compatible.

Hello, I’m sorry if this isn’t relevant, but I’m looking for a stick that has a playback option. I’m hoping that one of the programmable sticks in this thread can be used for something simple like what I have in mind–read button inputs when in “record” mode, and play it back in “playback” mode.

I’ve fallen in love with the MVC3 playback option in training mode, and am wondering if anybody has ever implemented an equivalent hardware solution like it with a programmable stick, or heard of specialty sticks that will do the same. The specs I am interested in are:

  1. PS3 compatible
  2. High quality Japanese stick and parts (no preference for manufacturer)
  3. Record for at least 30 seconds

I know I might be asking for too much here, but I’m wondering if anybody has any hints that will point me in the right direction?

It’s certainly a feature that I’ve put some thought towards in terms of implemenation, but haven’t managed to successfully do yet. My round 3 stick is likelky to have a button labelled record, and then it will just be a matter of coding to allow for it.

I’m sure it’s not too hard to do, just that it’s me trying to work it out.

These days, the easiest way to do programming stick stuff is probably to roll your own.

Thanks for the responses. They’ve been helpful. However, I just realized all I really need for what I want to accomplish is a digital camera, since all I want is immediate feedback on execution improvements I could be making in training mode. -_-

Well, what are you trying to do?

I was in training mode, using the playback function, and noticed that my execution was improving much more noticeably when I could see exactly what I was doing wrong. (By using the playback feature.) The brilliant idea occurred to me: “Aha! What if I could do this for other fighting games too?! What I need… is a stick with a playback button!”

What I ended up figuring out was that–wait a minute, why don’t I just use a digital camera and record what I’m doing… much easier than modding my own stick.

So yes, once I figured out exactly what it was I was trying to do, the equipment I needed turned out to be different from what I had thought it would be.

Massive achievement this afternoon. I had a session of programming, and have been able to write a sketch that records moves, and can then play them back.

The below is the code (without comments, and not well formatted - need to sleep first) which I did it with. Basically, you can record up to five button presses, and then send them to a PS360 (tested with Windows 7 USB game controller settings.)

Timing should be accurate as it’s reporting it only takes 55microseconds to do the sketch. :smiley:


#include "TimerOne.h"
#include <stdarg.h>
//deviates a little from v5 in trying to get record function working. can go back to v5 if this fails. 

  int button =   22;
  int record =   23;
  int play =     24;
  int button_out = 25;
  int playstate; 
  int recordstate;
  int buttonstate;
  
  int print_value; 
    int j;
    int i;
    int k;
    int time1;
    int time2;
    int F=16683;
    int frame_count=0;
    int frame_advance=0;
    unsigned long time;
    int record_state [10][2];
    int current_record_slot=0;

void setup() {

  
for (i=0;i<11;i++)
{record_state*[0]=0;record_state*[1]=1;}

  
  
Timer1.initialize(F);                     
Timer1.pwm(9,900);
Timer1.attachInterrupt(FrameAdv);
     
   Serial.begin(9600);
    pinMode(button,INPUT);
    pinMode(record,INPUT);
    pinMode(play,INPUT);
    pinMode(button_out,OUTPUT); 
    digitalWrite(button,HIGH);
    digitalWrite(play,HIGH);
    digitalWrite(record,HIGH); 
   
    
}
void FrameAdv(){frame_advance=1;}  



void loop(){
    
  if (frame_advance==1){

     time1=micros(); 
     
if(digitalRead(record)==LOW){    
    if (digitalRead(record)!=recordstate)
    {frame_count=0;current_record_slot=0;Serial.println("reset");
    for (i=0;i<11;i++)
    {record_state*[0]=0;record_state*[1]=1;}}}


if (digitalRead(button)!=buttonstate)
    {digitalWrite(button_out,digitalRead(button)); 
    if(current_record_slot<11)
    {record_state[current_record_slot][0]=frame_count; 
    record_state[current_record_slot][1]=digitalRead(button);
    current_record_slot++;}}
    
   
   if (digitalRead(play)==LOW){if (digitalRead(play)!=playstate)
       {frame_count=0;  Serial.print("play @ "); Serial.println(time2-time1+16683);   
       for (k=0;k<10;k++)
       {print_value = record_state[k][0]; Serial.print(print_value);Serial.print(" @ ");Serial.print(record_state[k][1]);Serial.println("");}}}
     
     
    for (j=0;j<10;j++)
     if(frame_count==record_state[j][0]){digitalWrite(button_out,record_state[j][1]); }


playstate=digitalRead(play);
recordstate=digitalRead(record);
buttonstate=digitalRead(button);

frame_count++;
time2=micros();
frame_advance=0;
}}



Sweet!

Can you scale it up to 100? :sweat:

Ah. You could also use ‘input display’ and a video recorder. (Though the displays are frequently out of sync.)

Shouldn’t be a problem. Just kept it to 1 button and 10 commands for the proof of concept.

[media=youtube]bYm7umpMagw[/media]
[media=youtube]57zPuY6qsPE[/media]

Two quick videos showing my achievements (no gamer points though.)

Updated my code. Now supports two buttons, but would be very easy to expand to however many. Takes 75microseconds to run the sketch, so still lots of time



#include "TimerOne.h"
#include <stdarg.h>
//deviates a little from v5 in trying to get record function working. can go back to v5 if this fails. 
  
  int button =   22;
  int button2 = 23;             //three inputs and one output. Button is the button to be recorded.
  int buttons_in[] = {button,button2};
  
  
  
  int record =   24;         //Record clears the memory and starts recording.
  int play =     25;         //Play commences playback
  
  int button_out = 26;       //This is the output to the PS360
  int button_out2 = 27;
  int buttons_out[] = {button_out,button_out2};
  
  
  int playstate;             //States are used so that I can compare the state of the button last frame to this frame
  int recordstate;
  int buttons_state[]={1,1};
  
  
    int j;int k; int i;      //Three variables used for various functions in the sktech. Do I need all three? Maybe not. 
   
    
    
    int time1;              //I use these to time how long my sketches takes. 
    int time2;
    int F=16683;            //The duration of one frame
    int frame_count=0;      //Used to set timing by frame
    int frame_advance=0;    //Trigger to advance to the next frame.
    unsigned long time;
    int record_state [10][3];       //Where the recorded move is stored.
    int current_record_slot=0;      //The current slot for data recording. 

void setup() {

  
for (i=0;i<11;i++){record_state*[0]=0;
    record_state*[1]=1;record_state*[2]=1;}       //Clears the record memory. 

  
Timer1.initialize(F);                                                //Sets up the frame counter                     
Timer1.pwm(9,900);
Timer1.attachInterrupt(FrameAdv);
     
   Serial.begin(9600);     //Allows information to be sent back to the arduino monitor
                            //Sets up the buttons
   for (i=0;i<2;i++){pinMode(buttons_in*,INPUT);
      digitalWrite(buttons_in*,HIGH);}
   for (i=0;i<2;i++){pinMode(buttons_out*,OUTPUT);
      digitalWrite(buttons_out*,HIGH);}
    pinMode(record,INPUT);
    pinMode(play,INPUT);
 
   
    digitalWrite(play,HIGH);
    digitalWrite(record,HIGH); 
for (i=0;i<2;i++)
    {buttons_state*=digitalRead(buttons_in*);}
    
}
void FrameAdv(){frame_advance=1;}  



void loop(){
    
if (frame_advance==1){

     time1=micros(); 
     
if(digitalRead(record)==LOW && digitalRead(record)!=recordstate)
    {frame_count=0;current_record_slot=0;Serial.print("reset @ ");
    Serial.println(time2-time1+16683);
    for (k=0;k<11;k++){for(i=1;i<3;i++)
      {record_state[k][0]=0;record_state[k]*=1;}}}


for (k=0;k<2;k++){if (digitalRead(buttons_in[k])!=buttons_state[k])
  {digitalWrite(buttons_out[k],digitalRead(buttons_in[k])); 
  
   if(current_record_slot<11)
    {record_state[current_record_slot][0]=frame_count; 
    
    for(i=0;i<2;i++){
      record_state[current_record_slot][i+1]=digitalRead(buttons_in*);}
      current_record_slot++;}}}
    
   
if (digitalRead(play)==LOW && digitalRead(play)!=playstate)
       {frame_count=0;  Serial.print("play @ "); 
       Serial.println(time2-time1+16683);   
       
       for (k=0;k<10;k++){for(i=0;i<2;i++)
         {Serial.print(record_state[k][i+1]);}
         Serial.print(" @ ");
         Serial.print(record_state[k][0]);Serial.println("");}}
     
     
for (k=0;k<10;k++)
   {if(frame_count==record_state[k][0]){for(i=0;i<2;i++)
   {digitalWrite(buttons_out*,record_state[k][i+1]);}}}



playstate=digitalRead(play);
recordstate=digitalRead(record);

for(k=0;k<2;k++){buttons_state[k]=digitalRead(buttons_in[k]);}


frame_count++;
time2=micros();
frame_advance=0;
}}



[media=youtube]Qwd0kUEML14[/media]

Now move recording for all buttons.


[media=youtube]ag_H4xHu1jg[/media]



#include "TimerOne.h"
#include <stdarg.h>

#include <LiquidCrystal.h>
  LiquidCrystal lcd(2, 3, 4, 10, 11, 12,13);

  int A=22; int B=23; int C=24; int X=25; int Y=26; int Z=27;
  int P=28; int Q=29; int U=30; int D=31; int R=32; int L=33;
  int STA=34; int SEL=35; int TUR=36; int HOM=37;
  int a=38; int b=39; int c=40; int x=41; int y=42; int z=43;
  int p=44; int q=45; int u=46; int d=47; int r=48; int l=49;
  int sta=50; int sel=51; int tub=52; int hom=53;

  int a_in=54; int b_in=55; int c_in=56; int x_in=57; int y_in=58; int z_in=59;
  int p_in=60; int q_in=61; int u_in=62; int d_in=63; int r_in=64; int l_in=65;
  int sta_in=66; int sel_in=67; int tur_in=68; int hom_in=69;

  int buttons_in[]=    {54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69};
  int buttons_out[] =  {22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37};
  int buttons_outP2[] = {38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53};
  int buttons_state []= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

int recording=0;
int playback=0;

  int record =  60;        //Record clears the memory and starts recording.
  int play =    61;        //Play commences playback
  int playstate;            //States are used so that I can compare the state of the button last frame to this frame
  int recordstate;
  int button_changed_state=0;
  int P1; int P2;
  int variables[]={0,5,10};
  int v1=variables[0];int v2=variables[1];int v3=variables[2];
 
  int j;int k; int i;int m;      //Three variables used for various functions in the sktech. Do I need all three? Maybe not.

  //I use these to time how long my sketches takes.
  int longest_frame;int lag;int lag_count=0;
  int time1;int time2;
    int F=16683;int frame_count=0;int frame_advance=0;
    unsigned long time;

    int record_slot_max = 124;// int button_number_max = 12;
    int record_state [125][12];
  int record_stateP2 [125][12];
    int record_state_time[255];    //Where the recorded move is stored.
    int current_record_slot=0;      //The current slot for data recording.
//////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  lcd.begin(16,2);analogWrite(5,60);

  for (i=0;i<record_slot_max;i++){record_state_time*=0;
  for (k=0;k<12;k++){record_state*[k]=1;record_stateP2*[k]=1;
}}      //Clears the record memory. * may need to change to button number
 
  Timer1.initialize(F);                                                //Sets up the frame counter
  Timer1.pwm(9,900);
  Timer1.attachInterrupt(FrameAdv);

  Serial.begin(9600);    //Allows information to be sent back to the arduino monitor
                            //Sets up the buttons
  for (i=0;i<16;i++){pinMode(buttons_in*,INPUT);
      digitalWrite(buttons_in*,HIGH);}
  for (i=0;i<16;i++){pinMode(buttons_out*,OUTPUT);pinMode(buttons_outP2*,OUTPUT);
      digitalWrite(buttons_out*,HIGH);digitalWrite(buttons_outP2*,HIGH);}
    pinMode(record,INPUT);
    pinMode(play,INPUT);
  pinMode(7,INPUT);
  pinMode(8,INPUT);
  pinMode(9,INPUT);

digitalWrite(7,HIGH);
  digitalWrite(8,HIGH);
  //digitalWrite(9,HIGH);
    digitalWrite(play,HIGH);
    digitalWrite(record,HIGH);
    //for (i=0;i<12;i++)
  //  {buttons_state*=digitalRead(buttons_in*);}

}
  void FrameAdv(){frame_advance=1;}

  void press (int start, int finish, ...) {
    int m,tmp;
    va_list args;
    va_start(args,finish);
    for(m=0;m<finish;m++){tmp=va_arg(args,int);
        if(frame_count>=start && frame_count<finish){digitalWrite(tmp,LOW);}
        if(frame_count==finish){digitalWrite(tmp,HIGH);}}
        if(frame_count==finish+1){return;}
    va_end(args);}
 
  int check(int button, int var){
    if(digitalRead(button)==LOW){
      if(digitalRead(u_in)==LOW){if(digitalRead(u_in)!=buttons_state[8])
    {variables[var]=variables[var]+5;}}
      if(digitalRead(d_in)==LOW){if(digitalRead(d_in)!=buttons_state[9])
    {variables[var]=variables[var]-5;}}
      if(digitalRead(r_in)==LOW){if(digitalRead(r_in)!=buttons_state[10])
    {variables[var]=variables[var]+1;}}
      if(digitalRead(l_in)==LOW){if(digitalRead(l_in)!=buttons_state[11])
    {variables[var]=variables[var]-1;}}
}}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void loop(){
    //digitalWrite(51,LOW);digitalWrite(35,LOW);
    //digitalWrite(37,LOW);//
  //digitalWrite(53,LOW); //use these to swap 360 and ps3
  digitalWrite(53,HIGH);
  digitalWrite(37,HIGH);
  digitalWrite(51,HIGH);
  digitalWrite(35,HIGH);
  
  if (frame_advance==1){
  time1=micros();
    press(1,2);

  check(p_in,0);
  check(q_in,1);
    v1=variables[0];v2=variables[1];v3=variables[2];
//press(v1,v1+1,R,C);press(v2,v2+1,D,C);
 
    for (k=0;k<16;k++){if (digitalRead(buttons_in[k])!=buttons_state[k]){button_changed_state=1;}}

    if(button_changed_state==1){
  //  if(current_record_slot<record_slot_max)
    {record_state_time[current_record_slot]=frame_count;}

    for(k=0;k<14;k++){buttons_state[k]=digitalRead(buttons_in[k]);
      if(P1==1){digitalWrite(buttons_out[k],digitalRead(buttons_in[k]));

      if(recording==1){record_state[current_record_slot][k]=digitalRead(buttons_in[k]); }}

      if(P2==1){digitalWrite(buttons_outP2[k],digitalRead(buttons_in[k]));

      if(recording==1){record_stateP2[current_record_slot][k]=digitalRead(buttons_in[k]); }}
  
}

if(recording==1){current_record_slot++;}
}
     
  if(digitalRead(record)==LOW && digitalRead(record)!=recordstate)
    {recording=recording-1; recording=abs(recording);
      if (recording==1){
      frame_count=0;current_record_slot=0;Serial.print("reset @ ");
    Serial.println(time2-time1+16683);
    for (k=0;k<record_slot_max;k++){for(i=0;i<12;i++)
      {record_state_time[k]=0;record_state[k]*=1;record_stateP2[k]*=1;}}}}
    
    if (digitalRead(play)==HIGH && digitalRead(play)!=playstate)
      {frame_count=0;  Serial.print("play @ ");
 
      Serial.println(time2-time1+16683);
      Serial.println("ABCXYZPQUDRLabcxyzpqudrl");//A,B,C,X,Y,Z,P,Q,U,D,R,L

      for (k=0;k<20;k++){for(i=0;i<12;i++)//record_slot_max - show fewer commands to get play to work earlier
        {Serial.print(record_state[k]*);}
        for(i=0;i<12;i++)//record_slot_max - show fewer commands to get play to work earlier
        {Serial.print(record_stateP2[k]*);}
        Serial.print(" @ ");
        Serial.print(record_state_time[k]);Serial.println("");}
   
}
 
for (k=0;k<record_slot_max;k++)
  {if(frame_count==record_state_time[k]){for(i=0;i<12;i++)
  {digitalWrite(buttons_out*,record_state[k]*);
  digitalWrite(buttons_outP2*,record_stateP2[k]*);
    }}}

for(i=0;i<12;i++){
  if(P1==1){if(digitalRead(buttons_in*)==LOW){digitalWrite(buttons_out*,LOW);}}
  if(P2==1){if(digitalRead(buttons_in*)==LOW){digitalWrite(buttons_outP2*,LOW);}} }

playstate=digitalRead(play);
recordstate=digitalRead(record);

frame_count++;
button_changed_state=0;
//if (frame_count>1){int lag = (time2-time1);
//lcd.clear();
//lcd.setCursor(5,1);lcd.print(lag);}
lcd.clear(); lcd.setCursor(0,0); lcd.print(variables[0]);lcd.setCursor(4,0); lcd.print(variables[1]);
lcd.setCursor(8,0); lcd.print(variables[2]);
if(digitalRead(7)==LOW){P1=1;lcd.setCursor(8,1);lcd.print(P1);}
if(digitalRead(7)==HIGH){P1=0;lcd.setCursor(8,1);lcd.print(P1);}
if(digitalRead(8)==LOW){P2=1;lcd.setCursor(11,1);lcd.print(P2);}
if(digitalRead(8)==HIGH){P2=0;lcd.setCursor(11,1);lcd.print(P2);}
if(recording == 1){lcd.setCursor(13,1);lcd.print("R");}

//if(digitalRead(9)==LOW){lcd.setCursor(10,1);lcd.print("1");}
//if(digitalRead(9)==HIGH){lcd.setCursor(10,1);lcd.print("0");}
time2=micros();
lcd.setCursor(0,1);lcd.print(time2-time1);
frame_advance=0;
}}


http://imageshack.us/photo/my-images/59/dsc00047di.jpg/

Hi everyone,

Read all the prior posts, I have a mad catz TE stick, am i able to re-program the buttons on that to do combos with one button press?
Do i just need software or other parts etc…

Any help is appreicated, thanks.

You would need software, and other parts… I’m not sure you’d get what you want out of it either.

Thanks Rufus.

You know the trial athlete trophy in SSFIV? I want to program a combo for each button so i could easily(i think) do a sequence of combos by pressing one button after the other.

I’ll mention that I would never use this in online mode, i am not interested in becoming no. 1 on the ladder or anything like that, just want an easy way out of those ridiculously time connsuming trophy’s.

That is what I want out of it…

The main thought that comes to my mind is “Is it execution or timing?” that’ stopping you completing the trials. If it’s execution what you have in mind will help. However if it’s timing (1F links etc). then having a set of inputs linked to a button won’t make it much easier.

As for your overall question, yes you can definitely use the kind of things I’ve been making to do trials, but you might be surprised at how long it takes.

e.g. you don’t want to know how long this took

(probably 30 mins or so, but that’s including some learning curve)