Too hi Accel on DC motor controlled thru SyRen25

Hi,

I didn't know if this was the correct place to post this issue, but as it involves controlling DC motors I hope it is close enough.

My setup is a go-cart for my kids, I use an Arduino Uno R3 to read a Hall-sensor throttle pedal on A0 and a toggle switch for selection of direction on D11.

The motor is a 200W worm-gear driven DC setup with 20Nm of torque.
The DC controller I chose for this setup is the SyRen 25 by DimentionEngineering.
Expensive, but awesome!

https://www.dimensionengineering.com/products/syren25

The basic control of the motor is quite straight forward due to the library made for the SyRen controller.
-126 equals 100% speed in negative direction
0 equals standstill
126 equals full speed forward.

As you can see in the code I've limited the reverse to 100 because kids :stuck_out_tongue:

The issue that I am having is that when the kids is smashing the throttle, or lifting the throttle, or most importantly when direction is switched while pedal is at 100% the SyRen does what it is told, giving full acceleration/retardation depending on mentioned scenario. This not only causes major wear on the worm gear, but also causes the bolts that connect the output shaft to the driveshaft to snap on a weekly basis.

Ive tried to utilise the Smoothing example in Arduino IDE to smooth out the output sent to the DC controller in hope of having some sort of ramping, but with the numReadings set to 255 (code fails if more) I can only see a marginally improvement where the DC controller ramps slightly.

I am out of ideas and since I'm quite the noob when it comes to programming I kindly ask for your assistance on programming the following:

-Ramping function that can be tuned with a parameter so that acceleration and retardation is smooth, and so that when switching direction while having the throttle at 100% the output it ramped down to 0 and then up to the desired output.

Thanks in advance.

// constants won't change. They're used here to set pin numbers:
    const int DirectionPin = 11;     // the number of the Direction pin

// variables will change:
    int DirectionState = 0;         // variable for reading the Driection status
    int ThrottleOutput = 0;

// Variables for Smoothing output

    const int numReadings = 255;

    int readings[numReadings];      // the readings from the analog input
    int readIndex = 0;              // the index of the current reading
    int total = 0;                  // the running total
    int AvgSpeedCmd = 0;                // the average


#include <SyRenSimplified.h>

SyRenSimplified SR; // We'll name the SyRen object SR.
                    // For how to configure the SyRen, see the DIP Switch Wizard for
                    //   http://www.dimensionengineering.com/datasheets/SyrenDIPWizard/start.htm
                    // Be sure to select Simplified Serial Mode for use with this library.
                    // This sample uses a baud rate of 9600.
                    //
                    // Connections to make:
                    //   Arduino TX->1  ->  SyRen S1
                    //   Arduino GND    ->  SyRen 0V
                    //   Arduino VIN    ->  SyRen 5V (OPTIONAL, if you want the SyRen to power the Arduino)
                    //
                    // If you want to use a pin other than TX->1, see the SoftwareSerial example.

void setup() {
  
  // initialize the pushbutton pin as an input:
    pinMode(DirectionPin, INPUT);
  
  // Initialize communication with DC controller
   SyRenTXPinSerial.begin(9600); // This is the baud rate you chose with the DIP switches.
  // Serial.begin(9600);
  
  // init Smoothing logic
    for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;}
  
  
}


void loop() {
  
// Read Value of Pedal:
      // read the input on analog pin 0:
         int PedalValue = analogRead(A0);
  
// Read the state of the pushbutton value:
          DirectionState = digitalRead(DirectionPin);

// check if the DirectionState is HIGH or LOW. map correct gains to output:
          if (DirectionState == LOW) {
              ThrottleOutput = map(PedalValue, 200, 800, 0, 126);
               ThrottleOutput = constrain(ThrottleOutput, 0, 126);
             } 
          else {
              ThrottleOutput = map(PedalValue, 200, 800, 0, -100);
               ThrottleOutput = constrain(ThrottleOutput, -100, 0);
             }



//Logic for smoothing of output
  
    // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
  readings[readIndex] = ThrottleOutput;
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }

// calculate the averaged/smoother ouput:
  AvgSpeedCmd = total / numReadings;
  
//send smoothed and constrained value to DC controller
 
 SR.motor(1, AvgSpeedCmd);   
  
}

Your averaging isn’t helping because it has no time reference, it’s calculated as fast as possible which is probably less than 50 milliseconds, give or take. Averaging could slow things down with the average done over a controlled time but it’s not what you really want, the usual solution is a linear ramp function over time that increases or decreases the motor speed command in a controlled fashion.

For example, start with throttle at zero. If throttle command is greater than zero, increase the motor speed one count every 20 milliseconds until count = throttle or at max speed. Changing the milliseconds interval will change the time it takes to from zero to max or max to zero.

Assume throttle goes from zero to 127 instantly. Incrementing by one every 20 milliseconds will create a ramp output will take 127*.02 = 2.54 seconds to change from 0 to 127 counts, thereby limiting the acceleration rate. Do the same with subtraction when decelerating.

Have a look at the “blink without delay” demo sketch to see how to use the millis() function to create the time base. It’s not as difficult as it may sound but if it makes no sense and you want to try it, leave a post and I should be able to either find something I’ve already done or cobble a demo together for you.