Variable frequency PWM signal

Hi,

I'm using an Arduino to control a stepper motor. The stepper motor needs to oscillate in a sine wave motion. My code attached has an array i made in matlab and copied into the arduino ide which sets the number of steps and pulse timing. The overall motion works but the timing of the step pulses are off and results in an oscillating frequency other than what was desired. The method im using is to digitalwrite high and low a pin which sends a step pulse to move the motor. After testing i found out this isnt the best method as i need to pulse at relatively high frequencies. I looked into timing on an arduino but couldnt understand how to use the different timers to get a reliable pulsing signal at the frequencies i need.

Would appreciate any help.

Thanks

// Define stepper motor connections and steps per revolution:
#define dirPin 10
#define stepPin 9
const long int frame[] = {1273,1273,1273,1274,1274,1274,1275,1276,1276,1277,1278,1279,1280,1281,1282,1283,1284,1286,1287,1289,1291,1293,1294,1296,1298,1301,1303,1305,1308,1310,1313,1316,1319,1322,1325,1328,1331,1335,1338,1342,1346,1350,1354,1358,1363,1367,1372,1377,1381,1387,1392,1397,1403,1409,1415,1421,1427,1434,1441,1448,1455,1463,1470,1478,1486,1495,1504,1513,1522,1532,1542,1552,1563,1574,1586,1598,1610,1623,1636,1650,1664,1679,1695,1711,1728,1745,1764,1783,1803,1824,1846,1869,1893,1918,1945,1973,2003,2035,2068,2104,2141,2182,2225,2271,2321,2374,2432,2495,2564,2640,2724,2817,2922,3040,3175,3331,3514,3734,4003,4345,4796,5432,6431,8363,20145,-20145,-8363,-6431,-5432,-4796,-4345,-4003,-3734,-3514,-3331,-3175,-3040,-2922,-2817,-2724,-2640,-2564,-2495,-2432,-2374,-2321,-2271,-2225,-2182,-2141,-2104,-2068,-2035,-2003,-1973,-1945,-1918,-1893,-1869,-1846,-1824,-1803,-1783,-1764,-1745,-1728,-1711,-1695,-1679,-1664,-1650,-1636,-1623,-1610,-1598,-1586,-1574,-1563,-1552,-1542,-1532,-1522,-1513,-1504,-1495,-1486,-1478,-1470,-1463,-1455,-1448,-1441,-1434,-1427,-1421,-1415,-1409,-1403,-1397,-1392,-1387,-1381,-1377,-1372,-1367,-1363,-1358,-1354,-1350,-1346,-1342,-1338,-1335,-1331,-1328,-1325,-1322,-1319,-1316,-1313,-1310,-1308,-1305,-1303,-1301,-1298,-1296,-1294,-1293,-1291,-1289,-1287,-1286,-1284,-1283,-1282,-1281,-1280,-1279,-1278,-1277,-1276,-1276,-1275,-1274,-1274,-1274,-1273,-1273,-1273,-1273,-1273,-1273,-1274,-1274,-1274,-1275,-1276,-1276,-1277,-1278,-1279,-1280,-1281,-1282,-1283,-1284,-1286,-1287,-1289,-1291,-1293,-1294,-1296,-1298,-1301,-1303,-1305,-1308,-1310,-1313,-1316,-1319,-1322,-1325,-1328,-1331,-1335,-1338,-1342,-1346,-1350,-1354,-1358,-1363,-1367,-1372,-1377,-1381,-1387,-1392,-1397,-1403,-1409,-1415,-1421,-1427,-1434,-1441,-1448,-1455,-1463,-1470,-1478,-1486,-1495,-1504,-1513,-1522,-1532,-1542,-1552,-1563,-1574,-1586,-1598,-1610,-1623,-1636,-1650,-1664,-1679,-1695,-1711,-1728,-1745,-1764,-1783,-1803,-1824,-1846,-1869,-1893,-1918,-1945,-1973,-2003,-2035,-2068,-2104,-2141,-2182,-2225,-2271,-2321,-2374,-2432,-2495,-2564,-2640,-2724,-2817,-2922,-3040,-3175,-3331,-3514,-3734,-4003,-4345,-4796,-5432,-6431,-8363,-20145,20145,8363,6431,5432,4796,4345,4003,3734,3514,3331,3175,3040,2922,2817,2724,2640,2564,2495,2432,2374,2321,2271,2225,2182,2141,2104,2068,2035,2003,1973,1945,1918,1893,1869,1846,1824,1803,1783,1764,1745,1728,1711,1695,1679,1664,1650,1636,1623,1610,1598,1586,1574,1563,1552,1542,1532,1522,1513,1504,1495,1486,1478,1470,1463,1455,1448,1441,1434,1427,1421,1415,1409,1403,1397,1392,1387,1381,1377,1372,1367,1363,1358,1354,1350,1346,1342,1338,1335,1331,1328,1325,1322,1319,1316,1313,1310,1308,1305,1303,1301,1298,1296,1294,1293,1291,1289,1287,1286,1284,1283,1282,1281,1280,1279,1278,1277,1276,1276,1275,1274,1274,1274,1273,1273,1273};
int steps;

void setup() {
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {

interrupts();
  for(int i = 0; i < 500 ; i++) {

    if (frame[i] > 0) {
      steps = frame[i];
      digitalWrite(dirPin, HIGH);
    }

    else {
      steps = abs(frame[i]);
      digitalWrite(dirPin, LOW);
    }
  
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(0.5*steps);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(0.5*steps);
  }
}

This line enabled interrupts in the code and is useless if you do not desabled interrupts before.
Why do you insert it in your code?

You do not say what stepper driver that you are using. The drivers that I am familiar with (A4988, DRV8825) step on the positive going edge. That means that the pulse only needs to remain HIGH for a us or so (consult data sheet). Then only the time that the pulse is LOW controls the speed. That will increase the speed range and, perhaps, make it easier to calculate the time between steps.

Reference Robin2's simple stepper program.

Can you put a number to that?

Can you document better the discrepancy?

The digitalWrite() step pair take about 5 or 6 microseconds and the minimum step delay is 1273 microseconds so I don't see a very big effect. Certainly you can speed the step pair timing to about 1us, but I think you may be focusing on the wrong thing. You can probably eliminate the digitalWrite() for the dir pin on every pass through the for loop, but again, that's only adding another few microseconds.

What are the two long interstep times at the reversals all about?

20145,-20145,
-20145,20145

As @groundFungus says, the step routine is better written as

digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delayMicroseconds(steps); //or some other method to control between step timing

I plotted your data in excel. It looks like the graph below. Its not clear how that could control a stepper motor.

I also I believe your frame could be an int16_t (will save space)

image

Sorry, I forgot to remove it, was trying something with the code.

I am using a microstepping driver from a company called Applied Motion, model ST10-IP. I will have a go at using the code you kindly gave and report back.

I need to oscillate at frequencies ranging from 1 to preferably 10 Hz, I havent been able to push the motor to the higher frequencies yet.

Thanks

Can you document better the discrepancy?

Depending on the number of steps per rev I choose for the microstepping driver the discrepancies can vary. On average for the 1Hz oscillation tests I did, I would get about 0.8-0.9Hz back from the motor.

What are the two long interstep times at the reversals all about?

As the sine wave reaches its peak the gradient of the curve becomes shallower and as a result the time steps are much longer. I generated these time steps from a model I made in MATLAB and copied into the Arduino IDE.

I'll have a go with the code from @groundFungus for the step routine and do a few tests and report back.

Thanks

These are just the time delays between each step at the motor. I calculated them using a model I made in MATLAB and imported into the Arduino IDE.

Thanks

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.