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

Question Servo motors torque mode operation. Ard pwm -> motor controller -> servo

Discussion in 'Motor actuators and drivers' started by Trigen, May 30, 2021.

  1. Trigen

    Trigen Active Member

    Joined:
    Nov 25, 2018
    Messages:
    466
    Balance:
    2,901Coins
    Ratings:
    +171 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino
    Hello

    Im revisiting my old Head g system as i have 2 st60 600w servo motors i can spare if i go with it. I see in the manual that torque mode wants a -10v - 10v analog signal to control the torque and direction. To me that sounds like i need to use a Ardunio to send a PWM signal to a motor controller that then send the V signals to the servo motors on pins Vref 25 and AGND 13.

    This honestly sounds pretty simple. All id need is a PWN signal from ardunio that keeps on going. Im wondering though. Is there a way i can do this directly from the Ard to the servo motor and cut out the motor controller and 10v? Digital or analog.

    My main problem is the ardunio sketch

    I need to create a PWN signal.
    I need values over 127 to give a positive signal and under 127 to give negative for direction
    127 - 255 will be 0 -255 CW
    So i need to invert the number so 127 - 0 becomes a positive 0 255 with CCW direction
    Or 0 to 127 CCW where 0 is full speed and 127 255 CW where 255 is full speed

    Any in depth help is greatly appreicated

    I thought id just modify this fan code
    Code:
    
    // Arduino Uno code based hugely on the work of SilentChill, Avenga76, and a number of others.
    // Forked off to support right and left speed commands (R000 and L000, etc) as well as traditional S000 format.
    
    // Version - 02_23_2021
    
    #define FALSE 0
    #define TRUE 1
    
    #define BRAKEVCC 0
    #define CW 1
    #define CCW 2
    #define BRAKEGND 3
    #define CS_THRESHOLD 100
    
    // If left and right fan control is swapped, just swap the values defined here for LEFT and RIGHT.
    #define BOTH 0
    #define LEFT 1
    #define RIGHT 2
    
    // Idle speed setting if you want the Arduino to reset or cold start with some air flow. Useful for
    // providing a light wind for VR comfort. Range is 0 to 255. I use 20 with TerraBloom fans. Default
    // value is 0 to not surprise anyone but change as you wish. There are no checks on this so you can
    // break the code if you use values less than 0 or more than 255.
    #define IDLESPEED 0
    
    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
        }
    
      // Just throw on a low speed in case no wind support in application...
      motorGo(0, CW, IDLESPEED); //Motor1
      motorGo(1, CW, IDLESPEED); //Motor2
      }
    
    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);
        }
        else if (Speed < 127) then 127 - becomes 0 -255 CCW
    
      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);
        }
      }
    
    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 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;
      }
       
    Last edited: May 30, 2021
  2. Ads Master

    Ads Master

    Balance:
    Coins
    Ratings:
    +0 / 0 / -0
  3. Trigen

    Trigen Active Member

    Joined:
    Nov 25, 2018
    Messages:
    466
    Balance:
    2,901Coins
    Ratings:
    +171 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino
    I got things working in Torque mode and done some testing. At the moment the servo drive does not react until about 4-5v input and im unsure why, Could it be the PWM frequency? Im using a Adafruit motor shield and it has a max of 1600hz

    Its also somewhat unstable even though the voltage is the same

    Temp code

    Code:
    #include <Wire.h>
    #include <Adafruit_MotorShield.h>
    
    Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
    
    // Enable adfruit motors. 
    
    Adafruit_DCMotor *myMotor1= AFMS.getMotor(1);
    Adafruit_DCMotor *myMotor2= AFMS.getMotor(2);
    Adafruit_DCMotor *myMotor3= AFMS.getMotor(3);
    Adafruit_DCMotor *myMotor4= AFMS.getMotor(4);
    
    
    int bufferArray[4];
    int motors = 4; 
    
    
    
    void setup() {
      // put your setup code here, to run once:
    
      Serial.begin(115200);           // set up Serial library at 9600 bps
      Serial.println("Adafruit Motorshield v2 - DC Motor test!");
    
     // AFMS.begin();  // create with the default frequency 1.6KHz
      AFMS.begin(1600);  // OR with a different frequency, say 1KHz
     
      // set the speed to start, from 0 (off) to 255 (max speed, Turn on M1 
     
      myMotor1->setSpeed(0);
      myMotor1->run(FORWARD);
      myMotor1->run(RELEASE);
    
      myMotor2->setSpeed(0);
      myMotor2->run(RELEASE);
    
      myMotor3->setSpeed(0);
      myMotor3->run(RELEASE);
    
      myMotor4->setSpeed(0);
      myMotor4->run(RELEASE);
    
    // disable timer0's interrupt handler - this will disable Arduino's time keeping functions such as delay()
    TIMSK0 &= B11111110;
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
       while (Serial.available())
       {
        unsigned int Speed = Serial.read()  ; // Dont need -48, Mover compensates // divide by 4 to get 8 bit 
    
         //myMotor1->setSpeed(Speed);
          //  myMotor1->run(FORWARD);
           
        //Serial.println (Speed)
    
         
        if (Speed > 128){
            Speed = map(Speed, 0, 128, 0, 255);
           // Serial.println (Speed);
            myMotor1->setSpeed(Speed);
            myMotor1->run(FORWARD);
         }
    
        else if (Speed < 126){
            Speed = map(Speed, 0, 126, 255, 0);
           
            myMotor1->setSpeed(Speed);
            myMotor1->run(BACKWARD);
         }
         else {
         //   motorOff ();
            myMotor1->run(RELEASE);
         
            }
             
       }
         
    
    }
    
    void motorOff()
      {
        //intialize brake
        for (int i = 0; i <= motors; i++) { 
         
          myMotor1->run(RELEASE);
          myMotor2->run(RELEASE);
          myMotor3->run(RELEASE);
          myMotor4->run(RELEASE);
        }
      }
    
    
  4. BlazinH

    BlazinH Well-Known Member

    Joined:
    Oct 19, 2013
    Messages:
    2,186
    Location:
    Oklahoma City, USA
    Balance:
    16,345Coins
    Ratings:
    +1,839 / 32 / -1
    You may need RC low-pass filters on the motor controller outputs for stabilization. Also you may be able to omit the motor controller and just use -5 to 5v. With 600w motors 50% power should give enough torque to move your head around. In that case put the RC filters on the PWM outputs.
    • Like Like x 1