1. Do not share user accounts! Any account that is shared by another person will be blocked and closed. This means: we will close not only the account that is shared, but also the main account of the user who uses another person's account. We have the ability to detect account sharing, so please do not try to cheat the system. This action will take place on 04/18/2023. Read all forum rules.
    Dismiss Notice
  2. 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!
  3. 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
  4. 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

SimTools Presets Can a single actuator be used for negative and positive sides of the same DOF?

Discussion in 'Game Engine Interface presets' started by Jumping Coin, Sep 26, 2020.

  1. Jumping Coin

    Jumping Coin Member

    Joined:
    Aug 7, 2020
    Messages:
    93
    Balance:
    70Coins
    Ratings:
    +54 / 0 / -0
    Hi,

    Is it possible to have a single actuator be used for the negative and positive sides of the same DOF?

    Long story short, I've created a pneumatic g-seat and I had an extra servo, so I decided to use it to add a little spin to my office chair. Everything works (build coming soon!), but I want to set up the servo that spins the office chair to respond to both left sway and right sway. I've tried a couple of things, but so far I can only get the servo to respond to one direction of the DOF (ie sway left or sway right). So far, I've tried setting up two separate axes (Axis5a and Axis6a in screenshot below), both of which are 50% sway in both directions, but that didn't work.

    upload_2020-9-25_23-21-31.png


    I've also tried mapping the same servo twice in the code under different labels, but that didn't work either. I'm stumped.

    In case it helps, I'm using the g-seat code, which I guess only responds to one side of a DOF, so perhaps I need to use some other code to allow for both directions?

    I'm totally new to this, so apologies if I'm asking a super obvious question. I've spent a good deal of time searching but I might be using the wrong keywords. I'm currently using the Generic 2D Basic, and while I've read all of the SimTools documentation, I could easily be overlooking a feature in the advanced Axis Type setup.

    Any help would be immensely appreciated. Thanks!
  2. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    21,058
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    148,046Coins
    Ratings:
    +10,885 / 54 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
  3. Jumping Coin

    Jumping Coin Member

    Joined:
    Aug 7, 2020
    Messages:
    93
    Balance:
    70Coins
    Ratings:
    +54 / 0 / -0
    Thanks so much for the quick reply, Noorbeast!

    Here's a link of my office chair spinning from the servo (without using Simtools):

    Attached is also the code that I'm using (office chair spin is using servo "E", pin 8, currently mapped to Axis5a), which has been adapted from here:
    https://www.xsimulator.net/communit...imulator-dof-reality.8570/page-43#post-166682

    The code seems to work (g-seat works fine), and I can get everything to respond to Simtools. However, I want just this one servo to spin from 0 to 90 degrees for one direction of sway (e.g. sway left) and 91 to 180 degrees for the other direction of sway (e.g. sway right).

    Right now the best I can get in Simtools is to specify one direction of sway for the servo. Here's a video of the office chair spinning using it's full 180 degree rotation for only one direction of sway in Simtools Output: Testing:

    Basically, the servo responds to 0 to 100 but not 0 to -100. This is how my current Axis Assignments are set up. I'm sure it needs to be modified, but I'm just not sure how.
    upload_2020-9-26_12-32-34.png

    If this solution requires coding changes, would you be able to point me to any example code where the actuator is used for both the directions for a particular DOF?

    Thanks so much!

    Attached Files:

    • Funny Funny x 1
  4. Gadget999

    Gadget999 Well-Known Member

    Joined:
    Dec 27, 2015
    Messages:
    1,935
    Location:
    London
    Balance:
    11,838Coins
    Ratings:
    +473 / 9 / -0
    My Motion Simulator:
    2DOF, DC motor, Arduino, 6DOF
    search for the SMC3 arduino code
  5. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    21,058
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    148,046Coins
    Ratings:
    +10,885 / 54 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    Try using @eaorobbie's RC servo code, as previously suggested: http://www.xsimulator.net/community/threads/2dof-simulator-servo-model.6851/#post-77270
  6. Jumping Coin

    Jumping Coin Member

    Joined:
    Aug 7, 2020
    Messages:
    93
    Balance:
    70Coins
    Ratings:
    +54 / 0 / -0
    Thanks @noorbeast and @Gadget999!

    Apparently I've been using @eorobbie's RC servo code all along and hadn't realized. The code must have been modified for the g-seat, which was causing the unwanted behavior with the chair spin. What confused me was that @eaorobbie's thread https://www.xsimulator.net/community/threads/rc-model-for-motion-simulation.4600/ has a zip attachment as well as a code block, and both are different code sets. I was originally looking at the zip attachment, which may have been an earlier version of the code, and it was much harder for me to follow. However, the code in the code block is actually what I've been using as the basis for the g-seat. A quick if statement and one extra line of code was all it took to fix the issue.

    For reference, here's my updated code, which now works. (I'll also be posting it in my build thread).

    Code:
    /************************************************/
    // Title:    Pneumatic G-Seat using 4 servos (A, B, C, D); Office Chair Spin using 1 servo (E)
    // Function: For use with Simtools software, apply sway, heave
    // Code adapted from: https://www.xsimulator.net/community/threads/low-cost-2dof-3dof-6dof-motion-simulator-dof-reality.8570/page-43#post-166682,
    // which had been adapted from https://www.xsimulator.net/community/threads/rc-model-for-motion-simulation.4600/
    //
    /************************************************/
    /*
    Values for interface:
      Interface Type : Serial
      Comport : is at every individual
      BitsPerSec : 9600
      Data Bits : 8
      Parity : None
      Stop Bits : 1
      Bit Range : 8
      Output Type : Decimal
      Interface Output : A<Axis1a>~B<Axis2a>~C<Axis3a>~D<Axis4a>~E<Axis5a>~E<Axis6a>~
      Output Rate : 10ms
    
    Pins:
      7 = G-Seat Left  Top    (A)
      4 = G-Seat Left  Bottom (B)
      6 = G-Seat Right Top    (C)
      5 = G-Seat Right Bottom (D)
      8 = Office Chair Spin   (E)
    */
    
    #include <Servo.h>
    
    const int kActuatorCount = 5; // number of servos
    const char kActuatorName[kActuatorCount] = { 'A', 'B', 'C', 'D', 'E'};
    const int kPins[kActuatorCount] = {7, 4, 6, 5, 8};
    Servo actuatorSet[kActuatorCount];                  // our array of Actuators
    
    int actuatorPosition[kActuatorCount]={90, 90, 90, 90, 90};
    const int kActuatorScale[kActuatorCount][6] = {
                                                      {40, 180},
                                                      {40, 180},
                                                      {40, 180},
                                                      {40, 180},
                                                      {40, 180}
                                                  };    
    
    const char kEOL = '~';                              // End of Line - the delimiter for our acutator values
    const int kMaxCharCount = 3;                        // some insurance...
    
    // set up some states for our state machine
    // psReadActuator = next character from serial port tells us the Actuator
    // psReadValue = next 3 characters from serial port tells us the value
    enum TPortState
    {
      psReadActuator,
      psReadValue
    };  
    
    int currentActuator;                                // keep track of the current Actuator being read in from serial port
    int valueCharCount = 0;                             // how many value characters have we read (must be less than kMaxCharCount!!
    
    TPortState currentState = psReadActuator;
    
    void setup()
    {
        // attach the Actuators to the pins
        for (int i = 0; i < kActuatorCount; i++)
            actuatorSet[i].attach(kPins[i]);
    
        // initialise actuator position
        for (int i = 0; i < kActuatorCount; i++)
            updateActuator(i);
         
        Serial.begin(9600); // opens serial port at a baud rate of 9600
    }
    /*************************************************/
    void loop()
    {
    }
    /**************************************************/
    // write the current Actuator position to the passed in Actuator
    void updateActuator(int thisActuator) {
        int safePos;
        safePos=actuatorPosition[thisActuator];
    //    safePos=100;
        actuatorSet[thisActuator].write(safePos);
    }
    
    // this code only runs when we have serial data available. ie (Serial.available() > 0).
    void serialEvent() {
        char tmpChar;
        int tmpValue;
     
        while (Serial.available()) {
            // if we're waiting for a Actuator name, grab it here
            if (currentState == psReadActuator) {
                tmpChar = Serial.read();
                // look for our actuator in the array of actuator names we set up
    
                #ifdef DEBUG          
                  Serial.print("read in ");          
                  Serial.println(tmpChar);          
                #endif
    
                for (int i = 0; i < kActuatorCount; i++) {
                    if (tmpChar == kActuatorName[i]) {
                        #ifdef DEBUG          
                        Serial.print("which is actuator ");          
                        Serial.println(i);          
                        #endif
                        currentActuator = i;                        // remember which actuator we found
                        currentState = psReadValue;                 // start looking for the Actuator position
                        actuatorPosition[currentActuator] = 0;      // initialise the new position
                        valueCharCount = 0;                         // initialise number of value chars read in
                          break;
                    }
                }
            }
           
            // if we're ready to read in the current Actuator's position data
            if (currentState == psReadValue) {
                while ((valueCharCount < kMaxCharCount) && Serial.available()) {
                    tmpValue = Serial.read();
                    if (tmpValue != kEOL) {
                        tmpValue = tmpValue - 48;
                        if ((tmpValue < 0) || (tmpValue > 9)) tmpValue = 0;
                        actuatorPosition[currentActuator] = actuatorPosition[currentActuator] * 10 + tmpValue;
                        valueCharCount++;
                    }
                    else break;
                }
               
                // if we've read the value delimiter, update the Actuator and start looking for the next Actuator name
                if (tmpValue == kEOL || valueCharCount == kMaxCharCount) {
     
                    #ifdef DEBUG          
                        Serial.print("read in ");          
                        Serial.println(actuatorPosition[currentActuator]);          
                    #endif
     
     
                    // If working with G-Seat servos
                    if (currentActuator < 4)
                    {
                        //No -ve on G-seat : 90 = middle
                        if (actuatorPosition[currentActuator]<127)
                        {
                            actuatorPosition[currentActuator]=127;
                        }
                        // scale the new position
                        // Range is now 0 - 255
                        // Maps between min and max
                        actuatorPosition[currentActuator] = map(actuatorPosition[currentActuator], 127, 255, kActuatorScale[currentActuator][0], kActuatorScale[currentActuator][1]);
                    }
                   
                    //Else this is the servo for spinning the chair
                    else
                    {
                        actuatorPosition[currentActuator] = map(actuatorPosition[currentActuator], 0, 255, kActuatorScale[currentActuator][0], kActuatorScale[currentActuator][1]);
                    }
                   
                    #ifdef DEBUG          
                        Serial.print("scaled to ");          
                        Serial.println(actuatorPosition[currentActuator]);          
                    #endif
     
                    updateActuator(currentActuator);
                    currentState = psReadActuator;
                }
            }
        }
    }
    Thanks again! And thanks to @eorobbie for initially posting the code!
    • Like Like x 1