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 Download Package Now!
  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 here. Do not following these rules will lead to permanent exclusion from this website: Read the forum rules.

Showroom FlyPT - 6DOF Brushless DIY Actuators

Discussion in 'DIY Motion Simulator Projects' started by pmvcda, Aug 29, 2017.

  1. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Hi,

    First time posting, but sneaking for a long long time (sorry for some English errors I might post).
    So some of the guys here are guilty! Yes, I started to build a 6DOF motion simulator with DIY actuators.
    SeatTimes, SilentChill and some others, you are an inspiration.
    I think my wife hates you guys... ;)

    So, for some years I've been looking at motion sims, but since my desire was always cars and air planes, I always thought that less than 6DOF would kill the aircraft experience (probably I'm wrong).
    But now with so many 6DOF builds, specially with actuators, I though it's the time to start my build.

    Well it already started some months ago, but free time is always a problem.
    I will make some posts to put at the start of this thread the current project development.
    I will make the following topics:
    -Videos and photos (latest images and videos of the construction)
    -Parts (list of all parts, and where I got them)
    -Plans (drawings, schematics and 3D printed parts files)
    -Software (software used, setups and code developed for this project)

    So let's start! Hope my project can help others. And let's hope I can make it.


    (FlyPT is the user I usually use in other forums, but I had it banned here, probably because I was not active for a long time?)
    • Like Like x 1
    • Creative Creative x 1
  2. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Videos and photos
    latest images and videos of the construction

    Video of first test (no PID control).


    Now with two actuators behaving like a 2DOF and with PID control.
    Also changed some parts with better tolerance to reduce vibrations.
    • Like Like x 2
    • Winner Winner x 1
    Last edited: Sep 1, 2017
  3. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Parts
    List of all parts, and where I got them
    No prices, because they are always changing, I don't want to know how much I spend in total :p
    To be updated with some images...


    Motors (6x):
    Nanotec.jpg
    Nanotec DB59C024035-A (brushless).
    1 Bought from Portuguese reseller
    5 Bought at Farnell (http://pt.farnell.com/nanotec/db59c024035-a/bldc-motor-24vdc-4500rpm/dp/2507576 - less than half the price from above )
    Specs: http://en.nanotec.com/fileadmin/files/Datenblaetter/BLDC/DB59/DB59C024035-A.pdf


    Motor drivers (6x):
    BLDC-8015A.jpg
    ACT Motor BLDC-8015A
    Bought on ebay (http://www.ebay.co.uk/itm/252468509819?_trksid=p2060353.m1438.l2649&ssPageName=STRK:MEBIDX:IT).
    Specs: http://www.wantmotor.com/product/8015a.html (From Wantai, but equal to ACT Motor)


    Power supply (1x):
    Mean Well.jpg
    Mean Well RSP-3000-24
    Bought on ebay (http://www.ebay.co.uk/itm/231473165159?_trksid=p2060353.m2749.l2649&var=530732464572&ssPageName=STRK:MEBIDX:IT).
    Specs: http://media.it-tronics.de/Datasheets/Power_Supplies/MeanWell/RSP-3000.pdf


    Microswitches (12x):
    Microswitch.jpg
    Bought on ebay (http://www.ebay.co.uk/itm/282088135235?_trksid=p2060353.m2749.l2649&var=581040167277&ssPageName=STRK:MEBIDX:IT)
    Specs: 16mm lever


    Aluminium tube (6x):
    Aluminium tube.jpg
    Bought from Motedis (http://www.motedis.com/shop/Tube-sy...ular-tube-aluminium-anodized-28x2mm::823.html)
    Specs: 28mm exterior, 2mm wall with 500mm length


    Aluminium profile (12x):
    Aluminium profile.JPG
    Bought from Motedis (http://www.motedis.com/shop/Slot-pr...-slot-5/Profile-20x60-I-Type-slot-5::499.html)
    Specs: 20x60 I-Type slot 5 with 730mm lenght


    Ballscrew (6x):
    Ball screw.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...es/Ball-screw/Ballscrew-SFU1605-DM::1444.html)
    Specs: SFU1605-DM with 542mm (5mm step for each turn with 16mm diameter)


    Nut for ballscrew (6x):
    Ball screw nut.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...ball-screw/Screw-nut-DIN-439-M10x1::2444.html)
    Specs: DIN 439 M10x1


    3D Filament PET-G 1,75mm black (2kg):
    PETG.jpg
    Bought from Motedis (http://www.motedis.com/shop/table_cats.php?table_id=45)


    Flange Bearing (6x)
    Bearing.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...lange-Bearing-10mm-die-cast-KFL000::5212.html)
    Specs: 10mm die-cast aluminium KFL000


    Plain bearing (6x):
    Igus.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...g/Plain-bearing-Igus-GFM-283239-20::1166.html)
    Specs: Igus GFM-283239-20 Type 283239-20


    Screw connector (6x):

    Bought from Motedis (http://www.motedis.com/shop/Tube-sy...-connector-for-circular-tube-28x2mm::900.html)
    Specs: For circular tube 28x2mm with size M8


    Joint head (6x): (REPLACED WITH 6 UNIVERSAL JOINTS)
    Joint head.jpg
    Bought from Motedis (http://www.motedis.com/shop/Mechani...crew-thread-rightward-M8x125-POSA8::1588.html)
    Specs: External screw thread rightward M8x1 25-POSA8


    Flexible clutch (6x):
    Clutch.jpg
    Bought from ebay(http://www.ebay.co.uk/itm/Wellenkup...287275?hash=item3f76fdd8eb:g:MIAAAOSwOgdYynFj)
    Specs: Diameter 25mm Lenght 30mm Shaft diameter 8,00mm/8,00mm


    Universal joint (12x):
    UJoint.jpg
    Bought from ebay (http://www.ebay.co.uk/itm/12mm-Dia-...654174&hash=item2cadada585:g:odAAAOSwuhhXWW89)
    Specs: 12mm Dia Shaft Coupling Motor Connector


    Socket cap Allen screw M5x20 (6x 5x = 30x):
    DIN 7984 M5x20.jpg
    Bought from Motedis (http://www.motedis.com/shop/Mechani...rd-parts/DIN-Screws/Screw-DIN-7984::1114.html)
    Specs: DIN 7984 M5x20


    Flat Allen screw M5x30 (6x 4x = 24x):
    Flat Allen screw M5x30.jpg
    Bought from Motedis (http://www.motedis.com/shop/Mechani...rd-parts/DIN-Screws/Screw-DIN-7991::1120.html)
    Specs: DIN 7991 M5x30


    Socket cap Allen screw M5x20 (6x 16x = 96x):
    Socket cap Allen screw M5x20.jpg
    Bought in conventional hardware stores
    Specs: Socket cap Allen M5x20


    Socket cap Allen screw M4x12 (6x 4x = 24x):
    Socket cap Allen screw M4x12.jpg
    Bought in conventional hardware stores
    Specs: Socket cap Allen M4x12


    Flat slotted screw M5x50 (6x 4x = 24x):
    Flat slotted screw M5x50.jpg
    Bought in conventional hardware stores
    Specs: Flat M5x50


    Cheese head slotted screw M5x60 (6x 9x = 54x):
    Cheese head slotted screw M5x60.jpg
    Bought in conventional hardware stores
    Specs: Cheese M5x60


    Washers M5 (6x 16x = 96x):
    Washer.jpg
    Bought in conventional hardware stores
    Specs: M5


    Self retaining nut M5 (6x 13x = 78x):
    Retaining nut.jpg
    Bought in conventional hardware stores
    Specs: M5


    Nut M5 (6x 1x = 6x):
    Nut.jpg
    Bought in conventional hardware stores
    Specs: M5


    Hex screw M6x25 (6x 2x = 12x)
    Hex screw M6x25.jpg
    Bought in conventional hardware stores
    Specs: Socket cap Allen M6x25


    Washers M6 (6x 4x = 24x):
    washer.jpg
    Bought in conventional hardware stores
    Specs: M6


    Self retaining nut M6 (6x 2x = 12x):
    retaining nut.jpg
    Bought in conventional hardware stores
    Specs: M6


    Rubber ring (12x):
    Rubber ring.jpg
    Bought in conventional hardware stores
    Specs: Rings used in water tubes (here used for vibration isolation)


    D Sub Connectors (6x):
    2294339-40.jpg 2294341-40.jpg 633860-40.jpg
    Bought at Farnell:
    Male: http://pt.farnell.com/norcomp/681s13w3103l001/d-sub-combo-plug-40amp-13way/dp/2294355?st=d sub
    Female: http://pt.farnell.com/norcomp/680s13w3103l401/d-sub-combo-plug-40amp-13way/dp/2294339?st=d sub
    Housing: http://pt.farnell.com/mh-connectors/mhd45zk-25-k/backshell-d-nickel-45dg-25way/dp/633860
    Specs: 3 power pins up to 40A and 10 signal pins up to 5A.


    Other parts needed if using positioning with pot:
    (Not needed if using internal hall sensors for positioning)

    Potentiometers (6x): (REPLACED - SEE BELLOW)
    Potentiometer.jpg
    Bourns 10K 10 turn
    Bought on ebay (http://www.ebay.co.uk/itm/182081894163?_trksid=p2060353.m2749.l2649&var=483220540951&ssPageName=STRK:MEBIDX:IT)
    Specs: http://bro.net.pl/ANDRZEJEK/dokumentywPDF/potentiometer3590s.pdf


    Potentiometers (6x):
    4434310.jpg
    Vishay 10K 10 turn
    Bought at Farnell (http://pt.farnell.com/vishay/536-1-1-103/wirewound-potentiometer-10kohm/dp/1386483?st=vishay pot)
    Specs: http://www.farnell.com/datasheets/2...MI_oTz8b3L2wIVhPdRCh08AQzXEAAYAiAAEgLrj_D_BwE


    Idler wheel for 6mm wide belt (6x):
    Idler wheel.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...-6mm/Idler-wheel-for-6mm-wide-belt::4523.html)
    Specs: 6mm wide with 18mm outside diameter


    Aluminium pulley (6x):
    6mm GT2 pulley with 24 teeth.jpg
    Bought on ebay (http://www.ebay.co.uk/itm/152084840946?_trksid=p2060353.m2749.l2649&var=451287689730&ssPageName=STRK:MEBIDX:IT)
    Specs: 24 teeth pulley for 6mm GT2 belt


    6mm GT2 belt (10m):
    6mm GT2 belt.jpg
    Bought from Motedis (http://www.motedis.com/shop/Dynamic...mm/GT2-Open-Timing-Belt-6mm-1000mm::4251.html)
    Specs: 6mm GT2 belt
    • Informative Informative x 3
    Last edited: Aug 3, 2018
  4. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Plans
    drawings, schematics and 3D printed parts files

    Files with the 3D printed parts for actuators using pot positioning:
    [​IMG]
    File: https://drive.google.com/open?id=1VDiJsNzJmQrOuzEaqN5gCoLyDfJcxLRb

    Files with the 3D printed parts for actuators using internal hall sensor positioning:
    SOON!

    Files with the 3D printed parts for the bottom and upper structure of the Stewart platform:
    SOON!

    Warning!
    Those files are made for my printer. They work for me and they have the right tolerances to fit the aluminium profiles and parts I use.
    They might not work for you. So use them at your own risk.
    They are printed in solid PETG. I think they are strong enough, although due to personal problems I still have to finish my rig to test them with the final load.
    So I don't know if they hold or how long they will hold.
    Also, this is continuously in development and I still might change the design.
    Last edited: Aug 3, 2018
  5. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Software
    Software used, setups and code developed for this project

    INTERNALL HALL SENSOR POSITIONING VERSION WITH ESP32 DEVKIT

    Used software:
    SimTools 2 (got the DIY license)
    LFS (demo version)
    Sketchup to draw all the printed parts (free)
    Cura 2.6 to print 3D parts (free)
    MSPhysics plugin for Sketchup, to test angles and dimensions of rig (free)
    Arduino and needed libraries to program the ESP32 (free)
    Google Chrome to browse this site...

    Developed software:
    ESP32 code that:
    -Calibrates actuators
    -Receives data from SimTools2
    -Implements PID to position actuators
    -Interprets the readings from the internal hall sensors to determine the actuator position

    Update history:

    Version 1:
    -First version, many things to enhance

    Latest version:
    Code:
    SOON!
    

    SimTools2 configuration should be:
    Interface settings:
    Interface Type: Serial
    ComPort: The one used by your ESP32
    BitsPerSec: 57600 (You can change the define to use another speed)
    Data Bits: 8
    Parity: None
    Stop Bits: 1
    Output - Bit Range: 10
    Output - Type: Binary
    Startup - Output: -
    HW Start: -
    Interface output: [1<Axis1a>][2<Axis2a>][3<Axis3a>]
    Output Rate: 10ms
    Shutdown - Output: -
    HW Stop: -

    Since each ESP32 controls 3 actuators, you need two, so you have to configure another one but use the corresponding ComPort and:
    Interface output: [4<Axis4a>][5<Axis5a>][6<Axis6a>]


    POT POSITIONING VERSION WITH ARDUINO UNO
    I moved to the internal hall positioning solution, so this is no longer updated, but here for reference

    Used software:
    SimTools 2 (got the DIY license)
    LFS (demo version)
    Sketchup to draw all the printed parts (free)
    Cura 2.6 to print 3D parts (free)
    MSPhysics plugin for Sketchup, to test angles and dimensions of rig (free)
    Arduino to program the Arduino Uno (free)
    Google Chrome to browse this site...

    Developed software:
    Arduino Uno code that:
    -Calibrates actuators
    -Receives data from SimTools2
    -Implements PID to position actuators

    Update history:

    Version 8:
    -Corrected error in the PID calculation (affected D where error and last error where already equal, returning always zero for D)
    -Remove unnecessary calculus int he PID calculation
    -Commented I calculation, since it's not used and always returns zero

    Version 7:
    -Removed dead zone, no noticeable benefit. One less if.
    -Removed counts when searching for maximum minimum, no noticeable benefit since the analogue read repeats solves this problem.

    Version 6:
    -Add constrain to position value to avoid oscillation when actuator is close to limits and activates the switches (sudden change for min to 0 or max to 1024)
    -Uses two functions for speed reasons, this avoids more if's. One gets position cropped and the other one not cropped.

    Version 5:
    -Remove unused functions
    -Remove optional hack for speed, now it's always implemented

    Version 4:
    -More code optimisation, removing some loops
    -For that, functions where created that receive index of actuator
    -Remove direction from array, it's already stored on the signal of the speed

    Version 3:
    Code optimisation
    Renamed functions for better understanding

    Version 2:
    Add minimum and maximum calibration

    Latest version:
    Code:
    // ============================
    // DIY 6DOF Motion Sim by FlyPT
    // ============================
    // SimTools2 Arduino code to control 6DOF actuators
    // Actuators use brushless motors controlled by BLDC8015A drivers
    
    
    // ===================================
    // Update history - Current: Version 8
    // ===================================
    // Version 8:
    //  Corrected error in the PID calculation (affected D where error and last error where already equal, returning always zero for D)
    //  Remove unecessary calculus inthe PID calculation
    //  Commented I calculation, since it's not used and always returns zero
    // Version 7:
    //  Removed dead zone, no noticeable benefit. One less if.
    //  Removed counts when searching for maximum minimum, no noticeable benefit since the analogue read repeats solves this problem.
    // Version 6:
    //  Add constrain to position value to avoid oscillation when actuator is close to limits and activates the switches (sudden change for min to 0 or max to 1024)
    //  Uses two functions for speed reasons, this avoids more if's. One gets position cropped and the other one not cropped.
    // Version 5:
    //  Remove unused functions
    //  Remove optional hack for speed, now it's always implemented
    // Version 4:
    //  More code optimisation, removing some loops
    //  For that, functions where created that receive index of actuator
    //  Remove direction from array, it's already stored on the signal of the speed
    // Version 3:
    //  Code optimisation
    //  Renamed functions for better understanding
    // Version 2:
    //  Add minimum and maximum calibration
    
    
    // ==================================
    // SimTools2 configuration should be:
    // ==================================
    // Interface settings:
    // Interface Type: Serial
    // ComPort: The one used by your Arduino
    // BitsPerSec: 57600 (You can change the define to use another speed)
    // Data Bits: 8
    // Parity: None
    // Stop Bits: 1
    // Output - Bit Range: 10
    // Output - Type: Binary
    // Startup - Output: -
    // HW Start: -
    // Interface output: [1<Axis1a>][2<Axis2a>][3<Axis3a>][4<Axis4a>][5<Axis5a>][6<Axis6a>]
    // Output Rate: 10ms
    // Shutdown - Output: -
    // HW Stop: -
    
    
    // =======
    // Defines
    // =======
    #define NUMBER_ACTUATORS 6  // Define to set the number of actuators to use
    #define SERIAL_SPEED 57600 // Define to set up the serial speed comunication
    #define CALIBRATION_SPEED 60 // Speed used to search for minimum and maximum values
    #define ENDS_GAP 0 // Value added or subtracted to maximum and minimum positions when calibrating
    #define UP HIGH // Define to set up direction as HIGH
    #define DOWN LOW // Define to se down direction as LOW
    #define POSITION_PIN 0 // Holds index where this information is stored in the actuator array
    #define DIRECTION_PIN 1 // Holds index where this information is stored in the actuator array
    #define SPEED_PIN 2 // Holds index where this information is stored in the actuator array
    #define MINIMUM_POSITION 3 // Holds index where this information is stored in the actuator array
    #define MAXIMUM_POSITION 4 // Holds index where this information is stored in the actuator array
    #define CURRENT_POSITION 5 // Holds index where this information is stored in the actuator array
    #define PRETENDED_POSITION 6 // Holds index where this information is stored in the actuator array
    #define P_PID 7 // Holds index where this information is stored in the actuator array
    #define I_PID 8 // Holds index where this information is stored in the actuator array
    #define D_PID 9 // Holds index where this information is stored in the actuator array
    #define INTEGRATED_ERROR 10 // Holds index where this information is stored in the actuator array
    #define LAST_ERROR 11 // Holds index where this information is stored in the actuator array
    #define SPEED 12 // Holds index where this information is stored in the actuator array
    #define ANALOG_READ_REPEATS 16 // Number of times we get analog read to calculate a medium value (to reduce noise, maximum 32)
    // Defines for setting and clearing register bits (used for speed hack)
    #ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #endif
    #ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #endif
    #define LOWBYTE(v)   ((unsigned char) (v))        //Read
    #define HIGHBYTE(v)  ((unsigned char) (((unsigned int) (v)) >> 8))
    #define BYTELOW(v)   (*(((unsigned char *) (&v) + 1)))      //Write
    #define BYTEHIGH(v)  (*((unsigned char *) (&v)))
    
    
    // ======================
    // Actuators information:
    // ======================
    // 0  - POSITION_PIN       - Pin to capture position from pot
    // 1  - DIRECTION_PIN      - Pin to se direction
    // 2  - SPEED_PIN          - Pin to set speed with PWM
    // 3  - MINIMUM_POSITION   - Minimum position
    // 4  - MAXIMUM_POSITION   - Maximum position
    // 5  - CURRENT_POSITION   - Current position
    // 6  - PRETENDED_POSITION - Pretended position
    // 7  - P_PID              - P from PID
    // 8  - I_PID              - I from PID
    // 9  - D_PID              - D from PID
    // 10 - INTEGRATED_ERROR   - Sum of differences between pretended and current position
    // 11 - LAST_ERROR         - Last difference between pretended and current position
    // 12 - SPEED              - Speed of motor rotation
    int actuator[6][13] = {
      {A0,  2,  3, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0},   //actuator 1
      {A1,  4,  5, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0},   //actuator 2
      {A2,  7,  6, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0},   //actuator 3
      {A3,  8,  9, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0},   //actuator 4
      {A4, 12, 10, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0},   //actuator 5
      {A5, 13, 11, 1023, 0, 0, 511, 100, 0, 100, 0, 0, 0}    //actuator 6
    };
    int buffer = 0; // To hold current read fom SimTools command
    int bufferCount = -1; // To hold position in bufferCommand array
    int bufferCommand[5] = {0}; // To hold command info from SimTools
    
    
    // ==============
    // Initialization
    // ==============
    void setup()
    {
      // Initialize serial comunication with SimTools2
      Serial.begin(SERIAL_SPEED);
      // Initialize pins
      for (byte n = 0; n < NUMBER_ACTUATORS; n++)
      {
        pinMode(actuator[n][POSITION_PIN], INPUT); // Pin to get position of actuator (0 to 1023)
        pinMode(actuator[n][DIRECTION_PIN], OUTPUT); // Pin to specify direction of rotation (0 or 1)
        pinMode(actuator[n][SPEED_PIN], OUTPUT); // Pin to specify speed (0 to 255)
      }
      // Speed up the arduino analogue read function setting analogue prescale to 16
      sbi(ADCSRA, ADPS2) ;
      cbi(ADCSRA, ADPS1) ;
      cbi(ADCSRA, ADPS0) ;
      // Calibrate actuators, searching for minimums and maximums
      calibrate();
    }
    
    
    // =======================================================================
    // Get actuator position (used in calibration to find minimum and maximum)
    // =======================================================================
    void getCurrentPosition(byte n)
    {
      // Make one reading
      actuator[n][CURRENT_POSITION] = analogRead(actuator[n][POSITION_PIN]);
      // Get determined number of readings and add them all
      for (byte m = 1; m < ANALOG_READ_REPEATS; m++) actuator[n][CURRENT_POSITION] += analogRead(actuator[n][POSITION_PIN]);
      // Divide to get medium value of the readings
      actuator[n][CURRENT_POSITION] /= ANALOG_READ_REPEATS;
    }
    
    
    // =======================================================================================
    // Get's actuators position constrained to maximum and minimum values found on calibration
    // =======================================================================================
    void getConstrainCurrentPosition(byte n)
    {
      // Make one reading
      actuator[n][CURRENT_POSITION] = analogRead(actuator[n][POSITION_PIN]);
      // Get determined number of readings and add them all
      for (byte m = 1; m < ANALOG_READ_REPEATS; m++) actuator[n][CURRENT_POSITION] += analogRead(actuator[n][POSITION_PIN]);
      // Divide to get medium value of the readings
      actuator[n][CURRENT_POSITION] /= ANALOG_READ_REPEATS;
      // Constrain position value to minimum/maximum range (this avoids oscilation when limit switches are activated)
      constrain(actuator[n][CURRENT_POSITION], actuator[n][MINIMUM_POSITION], actuator[n][MAXIMUM_POSITION]);
    }
    
    
    // =============================
    // Get information from SimTools
    // =============================
    void getSimToolsCommands()
    {
      // Look for start and finish of a command on the serial
      // When we have a command send it form analyze
      while (Serial.available())
      {
        if (bufferCount == -1)
        {
          buffer = Serial.read();
          if (buffer != '[') bufferCount = -1;
          else bufferCount = 0;
        }
        else
        {
          buffer = Serial.read();
          bufferCommand[bufferCount] = buffer;
          bufferCount++;
          if (bufferCount > 3)
          {
            if (bufferCommand[3] == ']') analyzeSimToolsCommand();
            bufferCount = -1;
          }
        }
      }
    }
    
    
    // ================================
    // Analyze command sent by SimTools
    // ================================
    void analyzeSimToolsCommand()
    {
      // Analyze command, see if it's a command and wich actuator is affected
      switch (bufferCommand[0])
      {
        case '1':
          actuator[0][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[0][MINIMUM_POSITION], actuator[0][MAXIMUM_POSITION]);
          break;
        case '2':
          actuator[1][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[1][MINIMUM_POSITION], actuator[1][MAXIMUM_POSITION]);
          break;
        case '3':
          actuator[2][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[2][MINIMUM_POSITION], actuator[2][MAXIMUM_POSITION]);
          break;
        case '4':
          actuator[3][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[3][MINIMUM_POSITION], actuator[3][MAXIMUM_POSITION]);
          break;
        case '5':
          actuator[4][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[4][MINIMUM_POSITION], actuator[4][MAXIMUM_POSITION]);
          break;
        case '6':
          actuator[5][PRETENDED_POSITION] = map((bufferCommand[1] * 256) + bufferCommand[2], 0, 1023, actuator[5][MINIMUM_POSITION], actuator[5][MAXIMUM_POSITION]);
          break;
        default:
          return;
          break;
      }
    }
    
    
    // ==========================================================
    // Calculate PID for each actuator and update actuators array
    // ==========================================================
    void calculatePID(byte n)
    {
      float error = (float)actuator[n][PRETENDED_POSITION] - (float)actuator[n][CURRENT_POSITION];
      actuator[n][INTEGRATED_ERROR] += error;
      float p = ((float)actuator[n][P_PID] * error);
      //float i = ((float)actuator[n][I_PID] * constrain(actuator[n][INTEGRATED_ERROR], -100, 100)); // Uncomment to use I
      float d = ((float)actuator[n][D_PID] * (error - actuator[n][LAST_ERROR]));
      actuator[n][LAST_ERROR] = error;
      //actuator[n][SPEED] = constrain((p + i + d) / 200.0, -255, 255); // Uncomment to use I
      actuator[n][SPEED] = constrain((p + d) / 200.0, -255, 255); // Comment to use I
    }
    
    
    // ======================================================================
    // Picks values from actuators arrays and sends data to motor controllers
    // ======================================================================
    void updateController(byte n)
    {
      if (actuator[n][SPEED] > 0)
      {
        analogWrite(actuator[n][SPEED_PIN], actuator[n][SPEED]);
        digitalWrite (actuator[n][DIRECTION_PIN], UP);
      }
      else
      {
        analogWrite(actuator[n][SPEED_PIN], -actuator[n][SPEED]);
        digitalWrite (actuator[n][DIRECTION_PIN], DOWN);
      }
    }
    
    
    // =========
    // Main loop
    // =========
    void loop()
    {
      // While to make main loop, avoiding some of the Arduino framework delays
      while (1 == 1)
      {
        getSimToolsCommands();
        for (byte n = 0; n < NUMBER_ACTUATORS; n++)
        {
          getConstrainCurrentPosition(n);
          calculatePID(n);
          updateController(n);
        }
      }
    }
    
    
    // ==================================================
    // Calibration, search for minimum and maximum values
    // ==================================================
    void calibrate()
    {
      getMinimums(); // We might be at the minimum already, better put all at minimum and then search maximum followed by minimum
      getMaximums();
      getMinimums();
    }
    
    
    // ====================================
    // Search for minimums in all actuators
    // ====================================
    void getMinimums()
    {
      byte found = 0;
      bool foundMinimum[6] = {false, false, false, false, false, false};
      for (byte n = 0; n < NUMBER_ACTUATORS; n++)
      {
        digitalWrite (actuator[n][DIRECTION_PIN], DOWN);
        analogWrite(actuator[n][SPEED_PIN], CALIBRATION_SPEED);
      }
      while (found < NUMBER_ACTUATORS)
      {
        for (byte n = 0; n < NUMBER_ACTUATORS; n++)
        {
          getCurrentPosition(n);
          if (!foundMinimum[n])
          {
            if (actuator[n][CURRENT_POSITION] > 0)
            {
              if (actuator[n][CURRENT_POSITION] < actuator[n][MINIMUM_POSITION]) actuator[n][MINIMUM_POSITION] = actuator[n][CURRENT_POSITION];
            }
            else
            {
              analogWrite(actuator[n][SPEED_PIN], 0);
              actuator[n][MINIMUM_POSITION] += ENDS_GAP;
              foundMinimum[n] = true;
              found++;
            }
          }
        }
      }
    }
    
    
    // ====================================
    // Search for maximums in all actuators
    // ====================================
    void getMaximums()
    {
      byte found = 0;
      bool foundMaximum[6] = {false, false, false, false, false, false};
      for (byte n = 0; n < NUMBER_ACTUATORS; n++)
      {
        digitalWrite (actuator[n][DIRECTION_PIN], UP);
        analogWrite(actuator[n][SPEED_PIN], CALIBRATION_SPEED);
      }
      while (found < NUMBER_ACTUATORS)
      {
        for (byte n = 0; n < NUMBER_ACTUATORS; n++)
        {
          getCurrentPosition(n);
          if (!foundMaximum[n])
          {
            if (actuator[n][CURRENT_POSITION] < 1023)
            {
              if (actuator[n][CURRENT_POSITION] > actuator[n][MAXIMUM_POSITION]) actuator[n][MAXIMUM_POSITION] = actuator[n][CURRENT_POSITION];
            }
            else
            {
              analogWrite(actuator[n][SPEED_PIN], 0);
              actuator[n][MAXIMUM_POSITION] -= ENDS_GAP;
              foundMaximum[n] = true;
              found++;
            }
          }
        }
      }
    }
    

    SimTools2 configuration should be:
    Interface settings:
    Interface Type: Serial
    ComPort: The one used by your Arduino
    BitsPerSec: 57600 (You can change the define to use another speed)
    Data Bits: 8
    Parity: None
    Stop Bits: 1
    Output - Bit Range: 10
    Output - Type: Binary
    Startup - Output: -
    HW Start: -
    Interface output: [1<Axis1a>][2<Axis2a>][3<Axis3a>][4<Axis4a>][5<Axis5a>][6<Axis6a>]
    Output Rate: 10ms
    Shutdown - Output: -
    HW Stop: -
    • Like Like x 1
    Last edited: Aug 3, 2018
  6. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Oh my! I can't edit the post's... I think I need at least five approved posts right? EDIT: I can now!

    Well, let me post here some of the progress.
    I will update the parts list when I can edit the post.

    First of all, my electronics schematic:
    [​IMG]
    (For full resolution: https://c1.staticflickr.com/5/4389/36059736774_07d10f6b53_o.png)


    The idea is to control all the actuators with one Arduino Uno.
    I get position feedback with pots and two limit switches.
    When the maximum switch is pressed, the pot value is immediately 1023 on the Arduino.
    The same for the minimum, we get 0 when the switch is enabled
    The motor controller needs speed and direction information.
    Speed is fed with PWM and direction is on/off.
    So with this config I can fit everything in one Arduino Uno:
    [​IMG]
    (For full resolution: https://c1.staticflickr.com/5/4362/36059748064_4c644dc11d_o.jpg)
    Last edited: Aug 29, 2017
  7. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    I already have two actuators made.
    Built the first one as a prototype, looking for design problems.
    Built the second one, just to find new problems o_O
    So this is the current design (will update the above posts with link to Sketchup files):

    Some Sketchup drawings (those are still WIP):
    [​IMG]

    [​IMG]

    The parts to be printed in solid PETG:
    [​IMG]


    1: Join the screw with the slider and aluminium tube:
    [​IMG]

    [​IMG]

    [​IMG]

    [​IMG]

    Please ignore that bad print, it was already replaced.
    Aluminium tube is hold tight by two screws, one in each side of the PETG "slider".
    The two visible holes will get two screws to mount a GT2 belt
  8. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    2: Mount motor support

    Open threads in the aluminium profile:
    [​IMG]

    Slide the motor mount in place and put the screws:
    [​IMG]

    Mount the other side:
    [​IMG]



    3: Mount ball screw, slider and aluminium tube in the motor mount:
    [​IMG]
    • Like Like x 4
  9. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    3: Top end actuator plate.
    Here we have the wheel for the GT2 belt and an Ingus bearing:

    [​IMG]

    [​IMG]

    [​IMG]

    [​IMG]

    [​IMG]

    We need to open some M5 threads on the aluminium:
    [​IMG]
    Only made 4 or 5 by hand, next ones with WD40 and electric drill...

    Testing the mounting:
    [​IMG]
    • Like Like x 2
  10. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    4: Mounting wires and limit switches:

    Solder wires, pass them between aluminium profile and motor mount.
    [​IMG]
    (note: microswitch should be placed before top end or we can't mount the housings for the switches)

    [​IMG]
    Motor already mounted

    Insert micro switches in 3D printed housings and tight them to the aluminium profile:
    [​IMG]

    [​IMG]
    Here we can see the slider touching the switch

    Updated list of parts, software and added a video on the posts at the start of this thread.
    • Like Like x 3
  11. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    5: Make cables that connect to the control box.
    In my idea, I want to build a box with all the power supply and controllers.
    When we have kids, just the actuator is already pretty dangerous, so electrics should be really safe and hidden, at least for cosmetic reasons.

    So, since I could not get the needed cables, I made my owns.
    Joined 6 packs of wires:
    [​IMG]

    With 11 wires, 3 for limit switches and pot 3 to power the motor and the rest for the hall sensor:
    [​IMG]

    Joined them at one end so I could put them inside a sleeve:
    [​IMG]

    [​IMG]

    And the result:
    [​IMG]
    • Like Like x 3
  12. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    6: Bottom plate
    This holds the pot and the UJoint. Must be strong!

    Printed two equal parts.
    They make a sandwich to hold the pot.
    All wires go inside and the go out in one cable, the one built in the above post:
    [​IMG]

    There's also a part to mount this on the aluminium profile and hold the UJoint:
    [​IMG]

    [​IMG]

    Mounting everything:
    [​IMG]

    [​IMG]

    [​IMG]
    This one with the belt already in place.
    • Like Like x 10
  13. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Some updates to the Arduino code.
    Updated the post about software in the start of the thread with the new code.

    Version 5:

    -Remove unused functions
    -Remove optional hack for speed, now it's always implemented

    Version 4:
    -More code optimisation, removing some loops
    -For that, functions where created that receive index of actuator
    -Remove direction from array, it's already stored on the signal of the speed

    Version 3:
    Code optimisation
    Renamed functions for better understanding

    Version 2:
    Add minimum and maximum calibration
    • Like Like x 1
  14. matthew loomis

    matthew loomis Member

    Joined:
    May 18, 2017
    Messages:
    89
    Location:
    rochester,ny
    Balance:
    434Coins
    Ratings:
    +78 / 0 / -0
    Pretty impressive. You made your own code for the uno. Pretty cool. I was trying to avoid that by using rc components. Much better solution. How do you handle the pid tuning? I've seen some arduino code for self tuning pid but don't have the skills to paste that into an existing sketch.
    Glad someone got brushless working.
    • Like Like x 1
  15. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    PID tuning is manual, we can change the values in the array for each motor.
    Really curious about that code with self tuning. Can you give me a link?
    I'm still having vibrations in stand still, around 10º rotation off the motor to each side.
    I'm uploading a video right now with 2 actuators and this code. Still some time to go...

    EDIT:
    Found the Arduino library for PID control and tuning, will have a look.
    But it must be fast for 6 motors.
    I still have to tune mine manually.
    Last edited: Aug 31, 2017
  16. matthew loomis

    matthew loomis Member

    Joined:
    May 18, 2017
    Messages:
    89
    Location:
    rochester,ny
    Balance:
    434Coins
    Ratings:
    +78 / 0 / -0

    GitHub - jackw01/arduino-pid-autotuner: Automated PID tuning using Ziegler-Nichols/relay method on Arduino and compatible boards
    https://github.com/jackw01/arduino-pid-autotuner
    • Like Like x 1
  17. pmvcda

    pmvcda Member

    Joined:
    Nov 3, 2010
    Messages:
    61
    Location:
    Portugal
    Balance:
    482Coins
    Ratings:
    +91 / 0 / -0
    My Motion Simulator:
    6DOF
    Uploaded a new video.
    We can see two actuators working with LFS (like a 2DOF).
    At the start, the Arduino code is searching for the minimum and maximum positions, performing a basic calibration.

    • Like Like x 5
  18. SeatTime

    SeatTime Well-Known Member SimTools 2.0 Beta Tester

    Joined:
    Dec 27, 2013
    Messages:
    1,873
    Location:
    Newcastle Australia
    Balance:
    24,145Coins
    Ratings:
    +2,214 / 18 / -0
    My Motion Simulator:
    DC motor, Motion platform, 6DOF
    Nice :thumbs, What sort of load can they lift?
  19. baykah

    baykah Active Member

    Joined:
    Sep 1, 2016
    Messages:
    115
    Location:
    Toulouse - France
    Balance:
    539Coins
    Ratings:
    +119 / 0 / -0
    My Motion Simulator:
    6DOF
    Nice !

    Carefull with the potentiometers, I had bad experience with cheap pots ... and the way you mounted them all the force of the belt tension goes to the pot shaft ...

    It would be better to have the pot axe free from stress ..
    • Agree Agree x 2
  20. alexdixey

    alexdixey New Member

    Joined:
    May 17, 2017
    Messages:
    28
    Occupation:
    Designer
    Location:
    Gardiner, NY USA
    Balance:
    213Coins
    Ratings:
    +32 / 0 / -0
    My Motion Simulator:
    4DOF
    Beautiful craftsmanship.. I like the 3 d printed parts on aluminum profiles together.
    Are the plastic parts solid density?
    Do you use special filament?
    What is the actuator max speed ?

    Thanks