Hi all,
as guentergunter did, I did some research and reprogramming and could now finalize my "Pedal-To-MIDI Box". 
 
My box supports not only 6 pedals but now it supports 
Pedal Noise and 
Half Pedal with a Sustain pedal in continous mode (Roland DP-10 in my case).
I had 2 main intentions for the box:
1. Reduce cabling going up to NS3. Keep cabling of (max.) 6 pedals on the floor. (normally I don't need all of them - just to be prepared)
2. Replace expensive Nord Triple Pedal 
So finally this box can replace the Nord Triple Pedal with all of it's special features - and more! 
 
My box is based on an Arduino Pro Mini 328 - 5V/16MHz. 
Schematic is based on 
download/file.php?id=9232 (in this thread).
Modifications (based on my preferations):
- MIDI IN: left out 
- Program up/down switches: left out
+ Rotary Speed toggle switch
+ Soft (left) pedal
+ Organ volume
I don't post photos of my box since it is a prototype and not very nice  
 
It is just a small plastic case which can hold the In and Out Jacks and the board with the arduino inside - nothing fancy at all.
Here's my finalized code:
Code: Select all
//
// Midi Box for Nord Stage 3
// by Klondyke77 03/2020
// Finalized V2.0: 16.03.2020
// V2.1: 19.12.2020 (starting improvement tests)
// Trying new code for sustain pedal
// Reducing of Midi commands for sustain pedal successfull
// V2.3: 20.12.2020 (continuing from 2.1, discarding V2.2)
// Pedal noise successfull. Calibrated sustain pedal trigger positions
// V2.4: 21.12.2020 implementing sustain pedal speed detection
// Sustain pedal including Half pedal and Pedal noise is working.
// code may still need some finalizing.
// V2.5: 25.12.2020 code finalizing and documenting
// ---------------------------------
// Contributions:
// code is based on:
// https://www.norduserforum.com/nord-stage-forum-f3/custom-comprehensive-nord-stage-pedal-board-t14141.html
// by "guentergunter"
// My own "Pedal-to-MIDI Box" is based on an Arduino Pro Mini 328 - 5V/16MHz
// Schematic is based on: https://www.norduserforum.com/download/file.php?id=9232 (in above thread)
// Schematic is modified:
// - MIDI IN: left out (not needed)
// - Program up/down switches: left out (not needed)
// + Rotary Speed toggle switch
// + Soft (left) pedal
// + Organ volume
// ---------------------------------
// Main improvement to V2.0 is "Velocity dependant Damper Noise" thanks to engineering of guentergunter!
// New findings regarding Sustain pedal in continous mode:
//
// In the following "send values" means always sending a Midi message on Control Channel (CC) 64, 
// which is Standard Control Channel for Sustain.
// 
// 1. My last implementation of continous sustain pedal was to send position values with every movement of the pedal. 
// This is also the way other manufacturers handle Midi messages with a continous Sustain Pedal (My Yamaha Clavinova does it this way). 
// But with the new knowledge I assume that this is not the way Nord has intended to handle it. 
// This may be the explanation why you get unintended Pedal Noise when doing so. 
// You would have to disable Pedal Noise per program - so did I - until now ;-)
// 
// 2. What Nord expects:
// - Send just one Midi message when pedal meets positions "Up / Half / Down", values: 0 / 64 / 127.
// - To activate Damper Noise via Midi:
//    + Send additional Midi message (on CC 64) right before position message Up or Down
//    + Slow pedal movement (low velocity) is represented by lower values and will cause light and silent pedal noise.
//    + Fast pedal movement (high velocity) is represented by higher values and will cause strong and loud(er) pedal noise.
//    + There are different value ranges for pedal up and pedal down:
//       * Pedal down: 27..42
//       * Pedal up:   10..18
//   Example for pedal down:
//   When pedal reaches defined position for pedal down, the following two commands are sent: 
//     send_MIDI_message(0xB0, MIDI_CC_Sustain, 30); // assuming 30 as derived damper speed
//     send_MIDI_message(0xB0, MIDI_CC_Sustain, 127); // message for pedal down
//           
//     + Speed detection is needed to make the values (2.) velocity dependant.
//        I decided to derive speed from measuring delta pedal position value in a
//        specified amount of time (sample interval).
//        Actually damper_speed is calculated continously but only used once when
//        damper positions down or up is reached.
//        There maybe ways to improve speed detection but for now I'm happy to have 
//        it working fine!
//  3. Half pedal can be realized by sending value 64 once when pedal reaches defined position ("Half").
//     Nord Stage 3 has only one position of half pedal implemented with corresponding samples - not more.
// ---------------------------------
//
// Toggle Debug Mode
// Debug mode configures/redirects serial output for serial monitoring
//#define DEBUG
    #ifdef DEBUG
      const int SERIAL_PORT_RATE = 9600;
    #else
      const int SERIAL_PORT_RATE = 31250;
    #endif
//
// MIDI CC (Control Channel) Numbers for NORD STAGE 3 Keyboard
//
const int MIDI_CC_Sustain = 64;          
const int MIDI_CC_Sostenuto = 66;          
const int MIDI_CC_SoftPedal = 67;
const int MIDI_CC_CrtlPedalExpr = 11;
const int MIDI_CC_RotarySpeed = 108;
const int MIDI_CC_OrganLevel = 13;
const int MIDI_CC_OrganSwell = 4;
//
// MIDI constant values
//
const int RotarySlow = 43;
const int RotaryFast = 127;
#define MIDI_Channel 0
// Pin Numbers
#define PIN_orgs A0     // Organ Swell Pedal (continous) Roland only!
#define PIN_sust A1     // Sustain Pedal (continous)     Roland only!
#define PIN_expr A2     // Expression Pedal (continous) Yamaha only!
#define PIN_sost 2      // Sostenuto Pedal (momentary)
#define PIN_soft 3      // Soft Pedal (momentary)
#define PIN_rota 4      // Rotary Speed (momentary)
// constant values
const int POT_THRESHOLD = 3;            // Threshold amount to guard against false values
// variable init
uint8_t sost = 0;
uint8_t sost_last = 0;
uint8_t soft = 0;
uint8_t soft_last = 0;
uint8_t rota = 0;
uint8_t rota_last = 0;
uint8_t rotary_state = 0;
uint8_t damper = 0;
uint8_t damper_last = 0;
// variables for speed detection
unsigned long currentMillis;
unsigned long previousMillis = 0;
unsigned long time_delta;
int damper_val1 = 0;
int damper_val2 = 0;
int damper_delta = 0;
const long interval = 50; // sample time in milliseconds
bool read_val = true;
int damper_speed = 0;
//
// End variable declaration/initialization
//
//
// Functions
//
void send_MIDI_message (byte cmd, byte byte1, byte byte2)
{
#ifdef DEBUG
  // redirect output in Debug mode
  char buf[100];
  sprintf(buf, "%d %d %d",cmd + MIDI_Channel, byte1, byte2);
  Serial.println(buf);
#else
  Serial.write(cmd + MIDI_Channel);
  Serial.write(byte1);
  Serial.write(byte2);
#endif
}
void setup()                            // Run once, when the sketch starts
{
    pinMode(PIN_sost, INPUT_PULLUP);
    pinMode(PIN_soft, INPUT_PULLUP);
    pinMode(PIN_rota, INPUT_PULLUP);
    Serial.begin(SERIAL_PORT_RATE);     // Starts communication with the serial port
    Serial.flush();
}
void loop()                             // Run over and over again
{
    
// **************************************
// Momentary Switches
// **************************************
    
    //
    // Sostenuto (Middle) Pedal (momentary/closed)
    //    
    sost = digitalRead(PIN_sost); 
    if (sost != sost_last)
    {
      sost_last = sost;
      send_MIDI_message(0xB0, MIDI_CC_Sostenuto, (sost * 127));
    }
    
    //
    // Soft (Left) Pedal (momentary/closed)
    //    
    soft = digitalRead(PIN_soft); 
    if (soft != soft_last)
    {
      soft_last = soft;
      send_MIDI_message(0xB0, MIDI_CC_SoftPedal, (soft * 127));
    }
    //
    // Rotary Speed switch (momentary/closed)
    // (toggle switch)
    //    
    rota = digitalRead(PIN_rota); 
    if (rota != rota_last && rota == 1)
    {
      if (rotary_state == 0)
      { 
        rotary_state = 1; // Rotary fast
        send_MIDI_message(0xB0, MIDI_CC_RotarySpeed, RotaryFast);
      }  
      else if (rotary_state == 1)
      { 
        rotary_state = 0; // Rotary slow
        send_MIDI_message(0xB0, MIDI_CC_RotarySpeed, RotarySlow);
      }
    }
    rota_last = rota;
// **************************************
// Continous Pedals
// **************************************
   
    //
    // Sustain Pedal (continous)
    // Values calibrated for: 
    // Roland DP10 in continous mode (Min=35, Max=1020)
    //
    
      //
      // Sustain Pedal - Speed detection
      //
      
      currentMillis = millis();
      // read and keep first value until second val is read
      if (read_val)
      {
        damper_val1 = analogRead(PIN_sust);
        read_val = false;
      }
  
      // wait interval time befor reading second value
      if (currentMillis - previousMillis >= interval)
      {
        previousMillis = currentMillis;
        damper_val2 = analogRead(PIN_sust);
        damper_delta = damper_val2 - damper_val1;
        // enable next speed detection
        read_val = true;
  
        // disable noise
        if (abs(damper_delta) > 2)
        {
           // calculate Midi values for damper speed
           // pedal down (delta positive): 27..42
           // pedal up (delta negative): 10..18
  
           if (damper_delta > 0) // pedal down
           {
              damper_speed = map (damper_delta, 0, 950, 27, 42);
              damper_speed = constrain (damper_speed, 27, 42);
           }
           if (damper_delta < 0) // pedal up
           {
              damper_speed = map (damper_delta, 0, -900, 10, 18);
              damper_speed = constrain (damper_speed, 10, 18);
           }
          /*
          #ifdef DEBUG
              // monitoring output
              char buf[120];
              sprintf(buf, "damper_delta:%4d damper_speed %2d", damper_delta, damper_speed);
              Serial.println(buf);
          #endif
          */
        }
      }
  
      //
      // Sustain Pedal 
      // position detection and MIDI output
      //
      
      static int s_SPmin = 30;
      static int s_SPmax = 1000;
      static int dposMid = 45;  // treshold relase to half-pressed
      static int dposHigh = 65; // treshold half-pressed to pressed
  
      damper_val2 = constrain((damper_val2),s_SPmin, s_SPmax);
      int damper_pos = map(damper_val2, s_SPmin, s_SPmax, 0, 127);  // Map the value to 0-127
      
      // Manually defined mapping to be able to define non-linear 
      // pedal positions for half-pedal and down position.
      // (calculated positions via map command did not fit my expections)
      //
      if (damper_pos <= dposMid) { 
          damper = 0; 
      }
      else if (damper_pos > dposMid and damper_pos <= dposHigh) {
          damper = 1; 
      }
      else
      { 
          damper = 2;
      }
        
      if(damper != damper_last)
      {
        damper_last = damper;
       
        switch (damper) 
        {
          case 0:
            send_MIDI_message(0xB0, MIDI_CC_Sustain, damper_speed);
            send_MIDI_message(0xB0, MIDI_CC_Sustain, 0);
            break;
          case 1:
            send_MIDI_message(0xB0, MIDI_CC_Sustain, 64);
            break;
          case 2:
            send_MIDI_message(0xB0, MIDI_CC_Sustain, damper_speed);
            send_MIDI_message(0xB0, MIDI_CC_Sustain, 127);
            break;
        }
       
      }
   
    //
    // Expression pedal (continous)
    // Values calibrated for: 
    // Yamaha EV-7 (Min=0, Max=1019)
    //
    
    static int s_EPmin = 0;
    static int s_EPmax = 1019;
    static int s_nLastPot0Value = 0;
    static int s_nLastMapped0Value = 0;
    int nCurrentPot0Value = analogRead(PIN_expr);
    if(abs(nCurrentPot0Value - s_nLastPot0Value) >= POT_THRESHOLD)
    {    
      s_nLastPot0Value = nCurrentPot0Value;
      nCurrentPot0Value = constrain( (nCurrentPot0Value),s_EPmin, s_EPmax);
      
      int nMapped0Value = map(nCurrentPot0Value, s_EPmin, s_EPmax, 0, 127);  // Map the value to 0-127
      if(nMapped0Value != s_nLastMapped0Value)
      {
        s_nLastMapped0Value = nMapped0Value;
        send_MIDI_message(0xB0, MIDI_CC_CrtlPedalExpr, nMapped0Value);
      }
    }
    //
    // Organ Swell pedal (continous)
    // Values calibrated for: 
    // Roland EV-7 (Min=0, Max=900)
    //
    
    static int s_SWmin = 0;
    static int s_SWmax = 900;
    static int s_nLastPot2Value = 0;
    static int s_nLastMapped2Value = 0;
    int nCurrentPot2Value = analogRead(PIN_orgs);
    if(abs(nCurrentPot2Value - s_nLastPot2Value) >= POT_THRESHOLD)
    {    
      s_nLastPot2Value = nCurrentPot2Value;
      int nMapped2Value = map(nCurrentPot2Value, s_SWmin, s_SWmax, 0, 127);  // Map the value to 0-127
      nCurrentPot2Value = constrain( (nCurrentPot2Value),s_SWmin, s_SWmax);
      if(nMapped2Value != s_nLastMapped2Value)
      {
        s_nLastMapped2Value = nMapped2Value;
        send_MIDI_message(0xB0, MIDI_CC_OrganSwell, nMapped2Value);
      }
    }
}
Hope this helps other people to realize similar projects. 
Reiner