TeensyStep - Fallen at the first hurdle!

Status
Not open for further replies.

450nick

Active member
Hi everyone! I just found this forum, I've been using Teensy's and Arduino now for a few months and it's SO MUCH FUN! So thank you for creating them. I'm still very much learning, and the project I'm attempting is a bit in at the deep end... I'm creating a new instrument cluster for a car I'm building. It features two Teensy 3.2s and one Teensy 3.5 performing a number of functions such as running an 128x32 OLED display, 4 BKA30lF1 instrument stepper motors via a VID 6606 driver chip, CAN bus interface and running various dashboard led indicators.

I designed a number of PCBs to make up the unit and have had a set of prototypes made which I'm currently testing. Most things work really well which I'm super pleased about, but a couple of bits aren't quite how I want them so I'm currently working up a change list to develop Rev 2 of the boards.

Today's issue is with Teensystepper. I actually prototyped the board with Accelstepper and it works great. Since getting the PCBs I have plugged everything in and it still works great, currently controlling via 4 potentiometers until I have time to build a square wave simulator for RPM & wheel speed. Presently I have the steppers running from a Teensy 3.2, with the inputs for the steppers also being processed by this board to maintain as high response and I can. Teensy A then serial transmits data across to Teensy 3.2 B, which runs the OLED, CAN Bus and some other bits and pieces. It works pretty well but I'm finding that with 4 steppers running and the serial send, the performance of the steppers is getting degraded to the point where the RPM pointer probably isn't quite fast enough.

Enter Teensystepper. I have heard it is a little quicker than Accelstepper so I thought I'd give it a go as I only need a small amount of improvement from where I am now. I tried starting with a very simple example code to get one stepper running, and so far no response from the stepper at all. I know it works from Accelstepper so there must be something obvious that I've not considered - can anyone help me see what it is? Also if you have any great suggestions for improving the performance then I'd be all ears! Thank you!


Here is a video of it running (I have now fixed the OLED refresh rate!) https://www.instagram.com/p/B70bz6cFKO5/?utm_source=ig_web_copy_link


Old code (excuse the clunky code for the potentiometers to test, this will be replaced by some neater code to count pulses on two pins based on this: https://forum.pjrc.com/threads/48101-PMT-pulse-counting-using-Teensy-3-2 then I'll pull the fuel level and water temperature across serial from the other Teensy's CAN interface)
Code:
#include <AccelStepper.h>

// Define some steppers and the pins the will use
AccelStepper SPEED_STEPPER(AccelStepper::DRIVER, 5, 6); //Step, Direction
AccelStepper RPM_STEPPER(AccelStepper::DRIVER, 7, 8); //Step, Direction
AccelStepper CT_STEPPER(AccelStepper::DRIVER, 11, 12); //Step, Direction
AccelStepper FL_STEPPER(AccelStepper::DRIVER, 9, 10); //Step, Direction

const int RESET = 18; // pin for RESET
const int numReadings = 50;

//Speed
int SPEED_Pin = 23;
int SPEED_Val = 0;
int SPEED_STEPS;
int SPEED_readings[numReadings];      // the readings from the analog input
int SPEED_readIndex = 0;              // the index of the current reading
int SPEED_total = 0;                  // the running total
int SPEED_average = 0;                // the average
int SPEED_MPH = 0;
int SPEED_SEND;

//RPM
int RPM_Pin = 22;
int RPM_Val;
int RPM_STEPS;
int RPM_readings[numReadings];      // the readings from the analog input
int RPM_readIndex = 0;              // the index of the current reading
int RPM_total = 0;                  // the running total
int RPM_average = 0;                // the average
long RPM = 0;
int RPM_SEND;

//Coolant_T
int CT_Pin = 21;
int CT_Val;
int CT_STEPS;
int CT_readings[numReadings];      // the readings from the analog input
int CT_readIndex = 0;              // the index of the current reading
int CT_total = 0;                  // the running total
int CT_average = 0;                // the average
int COOLANT_TEMP = 0;
int CT_SEND;

//Fuel_L
int FL_Pin = 20;
int FL_Val;
int FL_STEPS;
int FL_readings[numReadings];      // the readings from the analog input
int FL_readIndex = 0;              // the index of the current reading
int FL_total = 0;                  // the running total
int FL_average = 0;                // the average
int FUEL_LEVEL = 0;
int FL_SEND;

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 10;  //the value is a number of milliseconds

void setup()
{
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    SPEED_readings[thisReading] = 0;
    RPM_readings[thisReading] = 0;
    CT_readings[thisReading] = 0;
    FL_readings[thisReading] = 0;
  }

  SPEED_STEPPER.setMaxSpeed(10000.0);
  SPEED_STEPPER.setAcceleration(250000.0);
  RPM_STEPPER.setMaxSpeed(10000.0);
  RPM_STEPPER.setAcceleration(250000.0);
  CT_STEPPER.setMaxSpeed(10000.0);
  CT_STEPPER.setAcceleration(250000.0);
  FL_STEPPER.setMaxSpeed(10000.0);
  FL_STEPPER.setAcceleration(250000.0);

  //SPEED_STEPPER.runToNewPosition(-1000);
  SPEED_STEPPER.runToNewPosition(3000);
  SPEED_STEPPER.runToNewPosition(0);

  //RPM_STEPPER.runToNewPosition(1000);
  RPM_STEPPER.runToNewPosition(-3000);
  RPM_STEPPER.runToNewPosition(0);

  //CT_STEPPER.runToNewPosition(-500);
  CT_STEPPER.runToNewPosition(2216);
  CT_STEPPER.runToNewPosition(0);

  //FL_STEPPER.runToNewPosition(500);
  FL_STEPPER.runToNewPosition(-2216);
  FL_STEPPER.runToNewPosition(0);




  startMillis = millis();  //initial start time
}

void loop() {
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)


  //if (currentMillis - startMillis >= (period*2))  //test whether the period has elapsed
  //{
  //=====SPEED CALC=============
  // subtract the last reading:
  SPEED_total = SPEED_total - SPEED_readings[SPEED_readIndex];
  // read from the sensor:
  SPEED_Val = map(analogRead(SPEED_Pin), 0, 1023, 0, 3189);  //scal val2 (kph) to stepper motor positions

  SPEED_readings[SPEED_readIndex] = SPEED_Val;
  SPEED_total = SPEED_total + SPEED_readings[SPEED_readIndex];
  SPEED_readIndex = SPEED_readIndex + 1;
  if (SPEED_readIndex >= numReadings) {
    SPEED_readIndex = 0;
  }

  // calculate the average:
  SPEED_STEPS = SPEED_total / numReadings;     //10*(((total / numReadings)+5)/10);
  SPEED_MPH = SPEED_STEPS / 15.945;

  //=====RPM CALC=============
  // subtract the last reading:
  RPM_total = RPM_total - RPM_readings[RPM_readIndex];
  // read from the sensor:
  RPM_Val = map(analogRead(RPM_Pin), 0, 1023, 0, -2835);  //scal val2 (kph) to stepper motor positions

  RPM_readings[RPM_readIndex] = RPM_Val;
  RPM_total = RPM_total + RPM_readings[RPM_readIndex];
  RPM_readIndex = RPM_readIndex + 1;
  if (RPM_readIndex >= numReadings) {
    RPM_readIndex = 0;
  }

  // calculate the average:
  RPM_STEPS = RPM_total / numReadings;     //10*(((total / numReadings)+5)/10);
  RPM = RPM_STEPS / 0.4252;

  //=====CT CALC=============
  // subtract the last reading:
  CT_total = CT_total - CT_readings[CT_readIndex];
  // read from the sensor:
  CT_Val = map(analogRead(CT_Pin), 0, 1023, 2216, 0);  //range of 80 starting at 40

  CT_readings[CT_readIndex] = CT_Val;
  CT_total = CT_total + CT_readings[CT_readIndex];
  CT_readIndex = CT_readIndex + 1;
  if (CT_readIndex >= numReadings) {
    CT_readIndex = 0;
  }

  // calculate the average:
  CT_STEPS = CT_total / numReadings;     //10*(((total / numReadings)+5)/10);
  COOLANT_TEMP = CT_STEPS / 2.77;

  //=====FL CALC=============
  // subtract the last reading:
  FL_total = FL_total - FL_readings[FL_readIndex];
  // read from the sensor:
  FL_Val = map(analogRead(FL_Pin), 0, 1023, -2216, 0);  //scal val2 (kph) to stepper motor positions

  FL_readings[FL_readIndex] = FL_Val;
  FL_total = FL_total + FL_readings[FL_readIndex];
  FL_readIndex = FL_readIndex + 1;
  if (FL_readIndex >= numReadings) {
    FL_readIndex = 0;
  }

  // calculate the average:
  FL_STEPS = FL_total / numReadings;     //10*(((total / numReadings)+5)/10);
  FUEL_LEVEL = FL_STEPS / 3.887193;



  //}

  //=============================

  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    Serial1.print('<');

    if (SPEED_MPH != SPEED_SEND) {
      SPEED_SEND = SPEED_MPH;
      Serial1.print('S');
      Serial1.print(SPEED_SEND);
      Serial1.print('S');
    }

    if (RPM != RPM_SEND) {
      RPM_SEND = RPM;
      Serial1.print('R');
      Serial1.print(-RPM_SEND);
      Serial1.print('R');
    }

    if (COOLANT_TEMP != CT_SEND) {
      CT_SEND = COOLANT_TEMP;
      Serial1.print('T');
      Serial1.print(CT_SEND);
      Serial1.print('T');
    }

    if (FUEL_LEVEL != FL_SEND) {
      FL_SEND = FUEL_LEVEL;
      Serial1.print('F');
      Serial1.print(-FL_SEND);
      Serial1.print('F');
    }

    Serial1.print('>');

  }

  //=============================
  
  SPEED_STEPPER.moveTo(SPEED_STEPS);
  RPM_STEPPER.moveTo(RPM_STEPS);
  CT_STEPPER.moveTo(CT_STEPS);
  FL_STEPPER.moveTo(FL_STEPS);

  SPEED_STEPPER.run();
  RPM_STEPPER.run();
  CT_STEPPER.run();
  FL_STEPPER.run();
}



Code I'm trying to test (I tried LOW and HIGH pin polarity but no response to either):
Code:
#include "TeensyStep.h"

Stepper motor_1(5, 6);   //STEP pin =  2, DIR pin = 3
Stepper motor_2(7,8);   //STEP pin =  9, DIR pin = 10
Stepper motor_3(9,10);  //STEP pin = 14, DIR pin = 15

StepControl controller;

void setup()
{
  // setup the motors 
   motor_1
    .setMaxSpeed(50000)       // steps/s
    .setAcceleration(200000); // steps/s^2 
  
  motor_2
    .setMaxSpeed(50000)       // steps/s
    .setAcceleration(200000); // steps/s^2 
  motor_3
    //.setPullInSpeed(300)      // steps/s     currently deactivated...
    .setMaxSpeed(10000)       // steps/s
    .setAcceleration(50000)   // steps/s^2     
    .setStepPinPolarity(LOW); // driver expects active low pulses
}

void loop() 
{  
  constexpr int spr = 16*200;  // 3200 steps per revolution
  
  // lets shake    
  for(int i = 0; i < 5; i++)
  {
    motor_1.setTargetRel(spr/4); // 1/4 revolution
    controller.move(motor_1);  

    motor_1.setTargetRel(-spr/4);
    controller.move(motor_1);  
  }
  delay(500);
  
  // move motor_1 to absolute position (10 revolutions from zero)
  // move motor_2 half a revolution forward  
  // both motors will arrive their target positions at the same time
  motor_1.setTargetAbs(10*spr);
  motor_2.setTargetRel(spr/2);
  controller.move(motor_1, motor_2);

  // now move motor_2 together with motor_3
  motor_2.setTargetRel(300);
  motor_3.setTargetRel(-800);
  controller.move(motor_2, motor_3);

  // move all motors back to their start positions
  motor_1.setTargetAbs(0);
  motor_2.setTargetAbs(0);
  motor_3.setTargetAbs(0);
  controller.move(motor_1, motor_2, motor_3);
 
  delay(1000);
}
 

Attachments

  • Rear PCB Schematic.jpg
    Rear PCB Schematic.jpg
    85 KB · Views: 157
I tried your sketch, it works perfectly. Here the output of the step pins

Overview
pins.jpg

Zoomed in:
pins2.jpg

I assume some hardware issue, the driver you use is a 5V type which requires at least 3.15V for the high level. Unfortunately your schematic is very low res, I can't see if you have a level shifter included. I don't know the step pulse length of the AccelStepper, TeensyStep defaults to 5µs. Might be too short together with the 3.3V output?

Can you post a better schematic?
 
Thanks Luni! I will put a better schematic up when I get to work, but looking on my phone I think I may have found the problem. The VID6606 requires a step pulse of 450uS according to this datasheet: https://usermanual.wiki/Document/VID660620stepper20motor20driver2020manual.2030060063/amp

Can I increase this within Teensystepper to test? Then I suppose the question is whether I should replace the VID6606 with another chip? Is there something that may be better suited to my application do you think? Thanks again for your help.
 
The VID6606 requires a step pulse of 450uS according to this datasheet
No, it requires 450 nanoseconds not microseconds. Just check if you convert the 3.3V output to the required 5V output. Without converting the behaviour might be borderline (VID requires 3.15V HIGH level) and depend on details like the pulse width. If you want to experiment, you can set the pulsewidth in the constructor of the controller classes. See here for the documentation https://luni64.github.io/TeensyStep/documentation/stepControl/#constructor
The following example defines a controller with 500µs step pulse width.
Code:
StepControl controller(500);

Another thing: are your motors fast enough for your test sketch? You are moving them with 50kHz and an acceleration of 200kHz/s^2. Try to change that to something more reasonable first. Say, 1kHz max speed and 10kHz/s^2 acceleration.

Code:
motor_1
   .setMaxSpeed(1'000)       
   .setAcceleration(10'000);
 
Fantastic thanks Luni it now works! Just a quick question; if I want to set 4 motors off toward a target but I don't want them to arrive in sync (each go as fast as it's able), how should I make the call? 4 individual controller.move calls or is there another class?
 
if I want to set 4 motors off toward a target but I don't want them to arrive in sync (each go as fast as it's able), how should I make the call?

You'd use 4 controllers in this case
Code:
ctrl1.moveAsync(m1); //start all movements
ctrl2.moveAsync(m2);
ctrl3.moveAsync(m3);
ctrl4.moveAsync(m4);

while(ctrl1.isRunning() && ctrl2.isRunning() &&....)  // wait until all motors reached their targets. 
{
    delay(10);
}

BTW: your schematic doesn't show how you connected your driver. I suspect that you don't have a level shifter (3.3V->5V). If so, I strongly recommend to add one. Something like a 74HCT245 will do.
 
Thanks again Luni, two questions

1) What does the level shifter do? I realised that the driver is actually on the other PCB but it is driven direct from the Teensy. I think one of the problems was I hadn't initiated the driver by cycling the reset pin; it seems to work very well now.
See this link https://1drv.ms/u/s!AgmvMKMMwGkfnVAcFjSf8OzHpafI?e=Sc1N2x

2) I'm not sure the above code will work for my application. Perhaps you can help me understand how I need to structure it... I would like first for the motors to run a sweep; one pair and then the other (see this video for how they run: https://www.instagram.com/p/B70bz6cFKO5/?utm_source=ig_web_copy_link)

Once they've done their startup, I would like to run the loop which will check the inputs and calculate the new position of the steppers and send out the information on serial. Then at the end of each loop (probably) update the stepper positions so that they run to position with the minimum delay. The RPM motor will probably run much faster than the speedo, and the fuel gauge and temp gauge slower still. How do I call so they all run at their respective speeds without slowing each other down or delaying the code? This is what I currently have, and the first problem is that on startup, the second pair of steppers (CT & FL) don't complete their sweep; they stop about half way through and I'm not sure why....

Code:
#include "TeensyStep.h"

// Define some steppers and the pins the will use

Stepper SPEED_STEPPER(5, 6);   //STEP pin =  5, DIR pin = 6
Stepper RPM_STEPPER(7, 8);  //STEP pin =  7, DIR pin = 8
Stepper CT_STEPPER(9, 10); //STEP pin = 9, DIR pin = 10
Stepper FL_STEPPER(11, 12); //STEP pin = 11, DIR pin = 12

const int RESET = 18; // pin for RESET
const int numReadings = 50;

//Speed
int SPEED_Pin = 23;
int SPEED_Val = 0;
int SPEED_STEPS;
int SPEED_readings[numReadings];      // the readings from the analog input
int SPEED_readIndex = 0;              // the index of the current reading
int SPEED_total = 0;                  // the running total
int SPEED_average = 0;                // the average
int SPEED_MPH = 0;
int SPEED_SEND;

//RPM
int RPM_Pin = 22;
int RPM_Val;
int RPM_STEPS;
int RPM_readings[numReadings];      // the readings from the analog input
int RPM_readIndex = 0;              // the index of the current reading
int RPM_total = 0;                  // the running total
int RPM_average = 0;                // the average
long RPM = 0;
int RPM_SEND;

//Coolant_T
int CT_Pin = 21;
int CT_Val;
int CT_STEPS;
int CT_readings[numReadings];      // the readings from the analog input
int CT_readIndex = 0;              // the index of the current reading
int CT_total = 0;                  // the running total
int CT_average = 0;                // the average
int COOLANT_TEMP = 0;
int CT_SEND;

//Fuel_L
int FL_Pin = 20;
int FL_Val;
int FL_STEPS;
int FL_readings[numReadings];      // the readings from the analog input
int FL_readIndex = 0;              // the index of the current reading
int FL_total = 0;                  // the running total
int FL_average = 0;                // the average
int FUEL_LEVEL = 0;
int FL_SEND;

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 10;  //the value is a number of milliseconds
StepControl controller;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH);

  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    SPEED_readings[thisReading] = 0;
    RPM_readings[thisReading] = 0;
    CT_readings[thisReading] = 0;
    FL_readings[thisReading] = 0;
  }

  SPEED_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000); // steps/s^2
  RPM_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000); // steps/s^2
  CT_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000);   // steps/s^2
  FL_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000); // steps/s^2



  SPEED_STEPPER.setTargetRel(3780);
  RPM_STEPPER.setTargetRel(-3780);

  controller.move(SPEED_STEPPER, RPM_STEPPER);

  SPEED_STEPPER.setTargetRel(-3780);
  RPM_STEPPER.setTargetRel(3780);

  controller.move(SPEED_STEPPER, RPM_STEPPER);

  CT_STEPPER.setTargetRel(2126);
  FL_STEPPER.setTargetRel(-2126);
  controller.move(CT_STEPPER, FL_STEPPER);

  CT_STEPPER.setTargetRel(-2126);
  FL_STEPPER.setTargetRel(2126);
  controller.move(CT_STEPPER, FL_STEPPER);
  delay(1000);
  SPEED_STEPPER
  .setMaxSpeed(6000)       // steps/s
  .setAcceleration(10000); // steps/s^2
  RPM_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000); // steps/s^2
  CT_STEPPER
  .setMaxSpeed(6000)       // steps/s
  .setAcceleration(500);   // steps/s^2
  FL_STEPPER
  .setMaxSpeed(10000)       // steps/s
  .setAcceleration(500); // steps/s^2



  startMillis = millis();  //initial start time
}

void loop() {
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)


  //if (currentMillis - startMillis >= (period*2))  //test whether the period has elapsed
  //{
  //=====SPEED CALC=============
  // subtract the last reading:
  SPEED_total = SPEED_total - SPEED_readings[SPEED_readIndex];
  // read from the sensor:
  SPEED_Val = map(analogRead(SPEED_Pin), 0, 1023, 0, 3189);  //scal val2 (kph) to stepper motor positions

  SPEED_readings[SPEED_readIndex] = SPEED_Val;
  SPEED_total = SPEED_total + SPEED_readings[SPEED_readIndex];
  SPEED_readIndex = SPEED_readIndex + 1;
  if (SPEED_readIndex >= numReadings) {
    SPEED_readIndex = 0;
  }

  // calculate the average:
  SPEED_STEPS = SPEED_total / numReadings;     //10*(((total / numReadings)+5)/10);
  SPEED_MPH = SPEED_STEPS / 15.945;

  //=====RPM CALC=============
  // subtract the last reading:
  RPM_total = RPM_total - RPM_readings[RPM_readIndex];
  // read from the sensor:
  RPM_Val = map(analogRead(RPM_Pin), 0, 1023, 0, -2835);  //scal val2 (kph) to stepper motor positions

  RPM_readings[RPM_readIndex] = RPM_Val;
  RPM_total = RPM_total + RPM_readings[RPM_readIndex];
  RPM_readIndex = RPM_readIndex + 1;
  if (RPM_readIndex >= numReadings) {
    RPM_readIndex = 0;
  }

  // calculate the average:
  RPM_STEPS = RPM_total / numReadings;     //10*(((total / numReadings)+5)/10);
  RPM = RPM_STEPS / 0.4252;

  //=====CT CALC=============
  // subtract the last reading:
  CT_total = CT_total - CT_readings[CT_readIndex];
  // read from the sensor:
  CT_Val = map(analogRead(CT_Pin), 0, 1023, 2216, 0);  //range of 80 starting at 40

  CT_readings[CT_readIndex] = CT_Val;
  CT_total = CT_total + CT_readings[CT_readIndex];
  CT_readIndex = CT_readIndex + 1;
  if (CT_readIndex >= numReadings) {
    CT_readIndex = 0;
  }

  // calculate the average:
  CT_STEPS = CT_total / numReadings;     //10*(((total / numReadings)+5)/10);
  COOLANT_TEMP = CT_STEPS / 2.77;

  //=====FL CALC=============
  // subtract the last reading:
  FL_total = FL_total - FL_readings[FL_readIndex];
  // read from the sensor:
  FL_Val = map(analogRead(FL_Pin), 0, 1023, -2216, 0);  //scal val2 (kph) to stepper motor positions

  FL_readings[FL_readIndex] = FL_Val;
  FL_total = FL_total + FL_readings[FL_readIndex];
  FL_readIndex = FL_readIndex + 1;
  if (FL_readIndex >= numReadings) {
    FL_readIndex = 0;
  }

  // calculate the average:
  FL_STEPS = FL_total / numReadings;     //10*(((total / numReadings)+5)/10);
  FUEL_LEVEL = FL_STEPS / 3.887193;



  //}

  //=============================

  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    Serial1.print('<');

    if (SPEED_MPH != SPEED_SEND) {
      SPEED_SEND = SPEED_MPH;
      Serial1.print('S');
      Serial1.print(SPEED_SEND);
      Serial1.print('S');
    }

    if (RPM != RPM_SEND) {
      RPM_SEND = RPM;
      Serial1.print('R');
      Serial1.print(-RPM_SEND);
      Serial1.print('R');
    }

    if (COOLANT_TEMP != CT_SEND) {
      CT_SEND = COOLANT_TEMP;
      Serial1.print('T');
      Serial1.print(CT_SEND);
      Serial1.print('T');
    }

    if (FUEL_LEVEL != FL_SEND) {
      FL_SEND = FUEL_LEVEL;
      Serial1.print('F');
      Serial1.print(-FL_SEND);
      Serial1.print('F');
    }

    Serial1.print('>');

  }

  //=============================

  SPEED_STEPPER.setTargetAbs(SPEED_STEPS);
  RPM_STEPPER.setTargetAbs(RPM_STEPS);
  CT_STEPPER.setTargetAbs(CT_STEPS);
  FL_STEPPER.setTargetAbs(FL_STEPS);

  controller.moveAsync(SPEED_STEPPER);
  controller.moveAsync(RPM_STEPPER);
  controller.moveAsync(CT_STEPPER);
  controller.moveAsync(FL_STEPPER);
}
 
1) The level shifter adjusts the output voltage of the Teensy (3.3V) to the required input voltage of the driver (5V). Without it it might or might not work. If you only do this for your hobby and it works, all is good. If you plan to make this for others you better stick to the spec of the electronics.

2) If I understand your application right, you want the gauges to follow some external input. This is certainly possible but needs a different strategy. Since such things are commonly requested I can do an example on gitHub but I won't have time before the weekend. If you need that done more quickly you can have a look here https://forum.pjrc.com/threads/43491-New-Stepper-Motor-Library?p=198994&viewfull=1#post198994 which is very similar to your use case.
 
Last edited:
Great thanks Luni I'll take a look and see how far I can get before you're able to do the example.. I'll also look at the level shifter too - so this would need to go between the teensy and the stepper driver?

Lastly, how come the start sweep does not complete? If you are doing github examples, a solid zeroing example would be good. Is there a way to find home and then reset the stored home position?
 
Hi Luni,

Right so I have the below code to test your example, and I get an error around "overrideSpeed" not being a member... Does anything look wrong to you?

Code:
#include "TeensyStep.h"
#include "Arduino.h"

// Define some steppers and the pins the will use

Stepper SPEED_STEPPER(5, 6);   //STEP pin =  5, DIR pin = 6
Stepper RPM_STEPPER(7, 8);  //STEP pin =  7, DIR pin = 8
Stepper CT_STEPPER(9, 10); //STEP pin = 9, DIR pin = 10
Stepper FL_STEPPER(11, 12); //STEP pin = 11, DIR pin = 12

const int RESET = 18; // pin for RESET
const int numReadings = 50;
//---------------------------------------
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 10;  //the value is a number of milliseconds
StepControl controller;

constexpr unsigned PID_Interval = 10; // ms  
constexpr float P = 0.01;             // (P)roportional constant of the regulator needs to be adjusted (depends on speed and acceleration setting)
int32_t target = 0;

void pid()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > PID_Interval)
  {    
    float delta = (target - SPEED_STEPPER.getPosition()) * (P / PID_Interval);  // This implements a simple P regulator (can be extended to a PID if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}
-//---------------------------------------------

//Speed
int SPEED_Pin = 23;
int SPEED_Val = 0;
int SPEED_STEPS;
int SPEED_readings[numReadings];      // the readings from the analog input
int SPEED_readIndex = 0;              // the index of the current reading
int SPEED_total = 0;                  // the running total
int SPEED_average = 0;                // the average
int SPEED_MPH = 0;
int SPEED_SEND;


void setup()
{
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH);


  SPEED_STEPPER
  .setMaxSpeed(12000)       // steps/s
  .setAcceleration(750000); // steps/s^2

  SPEED_STEPPER.setTargetRel(3780);
  controller.move(SPEED_STEPPER);

  SPEED_STEPPER.setTargetRel(-3780);
  controller.move(SPEED_STEPPER, RPM_STEPPER);

  delay(1000);
  SPEED_STEPPER
  .setMaxSpeed(6000)       // steps/s
  .setAcceleration(10000); // steps/s^2


  startMillis = millis();  //initial start time
  elapsedMillis retargetTimer = 0;
  elapsedMillis outputTimer = 0;
}

void loop() {
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  pid();

  //if (currentMillis - startMillis >= (period*2))  //test whether the period has elapsed
  //{
  //=====SPEED CALC=============
  // subtract the last reading:
  SPEED_total = SPEED_total - SPEED_readings[SPEED_readIndex];
  // read from the sensor:
  SPEED_Val = map(analogRead(SPEED_Pin), 0, 1023, 0, 3189);  //scal val2 (kph) to stepper motor positions

  SPEED_readings[SPEED_readIndex] = SPEED_Val;
  SPEED_total = SPEED_total + SPEED_readings[SPEED_readIndex];
  SPEED_readIndex = SPEED_readIndex + 1;
  if (SPEED_readIndex >= numReadings) {
    SPEED_readIndex = 0;
  }

  // calculate the average:
  SPEED_STEPS = SPEED_total / numReadings;     //10*(((total / numReadings)+5)/10);
  SPEED_MPH = SPEED_STEPS / 15.945;


target = SPEED_STEPS;
}
 
Why not? Just change the StepControl to RotateControl. If you need to move the motors to an absolute position (like you do in setup()) use a step controller. You are not limited to one controller. Just make sure that you don't have two controllers moving the same motors at the same time.
 
I would ideally like to try and get this to work without changing the board design, as I have the prototype PCB in front of me for testing. Is there another way to get the steppers to follow the changing input values in the background?
 
Sorry, I was probably not clear in my last answer. Nothing needs to be changed on the hardware.

I don't have time to test your code right now, but you can try the following:

1) In line 13 of your code change StepControl to RotateControl
2) For first experiments remove all controller.move from your setup()
3) Test if the motor is following your input

As noted above, I'll do a worked out example on the weekend and put in on GitHub.
 
Awesome thanks Luni - really appreciate the help. I'll give this a try and will look forward to seeing your code at the weekend!
 
Morning Luni! I hope you had a good weekend. I spent quite a lot of time confused and trying to work out how to transmit and receive a frequency pulse rate. I finally succeeded at 2am on Sunday night :-O the joys of arduino. However I now finally have a stable signal that I can use to drive the stepper motors, currently using Accelstepper. Did you get on ok with the stepper example that I might be able to marry up to this? Thanks!
 
Success! I now have some code that runs really nicely, so much smoother than accelstepper! The last thing I would like is to do a nice sweep of the steppers on startup but I can't work out the best way to do it. I want all steppers to run to a pre-defined step number, then back to zero at the same time in the sketch setup. How do I do this? To ensure they are homed correctly, I intend to run them into the 0 stops prior to shutdown. Here's the code I now have:

Code:
#include "TeensyStep.h"
#include <AnalogSmooth.h>

//------Steppers--------------
constexpr float P = 0.01;             // (P)roportional constant of the regulator needs to be adjusted (depends on speed and acceleration setting)

constexpr unsigned Stepper1_Interval = 10; // ms
constexpr unsigned Stepper2_Interval = 10; // ms
constexpr unsigned Stepper3_Interval = 10; // ms
constexpr unsigned Stepper4_Interval = 10; // ms

const int RESET = 18; // pin for RESET

Stepper Stepper1(5, 6);
Stepper Stepper2(7, 8);
Stepper Stepper3(11, 12);
Stepper Stepper4(9, 10);
RotateControl controller1;
RotateControl controller2;
RotateControl controller3;
RotateControl controller4;

int32_t target = 0;
int32_t target2 = 0;
int32_t target3 = 0;
int32_t target4 = 0;

void Stepper1Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper1_Interval)
  {
    float delta = (target - Stepper1.getPosition()) * (P / Stepper1_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller1.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper2Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper2_Interval)
  {
    float delta = (target2 - Stepper2.getPosition()) * (P / Stepper2_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller2.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper3Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper3_Interval)
  {
    float delta = (target3 - Stepper3.getPosition()) * (P / Stepper3_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller3.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper4Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper4_Interval)
  {
    float delta = (target4 - Stepper4.getPosition()) * (P / Stepper4_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller4.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

//----------------------END STEPPERS------------------------------

//Milli Time -----------------------------
unsigned long currentMillis = 0;
unsigned long Prev_Time_Pot = 0;      // will store last time LED was updated
unsigned long Pot_Interval = 10;          // interval at which to blink (milliseconds
unsigned long Time_Millis = 0;
unsigned long Serial_Interval = 00;
unsigned long Prev_Time_Serial = 0;

//Speed-----------------------------------------
volatile unsigned long VSS_count = 0;
unsigned long VSS_prior_count = 0;
int pin_VSS = 14;
int SPEED_MPH;
int SPEED_STEPS;
unsigned long SpeedLastMicro;
unsigned long VSS_new_count;
int Speed_Teeth = 17;
float diffRatio = 3.42;
int WheelCirc = 2126; //mm
float GearboxToothGap = (1.0 / (Speed_Teeth));
float TyreTravelled = WheelCirc / diffRatio;
unsigned long SpeedTimeCount;
unsigned long speedRaw;
int Speed_Pulses = 0;
unsigned long SpeedTime;
//---------------------------------------------

//RPM
//Speed-----------------------------------------
volatile unsigned long RPM_count = 0;
unsigned long RPM_prior_count = 0;
int pin_RPM = 15;
int RPM;
int RPM_STEPS;
unsigned long RPMLastMicro;
unsigned long RPM_new_count;
int RPM_Teeth = 4;
unsigned long RPMTimeCount;
unsigned long RPMRaw;
int RPM_Pulses = 0;
unsigned long RPMTime;
//---------------------------------------------

//Coolant_T
int CT_Pin = 17;
int CT_STEPS;
int COOLANT_TEMP = 0;

//Fuel_L
int FL_Pin = 16;
int FL_STEPS;
int FUEL_LEVEL = 0;


//Pot Damper -----------------------------
float damping_coefficient = 0.01;
float Hz = 0;
int i = 1;
// Defaults to window size 10
AnalogSmooth as = AnalogSmooth();

// Window size can range from 1 - 100
AnalogSmooth as100 = AnalogSmooth(50);
AnalogSmooth as101 = AnalogSmooth(50);
//----------------------------------------

//Serial
char rc;
String readString;
int StrS1;
int StrF1;
int StrS2;
int StrF2;
int StrS3;
int StrF3;
int StrS4;
int StrF4;
String Pkt1;
String Pkt2;
String Pkt3;
String Pkt4;
String inChar;
int SPEED_SEND;
int RPM_SEND;
int CT_SEND;
int FL_SEND;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);

  //-------------Initiate stepper driver----------------
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH);

  while (!Serial && millis() < 1000);

  Stepper1
  .setMaxSpeed(10000)
  .setAcceleration(75000);
  controller1.rotateAsync(Stepper1);
  controller1.overrideSpeed(0); // start with stopped slide

  Stepper2
  .setMaxSpeed(10000)
  .setAcceleration(75000);
  controller2.rotateAsync(Stepper2);
  controller2.overrideSpeed(0); // start with stopped slide

  Stepper3
  .setMaxSpeed(10000)
  .setAcceleration(75000);
  controller3.rotateAsync(Stepper3);
  controller3.overrideSpeed(0); // start with stopped slide

  Stepper4
  .setMaxSpeed(10000)
  .setAcceleration(75000);
  controller4.rotateAsync(Stepper4);
  controller4.overrideSpeed(0); // start with stopped slide

//---------------------STEPPER HOMING CODE GOES HERE---------------------------



  //Speed Setup---------------------------------------------------
  GearboxToothGap = GearboxToothGap * TyreTravelled;
  pinMode(pin_VSS, INPUT_PULLUP);
  pinMode(pin_RPM, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(pin_VSS), SpeedPulse, RISING);
  attachInterrupt(digitalPinToInterrupt(pin_RPM), RPMPulse, RISING);
  NVIC_SET_PRIORITY(IRQ_PORTA, 0);
  //---------------------------------------------------

}

void loop() {
  noInterrupts ();
  VSS_new_count = VSS_count;
  RPM_new_count = RPM_count;
  interrupts ();
  SpeedTime = micros();
  RPMTime = micros();

  //----Speed Pulse Read----------
  Speed_Pulses = VSS_new_count - VSS_prior_count;
  if (Speed_Pulses >= 10) {
    SpeedTimeCount = (SpeedTime - SpeedLastMicro) / 1000;
    speedRaw = ((VSS_new_count - VSS_prior_count) * 60 * 1000 / (GearboxToothGap * SpeedTimeCount)) / 10;
    VSS_prior_count = VSS_new_count;
    SpeedLastMicro = SpeedTime;
  }

  //----RPM Pulse Read----------
  //  RPM_Pulses = RPM_new_count - RPM_prior_count;
  //  if (RPM_Pulses >= 4) {
  //    RPMTimeCount = (RPMTime - RPMLastMicro) / 1000;
  //    RPMRaw = 1000000 / RPMTimeCount;
  //    RPM_prior_count = RPM_new_count;
  //    RPMLastMicro = RPMTime;
  //  }


  //------Get Fuel & Temp Data

  //Serial.println(SpeedTime);
  currentMillis = millis();
  Time_Millis = currentMillis - Prev_Time_Pot;
  if (Time_Millis > Pot_Interval)
  {
    //=========READ SERIAL=========
    Get_Serial_Data();

    //=========OR READ POTS========
    //      COOLANT_TEMP = as100.analogReadSmooth(CT_Pin) / 10;
    //      //COOLANT_TEMP = 81798 / CT_Val; //Define line curve here
    //      COOLANT_TEMP = map(CT_Pin, 10, 1023, 20, 150);        // map temp
    //
    //      FUEL_LEVEL = as101.analogReadSmooth(FL_Pin) / 10;
    //      //FUEL_LEVEL = 81798 / FL_Val; //define line curve here
    //      FUEL_LEVEL = map(FL_Pin, 10, 1023, 0, 57);        // map fuel level

    Prev_Time_Pot = currentMillis;
    Prev_Time_Serial = currentMillis;
  }


  //=====SPEED CALC=============
  SPEED_MPH = speedRaw * 1.6;  //speed conversion
  SPEED_STEPS = map(SPEED_MPH, 0, 200, 0, 3189);

  //=====RPM CALC=============
  RPM_STEPS = map(RPM, 0, 7000, 0, -2835);
  
  //=====CT CALC=============
  CT_STEPS = map(COOLANT_TEMP, 20, 150, 0, 2216);
  
  //=====FL CALC=============
  FL_STEPS = map(FUEL_LEVEL, 0, 57, -2216, 0);


//=======MOVE STEPPERS=================
  Stepper1Update();
  Stepper2Update();
  Stepper3Update();
  Stepper4Update();

    target = SPEED_STEPS;    //random(-3000, 3000);
    target2 = RPM_STEPS;    //random(-3000, 3000);
    target3 = CT_STEPS;    //random(-3000, 3000);
    target4 = FL_STEPS;    //random(-3000, 3000);

  //Send Serial Data=============================
  
  currentMillis = millis();
  Time_Millis = currentMillis - Prev_Time_Serial;
  if (Time_Millis > Serial_Interval)
  {
    //noInterrupts ();
    Send_Serial_Data();
    //interrupts ();
  }
//Serial.println(RPM);
}
//================================END OF LOOP=============================

//================================FUNCTIONS===============================
void SpeedPulse() {
  VSS_count = VSS_count + 1;
}

void RPMPulse() {
  RPM_count = RPM_count + 1;
}

void Get_Serial_Data() {
  //inChar = Serial1.read();

  if (Serial1.available() > 0) {
    rc = Serial1.read();
    if (rc == '>') {
      //do stuff

      //Serial.println();
      //Serial.print("captured String is : ");
      Serial.println(readString); //prints string to serial port out

      if (readString.indexOf("S") > 0) {  //is speed in the data packet?
        StrS1 = readString.indexOf('S');  //finds start location
        StrF1 = readString.lastIndexOf('S'); //finds finish location
        Pkt1 = readString.substring(StrS1 + 1, StrF1); //captures data String
      }

      if (readString.indexOf("R") > 0) {  //is speed in the data packet?
        StrS2 = readString.indexOf('R');  //finds start location
        StrF2 = readString.lastIndexOf('R'); //finds finish location
        Pkt2 = readString.substring(StrS2 + 1, StrF2); //captures data String
      }

      if (readString.indexOf("T") > 0) {  //is speed in the data packet?
        StrS3 = readString.indexOf('T');  //finds start location
        StrF3 = readString.lastIndexOf('T'); //finds finish location
        Pkt3 = readString.substring(StrS3 + 1, StrF3); //captures data String
      }

      if (readString.indexOf("F") > 0) {  //is speed in the data packet?
        StrS4 = readString.indexOf('F');  //finds start location
        StrF4 = readString.lastIndexOf('F'); //finds finish location
        Pkt4 = readString.substring(StrS4 + 1, StrF4); //captures data String
      }

//            Serial.print("Speed = ");
//            Serial.println(Pkt1);
//            Serial.print("RPM = ");
//            Serial.println(Pkt2);
//            Serial.print("Coolant = ");
//            Serial.println(Pkt3);
//            Serial.print("Fuel = ");
//            Serial.println(Pkt4);
//            Serial.println();
//            Serial.println();


      readString = ""; //clears variable for new input
      //SPEED_MPH = Pkt1.toInt();
      RPM = Pkt2.toInt()*10;
      COOLANT_TEMP = Pkt3.toInt(); //Adjust to tune
      FUEL_LEVEL = Pkt4.toInt();
      //Serial.println(CT_STEPS);
      //Serial.println(RPM);
    }
    else {
      readString += rc; //makes the string readString
    }
  }
}

void Send_Serial_Data() {

 //if(SPEED_MPH != SPEED_SEND ||RPM != RPM_SEND ||COOLANT_TEMP != CT_SEND||FUEL_LEVEL != FL_SEND){Serial1.print('<');}

  if (SPEED_MPH != SPEED_SEND) {
    SPEED_SEND = SPEED_MPH;
    Serial1.print('<');
    Serial1.print('S');
    Serial1.print(SPEED_SEND);
    Serial1.print('S');
    Serial1.print('>');
  }
//Serial.println(SPEED_SEND);
//  if (RPM != RPM_SEND) {
//    RPM_SEND = RPM;
//    Serial1.print('R');
//    Serial1.print(-RPM_SEND);
//    Serial1.print('R');
//  }
//
//  if (COOLANT_TEMP != CT_SEND) {
//    CT_SEND = COOLANT_TEMP;
//    Serial1.print('T');
//    Serial1.print(CT_SEND);
//    Serial1.print('T');
//  }
//
//  if (FUEL_LEVEL != FL_SEND) {
//    FL_SEND = FUEL_LEVEL;
//    Serial1.print('F');
//    Serial1.print(-FL_SEND);
//    Serial1.print('F');
//  }

//if(SPEED_MPH != SPEED_SEND ||RPM != RPM_SEND ||COOLANT_TEMP != CT_SEND||FUEL_LEVEL != FL_SEND){Serial1.print('>');}


}
 
If I understand correctly your code is now able to make the stepper following some input, right? So, to get the sweep at startup you could simply fake the input say 1s 0 then 1s max which should produce a nice sweep.
 
Hi Luni thanks but I'd like to go to a specific step count to sweep a scale. Could I raise a step controller and .move to a step number then to 0 before I use rotate control?
 
Sorry, missed that post.
Yes, you can use a step controller and a rotate controller. Just make sure that only one of the controllers moves the motor at one time.
 
Hi Luni! Here is my updated code, but something is wrong... Now I have the two controller types, neither work. The pointers do not move on startup and also don't move when I move the input signal as they did before. I guess somehow the two are blocking each other?

Code:
#include "TeensyStep.h"
#include <AnalogSmooth.h>

//------Steppers--------------
constexpr float P = 0.01;             // (P)roportional constant of the regulator needs to be adjusted (depends on speed and acceleration setting)

constexpr unsigned Stepper1_Interval = 10; // ms
constexpr unsigned Stepper2_Interval = 10; // ms
constexpr unsigned Stepper3_Interval = 10; // ms
constexpr unsigned Stepper4_Interval = 10; // ms

const int RESET = 18; // pin for RESET

Stepper Stepper1(5, 6);
Stepper Stepper2(7, 8);
Stepper Stepper3(11, 12);
Stepper Stepper4(9, 10);
RotateControl controller1;
RotateControl controller2;
RotateControl controller3;
RotateControl controller4;

StepControl StepC;

int32_t target = 0;
int32_t target2 = 0;
int32_t target3 = 0;
int32_t target4 = 0;

void Stepper1Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper1_Interval)
  {
    float delta = (target - Stepper1.getPosition()) * (P / Stepper1_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller1.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper2Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper2_Interval)
  {
    float delta = (target2 - Stepper2.getPosition()) * (P / Stepper2_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller2.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper3Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper3_Interval)
  {
    float delta = (target3 - Stepper3.getPosition()) * (P / Stepper3_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller3.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

void Stepper4Update()
{
  static unsigned lastTick = 0;

  if (millis() - lastTick > Stepper4_Interval)
  {
    float delta = (target4 - Stepper4.getPosition()) * (P / Stepper4_Interval);  // This implements a simple P regulator (can be extended to a Stepper1 if necessary)
    float factor = std::max(-1.0f, std::min(1.0f, delta)); // limit to -1.0..1.0

    controller4.overrideSpeed(factor); // set new speed
    lastTick = 0;
  }
}

//----------------------END STEPPERS------------------------------

//Milli Time -----------------------------
unsigned long currentMillis = 0;
unsigned long Prev_Time_Pot = 0;      // will store last time LED was updated
unsigned long Pot_Interval = 10;          // interval at which to blink (milliseconds
unsigned long Time_Millis = 0;
unsigned long Serial_Interval = 00;
unsigned long Prev_Time_Serial = 0;

//Speed-----------------------------------------
volatile unsigned long VSS_count = 0;
unsigned long VSS_prior_count = 0;
int pin_VSS = 14;
int SPEED_MPH;
int SPEED_STEPS;
unsigned long SpeedLastMicro;
unsigned long VSS_new_count;
int Speed_Teeth = 17;
float diffRatio = 3.42;
int WheelCirc = 2126; //mm
float GearboxToothGap = (1.0 / (Speed_Teeth));
float TyreTravelled = WheelCirc / diffRatio;
unsigned long SpeedTimeCount;
unsigned long speedRaw;
int Speed_Pulses = 0;
unsigned long SpeedTime;
//---------------------------------------------

//RPM
//Speed-----------------------------------------
volatile unsigned long RPM_count = 0;
unsigned long RPM_prior_count = 0;
int pin_RPM = 15;
int RPM;
int RPM_STEPS;
unsigned long RPMLastMicro;
unsigned long RPM_new_count;
int RPM_Teeth = 4;
unsigned long RPMTimeCount;
unsigned long RPMRaw;
int RPM_Pulses = 0;
unsigned long RPMTime;
//---------------------------------------------

//Coolant_T
int CT_Pin = 17;
int CT_STEPS;
int COOLANT_TEMP = 0;

//Fuel_L
int FL_Pin = 16;
int FL_STEPS;
int FUEL_LEVEL = 0;


//Pot Damper -----------------------------
float damping_coefficient = 0.01;
float Hz = 0;
int i = 1;
// Defaults to window size 10
AnalogSmooth as = AnalogSmooth();

// Window size can range from 1 - 100
AnalogSmooth as100 = AnalogSmooth(50);
AnalogSmooth as101 = AnalogSmooth(50);
//----------------------------------------

//Serial
char rc;
String readString;
int StrS1;
int StrF1;
int StrS2;
int StrF2;
int StrS3;
int StrF3;
int StrS4;
int StrF4;
String Pkt1;
String Pkt2;
String Pkt3;
String Pkt4;
String inChar;
int SPEED_SEND;
int RPM_SEND;
int CT_SEND;
int FL_SEND;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(250000);
  pinMode(RESET, OUTPUT);

  //-------------Initiate stepper driver----------------
  digitalWrite(RESET, LOW);
  delay(1);  // keep reset low min 1ms
  digitalWrite(RESET, HIGH);


  //---------------------STEPPER HOMING CODE GOES HERE---------------------------
  Stepper1
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper2
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper3
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper4
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);

  StepC.move(Stepper1,Stepper2,Stepper3,Stepper4);

  Stepper1.setTargetRel(3800);
  Stepper2.setTargetRel(3800);
  Stepper3.setTargetRel(3800);
  Stepper4.setTargetRel(3800);

  StepC.move(Stepper1,Stepper2,Stepper3,Stepper4);
  
  
  //Speed Setup---------------------------------------------------
  GearboxToothGap = GearboxToothGap * TyreTravelled;
  pinMode(pin_VSS, INPUT_PULLUP);
  pinMode(pin_RPM, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(pin_VSS), SpeedPulse, RISING);
  attachInterrupt(digitalPinToInterrupt(pin_RPM), RPMPulse, RISING);
  NVIC_SET_PRIORITY(IRQ_PORTA, 0);
  //---------------------------------------------------

}

void loop() {
  noInterrupts ();
  VSS_new_count = VSS_count;
  RPM_new_count = RPM_count;
  interrupts ();
  SpeedTime = micros();
  RPMTime = micros();

  //----Speed Pulse Read----------
  Speed_Pulses = VSS_new_count - VSS_prior_count;
  if (Speed_Pulses >= 10) {
    SpeedTimeCount = (SpeedTime - SpeedLastMicro) / 1000;
    if (SpeedTimeCount > 400) { //---------------------------------MAY NEED TO CHANGE THIS TO LOCK IN 0
      speedRaw = 0;
    }
    else {
      speedRaw = ((VSS_new_count - VSS_prior_count) * 60 * 1000 / (GearboxToothGap * SpeedTimeCount)) / 10;
    }

    VSS_prior_count = VSS_new_count;
    SpeedLastMicro = SpeedTime;
  }

  //----RPM Pulse Read----------
  //  RPM_Pulses = RPM_new_count - RPM_prior_count;
  //  if (RPM_Pulses >= 4) {
  //    RPMTimeCount = (RPMTime - RPMLastMicro) / 1000;
  //    RPMRaw = 1000000 / RPMTimeCount;
  //    RPM_prior_count = RPM_new_count;
  //    RPMLastMicro = RPMTime;
  //  }


  //------Get Fuel & Temp Data

  //Serial.println(SpeedTime);
  currentMillis = millis();
  Time_Millis = currentMillis - Prev_Time_Pot;
  if (Time_Millis > Pot_Interval)
  {


    //=========OR READ POTS========
    //      COOLANT_TEMP = as100.analogReadSmooth(CT_Pin) / 10;
    //      //COOLANT_TEMP = 81798 / CT_Val; //Define line curve here
    //      COOLANT_TEMP = map(CT_Pin, 10, 1023, 20, 150);        // map temp
    //
    //      FUEL_LEVEL = as101.analogReadSmooth(FL_Pin) / 10;
    //      //FUEL_LEVEL = 81798 / FL_Val; //define line curve here
    //      FUEL_LEVEL = map(FL_Pin, 10, 1023, 0, 57);        // map fuel level

    Prev_Time_Pot = currentMillis;
    Prev_Time_Serial = currentMillis;
  }
    //=========READ SERIAL=========
    Get_Serial_Data();

  //=====SPEED CALC=============
  SPEED_MPH = speedRaw * 1.6;  //speed conversion
  SPEED_STEPS = map(SPEED_MPH, 0, 200, 0, 3000);

  //=====RPM CALC=============
  RPM_STEPS = map(RPM, 0, 7000, 0, -2835);

  //=====CT CALC=============
  CT_STEPS = map(COOLANT_TEMP, 20, 150, 0, 2216);

  //=====FL CALC=============
  FL_STEPS = map(FUEL_LEVEL, 0, 57, -2216, 0);


  //=======MOVE STEPPERS=================
  Stepper1Update();
  Stepper2Update();
  Stepper3Update();
  Stepper4Update();

  target = SPEED_STEPS;    //random(-3000, 3000);
  target2 = RPM_STEPS;    //random(-3000, 3000);
  target3 = CT_STEPS;    //random(-3000, 3000);
  target4 = FL_STEPS;    //random(-3000, 3000);

  //Send Serial Data=============================

  currentMillis = millis();
  Time_Millis = currentMillis - Prev_Time_Serial;
  if (Time_Millis > Serial_Interval)
  {
    //noInterrupts ();
    Send_Serial_Data();
    //interrupts ();
    Serial.println(SpeedTimeCount);
  }
  //Serial.println(RPM);
}
//================================END OF LOOP=============================

//================================FUNCTIONS===============================
void SpeedPulse() {
  VSS_count = VSS_count + 1;
}

void RPMPulse() {
  RPM_count = RPM_count + 1;
}

void Get_Serial_Data() {
  //inChar = Serial1.read();

  if (Serial1.available() > 0) {
    rc = Serial1.read();
    if (rc == '>') {
      //do stuff

      //Serial.println();
      //Serial.print("captured String is : ");
      //Serial.println(readString); //prints string to serial port out

      if (readString.indexOf("S") > 0) {  //is speed in the data packet?
        StrS1 = readString.indexOf('S');  //finds start location
        StrF1 = readString.lastIndexOf('S'); //finds finish location
        Pkt1 = readString.substring(StrS1 + 1, StrF1); //captures data String
      }

      if (readString.indexOf("R") > 0) {  //is speed in the data packet?
        StrS2 = readString.indexOf('R');  //finds start location
        StrF2 = readString.lastIndexOf('R'); //finds finish location
        Pkt2 = readString.substring(StrS2 + 1, StrF2); //captures data String
      }

      if (readString.indexOf("T") > 0) {  //is speed in the data packet?
        StrS3 = readString.indexOf('T');  //finds start location
        StrF3 = readString.lastIndexOf('T'); //finds finish location
        Pkt3 = readString.substring(StrS3 + 1, StrF3); //captures data String
      }

      if (readString.indexOf("F") > 0) {  //is speed in the data packet?
        StrS4 = readString.indexOf('F');  //finds start location
        StrF4 = readString.lastIndexOf('F'); //finds finish location
        Pkt4 = readString.substring(StrS4 + 1, StrF4); //captures data String
      }

      //            Serial.print("Speed = ");
      //            Serial.println(Pkt1);
      //            Serial.print("RPM = ");
      //            Serial.println(Pkt2);
      //            Serial.print("Coolant = ");
      //            Serial.println(Pkt3);
      //            Serial.print("Fuel = ");
      //            Serial.println(Pkt4);
      //            Serial.println();
      //            Serial.println();


      readString = ""; //clears variable for new input
      //SPEED_MPH = Pkt1.toInt();
      RPM = Pkt2.toInt() * 10;
      COOLANT_TEMP = Pkt3.toInt(); //Adjust to tune
      FUEL_LEVEL = Pkt4.toInt();
      //Serial.println(CT_STEPS);
      //Serial.println(RPM);
    }
    else {
      readString += rc; //makes the string readString
    }
  }
}

void Send_Serial_Data() {

  //if(SPEED_MPH != SPEED_SEND ||RPM != RPM_SEND ||COOLANT_TEMP != CT_SEND||FUEL_LEVEL != FL_SEND){Serial1.print('<');}

  if (SPEED_MPH != SPEED_SEND) {
    SPEED_SEND = SPEED_MPH;
    Serial1.print('<');
    Serial1.print('S');
    Serial1.print(SPEED_SEND);
    Serial1.print('S');
    Serial1.print('>');
  }
  //Serial.println(SPEED_SEND);
  //  if (RPM != RPM_SEND) {
  //    RPM_SEND = RPM;
  //    Serial1.print('R');
  //    Serial1.print(-RPM_SEND);
  //    Serial1.print('R');
  //  }
  //
  //  if (COOLANT_TEMP != CT_SEND) {
  //    CT_SEND = COOLANT_TEMP;
  //    Serial1.print('T');
  //    Serial1.print(CT_SEND);
  //    Serial1.print('T');
  //  }
  //
  //  if (FUEL_LEVEL != FL_SEND) {
  //    FL_SEND = FUEL_LEVEL;
  //    Serial1.print('F');
  //    Serial1.print(-FL_SEND);
  //    Serial1.print('F');
  //  }

  //if(SPEED_MPH != SPEED_SEND ||RPM != RPM_SEND ||COOLANT_TEMP != CT_SEND||FUEL_LEVEL != FL_SEND){Serial1.print('>');}


}

The sweep/homing code I added is this:

controller initiation:

Code:
StepControl StepC;

Then in setup:

Code:
  Stepper1
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper2
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper3
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);
  
  Stepper4
  .setMaxSpeed(10000)
  .setAcceleration(75000)
  .setTargetRel(3700);

  StepC.move(Stepper1,Stepper2,Stepper3,Stepper4);

  Stepper1.setTargetRel(3800);
  Stepper2.setTargetRel(3800);
  Stepper3.setTargetRel(3800);
  Stepper4.setTargetRel(3800);

  StepC.move(Stepper1,Stepper2,Stepper3,Stepper4);
 
Sorry, forgot to mention that the possibility to define more than 4 controllers is not yet in the master branch (should really merge that...). Can you please try the branch DevTimer instead. This allows for defining as many controllers as you like. You just need to make sure not using more than 4 at the same time (this is limited by the available hardware timers).
 
Status
Not open for further replies.
Back
Top