1. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Now a Download Plan!
  2. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  3. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant. Do not follow these rules can lead to permanent exclusion from this website: Read the forum rules.
    Are you a company? Read our company rules

Simulated Wind using MonsterMoto and ArduinoUno

Discussion in 'SimTools compatible interfaces' started by SilentChill, May 15, 2015.

  1. dutiti

    dutiti New Member Gold Contributor

    Joined:
    Feb 23, 2018
    Messages:
    15
    Balance:
    - 130Coins
    Ratings:
    +5 / 0 / -0
    Yes

    I tested the S100 and S000, S025 commands on another pc and it works, it comes from my pc, I must have missed a driver somewhere, I tested the 4 port usb card it didn't change anything .
  2. dutiti

    dutiti New Member Gold Contributor

    Joined:
    Feb 23, 2018
    Messages:
    15
    Balance:
    - 130Coins
    Ratings:
    +5 / 0 / -0
    A very big thank you to Zed for your help, now with this code everything works perfectly:

    Code:
    #define FALSE 0
    #define TRUE 1
    
    #define BRAKEVCC 0
    #define CW   1
    #define CCW  2
    #define BRAKEGND 3
    #define CS_THRESHOLD 100
    
    #define BOTH 0
    #define LEFT 1
    #define RIGHT 2
    
    int inApin[2] = {7, 4};  // INA: Clockwise output
    int inBpin[2] = {8, 9}; // INB: Counter-clockwise output
    int pwmpin[2] = {5, 6}; // PWM output
    int cspin[2] = {2, 3}; // CS: Current sense ANALOG input
    int enpin[2] = {0, 1}; // EN: Status of switches output (Analog pin)
    int statpin = 13;
    
    // pwmMode - sets the PWM frequency, valid options as follows:
    // pwmMode = 0 will use 980Hz PWM, default mode which will work with all fan types, will cause coil whine if using a MM.
    // pwmMode = 1 will use 4kHz PWM, might reduce coil whine for blowers, use heatsinks on the MM - check MM temp at a low fan speed.
    // pwmMode = 2 will use 8kHz PWM, might be OK for blowers with active cooling on the MM - check MM temp at a low fan speed.
    // pwmMode = 3 will use 31kHz PWM, use with caution - not for blowers with MM as it will cause very high temps. Check MM temp at a low fan speed.
    // server fans - should be able to use pwmMode = 2 or 3.  If you are using the PWM control on the server fan, leave this at default 0.
    // if you have blowers with a monster moto, try pwmMode = 1 or 2 and check whether your monster moto temp at low speeds.
    int pwmMode = 1;        // value of 0, 1, 2 or 3 - modes 2 and 3 will overheat a Monster Moto if used with blowers
    
    // This just works with one variable from the Game Dash.
    int Speed ;
    int SpeedGameDash = 0;
    int bufferArray[4];
    
    int whichFan = BOTH;
    
    void setup()
    {
       Serial.begin(9600);
    
       // initialize digital pins as outputs
       for (int i=0; i<2; i++)
       {
          pinMode(inApin[i], OUTPUT);
          pinMode(inBpin[i], OUTPUT);
          pinMode(pwmpin[i], OUTPUT);
          digitalWrite(inApin[i], LOW);
          digitalWrite(inBpin[i], LOW);
       }
    
       // disable timer0's interrupt handler - this will disable Arduino's time keeping functions such as delay()
       TIMSK0 &= B11111110;
    
       if (pwmMode == 1)
       {
          // Set pins 5 & 6 to Phase-correct PWM of 3.9 kHz (prescale factor of 8)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
          TCCR0B = _BV(CS01);  // prescaler of 8, gives frequency 61kHz/8/2 = 3.9kHz
       }
       else if (pwmMode == 2)
       {
          // Set pins 5 & 6 to Fast PWM of 7.8 kHz (prescale factor of 8)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
          TCCR0B = _BV(CS01);  // prescaler of 8, gives frequency 61kHz/8 = 7.8kHz
       }
       else if (pwmMode == 3)
       {
          // Set pins 5 & 6 to Phase-correct PWM of 31.25 kHz (prescale factor of 1)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
          TCCR0B = _BV(CS00); // prescaler of 1, gives frequency 61kHz/1/2 = 31.25kHz
       }
       else
       {
          // Set pins 5 & 6 to Fast PWM of 980Hz (prescale factor of 64)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
          TCCR0B = _BV(CS01) | _BV(CS00);  // prescaler of 64, gives frequency 61kHz/64 = 980Hz
       }
    }
    
    void loop(){
    
    ReadDataNEW();
    
    if (whichFan == BOTH){
      motorGo(0, CW, SpeedGameDash);      //Motor1
      motorGo(1, CW, SpeedGameDash);      //Motor2
      if (SpeedGameDash == 0) motorOff(0);
      if (SpeedGameDash == 0) motorOff(1);
      }
    
    if (whichFan == LEFT){
      motorGo(0, CW, SpeedGameDash);      //Motor1
      if (SpeedGameDash == 0) motorOff(0);
      }
    
    if (whichFan == RIGHT){
      motorGo(1, CW, SpeedGameDash);      //Motor2
      if (SpeedGameDash == 0) motorOff(1);
      }
    }
    
    void motorOff(int motor)
    {
    // Initialize braked
    for (int i=0; i<2; i++)
    {
       digitalWrite(inApin[i], LOW);
       digitalWrite(inBpin[i], LOW);
    }
    analogWrite(pwmpin[motor], Speed);
    }
    
    void motorGo(uint8_t motor, uint8_t direct, uint8_t Speed)
    {
    if (motor <= 1)
    {
       if (direct <=4)
       {
         // Set inA[motor]
         if (direct <=1)
           digitalWrite(inApin[motor], HIGH);
         else
           digitalWrite(inApin[motor], LOW);
    
         // Set inB[motor]
         if ((direct==0)||(direct==2))
           digitalWrite(inBpin[motor], HIGH);
         else
           digitalWrite(inBpin[motor], LOW);
         analogWrite(pwmpin[motor], Speed);
       }
    }
    }
    
    void ReadDataNEW(){
    
      // We need 4 characters - the command followed by three digits
    
      bool haveCommand = FALSE;
      bool haveStart = FALSE;
    
      while (haveCommand == FALSE){     // can't exit until have a full valid cddd command
                                        // where c is a valid char and ddd is a valid 3
                                        // character representation of three digits
    
        // Valid command always starts with an S (legacy for both fans), L (left fan), or R (right fan)
        while (haveStart == FALSE){
          while (Serial.available() == 0); // spin and wait for data
          bufferArray[0] = Serial.read(); // have data, read it
    
          if (bufferArray[0] == 'S'){  //S
            whichFan = BOTH;
            haveStart = TRUE;
          }
          else if (bufferArray[0] == 'L'){   //L
            whichFan = LEFT;
            haveStart = TRUE;
          }
          else if (bufferArray[0] == 'R'){   //R
            whichFan = RIGHT;
            haveStart = TRUE;
          }
        }
    
        // Now need the numbers - will just read three and throw them away if any don't qualify
        // if we unsynchronize, it will fail valid digits and go back to waiting for command char
    
        for (int i = 1; i < 4; i++){       // read and label each byte.
          while (Serial.available() == 0); // spin and wait for 3 characters to arrive
          bufferArray[i] = Serial.read();  // store as they come in
        }
    
        // Check the numbers for validity
        if (isDigit(bufferArray[1]) && isDigit(bufferArray[2]) && isDigit(bufferArray[3])){
          // all are numbers - have a full cddd command
          haveCommand = TRUE;   // otherwise start over looking for a new and valid command
        }
      }
    
      // Now turn that into a number and clip to 255 - rely on Game Dash for proper scaling
      SpeedGameDash = ((bufferArray[1]-48)*100) + ((bufferArray[2]-48)*10) + ((bufferArray[3]-48)*1);
      //Serial.println(SpeedGameDash);
      if (SpeedGameDash > 255){
        SpeedGameDash = 255;
      }
    }
    
    void ReadDataOLD(){
      if (Serial.available() == 4)  {    //if 4 bytes available in the Serial buffer...
    
            int i;
            for (i=0; i<4; i=i+1) {       // read and label each byte.
                   bufferArray[i] = Serial.read();
             }
    
             if (bufferArray[0]  == 'S'){
               SpeedGameDash = ((bufferArray[1]-48)*100) + ((bufferArray[2]-48)*10) + // Take values 1-3.
                                   ((bufferArray[3]-48)*1);
                    //Serial.println(SpeedGameDash);
                    if (SpeedGameDash > 255){
                                    SpeedGameDash = 255;
                    } 
        
               //Serial.print("You have set the Speed to a Value of:");
               //Serial.println(SpeedGameDash);
          }
       }
    }
    
    [/QUOTE]
    • Like Like x 3
  3. Zed

    Zed VR Simming w/Index Gold Contributor

    Joined:
    Apr 4, 2017
    Messages:
    890
    Location:
    USA
    Balance:
    4,909Coins
    Ratings:
    +892 / 3 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    Well, another wow! It was a longshot that it would fix things but I’m glad it did! Excellent!

    What dutiti is talking about is a few of us are wanting to get “windiness” to work where we combine canopy position with RPM and airspeed to give the wind a bit more fidelity and have it follow other cues. Since we were looking into the plugin and working with the telemetry, I though about controlling the fans individually and rewrote parts of the Arduino fan code to add R and L to the existing S command. S commands still work and set both fans, but if any plugins add the capability for differential wind, it’s in there. Where I was going is in aircraft you can slip and crab too and not have wind always on the centerline. Mixing slip indicator angle into the wind speed and controlling the fans individually lets you mimic lots of aircraft situations.

    But while I was in the code I reworked the USB communications to include error checking to prevent bad commands and stay synchronized. I found I had to issue commands multiple times in the Arduino monitor program when testing but now it works every time. Apparently it fixed whatever was happening in dutiti's rig too.

    @dutiti - thanks for testing that and glad it fixed your issue!

    Here is where we were discussing windiness: https://www.xsimulator.net/community/threads/new-output-possibilities-for-dcs.10181/

    And if anyone is interested, I swapped for a new fan on the market that is a bit more expensive but they work like a champ and the fan noise is way lower. No separate power supply or Monster Moto needed. Dual ball bearings. No squeals or tics as with the bilge fans: https://www.xsimulator.net/community/threads/wind-simulator-fans.14124/
    • Like Like x 1
    Last edited: Jan 22, 2020
  4. Zed

    Zed VR Simming w/Index Gold Contributor

    Joined:
    Apr 4, 2017
    Messages:
    890
    Location:
    USA
    Balance:
    4,909Coins
    Ratings:
    +892 / 3 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    If anyone is interested, here is a trimmed down version. Unified things a bit.

    Edited - introduced a bug. Fixed Also, I'm not using Monster Moto so I can't say this one works with those. I think it does but am unfamiliar with the code that controls them. Hence the bug. Sorry.

    Code:
    #define FALSE 0
    #define TRUE 1
    
    #define BRAKEVCC 0
    #define CW   1
    #define CCW  2
    #define BRAKEGND 3
    #define CS_THRESHOLD 100
    
    #define BOTH 0
    #define LEFT 1
    #define RIGHT 2
    
    int inApin[2] = {7, 4};  // INA: Clockwise output
    int inBpin[2] = {8, 9}; // INB: Counter-clockwise output
    int pwmpin[2] = {5, 6}; // PWM output
    int cspin[2] = {2, 3}; // CS: Current sense ANALOG input
    int enpin[2] = {0, 1}; // EN: Status of switches output (Analog pin)
    int statpin = 13;
    
    // pwmMode - sets the PWM frequency, valid options as follows:
    // pwmMode = 0 will use 980Hz PWM, default mode which will work with all fan types, will cause coil whine if using a MM.
    // pwmMode = 1 will use 4kHz PWM, might reduce coil whine for blowers, use heatsinks on the MM - check MM temp at a low fan speed.
    // pwmMode = 2 will use 8kHz PWM, might be OK for blowers with active cooling on the MM - check MM temp at a low fan speed.
    // pwmMode = 3 will use 31kHz PWM, use with caution - not for blowers with MM as it will cause very high temps. Check MM temp at a low fan speed.
    // server fans - should be able to use pwmMode = 2 or 3.  If you are using the PWM control on the server fan, leave this at default 0.
    // if you have blowers with a monster moto, try pwmMode = 1 or 2 and check whether your monster moto temp at low speeds.
    int pwmMode = 1;        // value of 0, 1, 2 or 3 - modes 2 and 3 will overheat a Monster Moto if used with blowers
    
    int Speed = 0;
    int bufferArray[4];
    int whichFan = BOTH;
    
    void setup()
    {
       Serial.begin(9600);
       // initialize digital pins as outputs
       for (int i=0; i<2; i++)
       {
          pinMode(inApin[i], OUTPUT);
          pinMode(inBpin[i], OUTPUT);
          pinMode(pwmpin[i], OUTPUT);
          digitalWrite(inApin[i], LOW);
          digitalWrite(inBpin[i], LOW);
       }
       // disable timer0's interrupt handler - this will disable Arduino's time keeping functions such as delay()
       TIMSK0 &= B11111110;
       if (pwmMode == 1)
       {
          // Set pins 5 & 6 to Phase-correct PWM of 3.9 kHz (prescale factor of 8)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
          TCCR0B = _BV(CS01);  // prescaler of 8, gives frequency 61kHz/8/2 = 3.9kHz
       }
       else if (pwmMode == 2)
       {
          // Set pins 5 & 6 to Fast PWM of 7.8 kHz (prescale factor of 8)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
          TCCR0B = _BV(CS01);  // prescaler of 8, gives frequency 61kHz/8 = 7.8kHz
       }
       else if (pwmMode == 3)
       {
          // Set pins 5 & 6 to Phase-correct PWM of 31.25 kHz (prescale factor of 1)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
          TCCR0B = _BV(CS00); // prescaler of 1, gives frequency 61kHz/1/2 = 31.25kHz
       }
       else
       {
          // Set pins 5 & 6 to Fast PWM of 980Hz (prescale factor of 64)
          TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
          TCCR0B = _BV(CS01) | _BV(CS00);  // prescaler of 64, gives frequency 61kHz/64 = 980Hz
       }
    }
    
    void loop(){
    ReadData();
    if (whichFan == BOTH){
      motorGo(0, CW, Speed);      //Motor1
      motorGo(1, CW, Speed);      //Motor2
      if (Speed == 0) motorOff(0);
      if (Speed == 0) motorOff(1);
      }
    if (whichFan == LEFT){
      motorGo(0, CW, Speed);      //Motor1
      if (Speed == 0) motorOff(0);
      }
    if (whichFan == RIGHT){
      motorGo(1, CW, Speed);      //Motor2
      if (Speed == 0) motorOff(1);
      }
    }
    
    void motorOff(int motor){
    // Initialize braked
    for (int i=0; i<2; i++){
      digitalWrite(inApin[i], LOW);
      digitalWrite(inBpin[i], LOW);
      }
    analogWrite(pwmpin[motor], Speed);
    }
    
    void motorGo(uint8_t motor, uint8_t direct, uint8_t Speed){
    if (motor <= 1){
      if (direct <=4){
        // Set inA[motor]
        if (direct <=1)
          digitalWrite(inApin[motor], HIGH);
        else
          digitalWrite(inApin[motor], LOW);
        analogWrite(pwmpin[motor], Speed);
        // Set inB[motor]
        if ((direct==0)||(direct==2))
          digitalWrite(inBpin[motor], HIGH);
        else
          digitalWrite(inBpin[motor], LOW);
        analogWrite(pwmpin[motor], Speed);
        }
      }
    }
    
    void ReadData(){
      // We need 4 characters - the command followed by three digits
      bool haveCommand = FALSE;
      bool haveStart = FALSE;
     
      while (haveCommand == FALSE){     // can't exit until have a full valid cddd command
                                        // where c is a valid char and ddd is a valid 3
                                        // character representation of three digits
        // Valid command always starts with an S (legacy for both fans), L (left fan), or R (right fan)
        while (haveStart == FALSE){
          while (Serial.available() == 0); // spin and wait for data
          bufferArray[0] = Serial.read(); // have data, read it
        
          if (bufferArray[0] == 'S'){  //S
            whichFan = BOTH;
            haveStart = TRUE;
          }
          else if (bufferArray[0] == 'L'){   //L
            whichFan = LEFT;
            haveStart = TRUE;
          }
          else if (bufferArray[0] == 'R'){   //R
            whichFan = RIGHT;
            haveStart = TRUE;
          }
        }
        // Now need the numbers - will just read three and throw them away if any don't qualify
        // if we unsynchronize, it will fail valid digits and go back to waiting for command char
      
        for (int i = 1; i < 4; i++){       // read and label each byte.
          while (Serial.available() == 0); // spin and wait for each character to arrive
          bufferArray[i] = Serial.read();  // store as they come in
        }
      
        // Check the numbers for validity
        if (isDigit(bufferArray[1]) && isDigit(bufferArray[2]) && isDigit(bufferArray[3])){
          // all are numbers - have a full cddd command
          haveCommand = TRUE;   // otherwise start over looking for a new and valid command
        }  
      }
      // Now turn that into a number and clip to 255 - rely on Game Dash for proper scaling
      Speed = ((bufferArray[1]-48)*100) + ((bufferArray[2]-48)*10) + ((bufferArray[3]-48)*1);
      //Serial.println(SpeedGameDash);
      if (Speed > 255){
        Speed = 255;
      }
    }
    
    • Winner Winner x 1
    Last edited: Jan 22, 2020
  5. Wmacky

    Wmacky New Member

    Joined:
    Aug 11, 2019
    Messages:
    2
    Balance:
    23Coins
    Ratings:
    +0 / 0 / -0
    My Motion Simulator:
    2DOF, AC motor, Arduino, Motion platform


    I assume the zip file was deleted?
  6. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    15,361
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    112,932Coins
    Ratings:
    +9,088 / 46 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
  7. Wmacky

    Wmacky New Member

    Joined:
    Aug 11, 2019
    Messages:
    2
    Balance:
    23Coins
    Ratings:
    +0 / 0 / -0
    My Motion Simulator:
    2DOF, AC motor, Arduino, Motion platform
    Thanks.
    Yeah, I see It's are being sold commercially now with kit. Ah well, Time to polish up my design skills ( OR grab an alternative from Thingverse.)
  8. tomkil192

    tomkil192 Member

    Joined:
    Jun 25, 2015
    Messages:
    62
    Location:
    Uk. London
    Balance:
    117Coins
    Ratings:
    +21 / 0 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino
    I love the idea. I could use server fans. Can I use the Dash with DIY licence?
  9. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    15,361
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    112,932Coins
    Ratings:
    +9,088 / 46 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    • Like Like x 1
    Last edited: Apr 9, 2020
  10. paulopsx2

    paulopsx2 Active Member

    Joined:
    Apr 2, 2016
    Messages:
    480
    Location:
    brasil
    Balance:
    339Coins
    Ratings:
    +105 / 0 / -0
    My Motion Simulator:
    2DOF, Arduino, Motion platform
    well, $30 its superb price for all these features. Other softwares like simexperience = more than "twice price"
    • Agree Agree x 1
  11. tomkil192

    tomkil192 Member

    Joined:
    Jun 25, 2015
    Messages:
    62
    Location:
    Uk. London
    Balance:
    117Coins
    Ratings:
    +21 / 0 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino
    Hi Everyone.
    Would you be able to tell me what im doing wrong? Fan will not move and no voltage on the MM output.

    upload_2020-6-7_14-2-39.png
  12. tomkil192

    tomkil192 Member

    Joined:
    Jun 25, 2015
    Messages:
    62
    Location:
    Uk. London
    Balance:
    117Coins
    Ratings:
    +21 / 0 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino
    False alarm. MM was sending low values on A1B1. I have measured A2 B2. Connected fan and all works!!
    Version Alpha completed.
    Well done guys
    • Like Like x 1
  13. Trigen

    Trigen Active Member

    Joined:
    Nov 25, 2018
    Messages:
    400
    Balance:
    2,614Coins
    Ratings:
    +129 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino
    Could this be adapted to running motors in Torque mode for G helmet and other G systems?
  14. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    15,361
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    112,932Coins
    Ratings:
    +9,088 / 46 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    You can use SimTools motion features for G-Systems, its companion app GameDash is for associated peripherals such as wind simulation.
  15. cfischer

    cfischer Active Member Gold Contributor

    Joined:
    Sep 7, 2015
    Messages:
    178
    Location:
    Colorado
    Balance:
    1,193Coins
    Ratings:
    +95 / 0 / -0
    You can use this code as is (im pretty sure) to move a motor in torque mode.
    But it would probably be better to simplify another sketch with more than one motor output and a better motor drive.