TeensyStep reverse not working as it should be.

krbek

Member
Hi Forum.

@luni from teensyStep

Please excuse me my ignorance.
Having no technical background and totally no programming experience.

Just a musician trying to engineer something useful. (i.e. grinding a bassoon reed. For reference a bassoon sounds like this: https://www.youtube.com/watch?v=ldMz94OGbIM)

The situation:
Using following stepper/servo motor: https://shop.cnc-technics.de/Integrated-Servo-Motor-36VDC-JMC-iHSV57-30-18-36-62-126.html
(and the same problem arises with the other stepper motor I have for testing: https://shop.cnc-technics.de/IHSS60-36-30-31-2phase-Hybrid-3Nm-Closed-Loop-Schrittmotor-39-40-172.html

Using a teensy 3.2 custom pcb from the same shop.

Searched online and offline for a way to advance and reverse the given motor using following basic code:

Code:
#include "TeensyStep.h"
Stepper motor (2,15);                   // Basic stepper
StepControl controller;                 // Use default settings 

void setup() {
  motor.setMaxSpeed(66000);
  motor.setAcceleration(60000);  
}

void loop() {
  Serial.println(millis());                         // Just so I know something is happening

  motor.setTargetAbs(10000);                    // motor advances clock wise
  controller.move(motor);
  delay(1000);

  motor.setTargetAbs(-10000);                   // I should expect motor reversing counter-clock wise, but it still advances. Examening the currentposition hower gives the startposition (i.e. 0)
  controller.move(motor);
  delay(1000);
}

The motor.setTargetAbs(10000) advances the motor clock-wise.
I would excpect the statement "motor.setTargetAbs(-10000) to go counter-clockwise.

Hower the motor just keeps advancing.

In a more extended example, the motor.getPosition() before and after advancing gives a correct position but the motor is not physically reversing direction.

Need some desperate help for this.

Code:
#include "TeensyStep.h"

Stepper motor (2,15);                   // Basic stepper

// Stepper GrindingMtr (2, 15);         // STEP pin: 2, DIR pin: 15
// Stepper RotateMtr (3, 14);           // STEP pin: 3, DIR pin: 14

StepControl controller;                 // Use default settings 
RotateControl rotator;                  // Use default settings for the GrindingController

const int rpm = 1600;
const int spindlePPR = 3200;                                            // Hardware settings pulse per revolution (dip switches)
const int spindleSPR = 200;                                             // steps per revolution (360/1.8°)
const int spindleAccel = 75000;                                         // spindle acceleration
constexpr signed spindleSpeed = (rpm * spindlePPR) / 60;                // steps per second

const int ledPin = 13;        // Led pin

void setup()
{
  Serial.begin(9600); // USB is always 12 or 480 Mbit/sec
  while (!Serial);

  // Define ledpin
  pinMode(ledPin, OUTPUT);

  // Parameter for the stepper motor
  motor
    .setAcceleration(spindleAccel)
    .setMaxSpeed(spindleSpeed);

  // H for HELP ME !
  Serial.println("h for help");
}

void loop() 
{
  handleCommands();
}

void moveToPosition(int numberOfSteps)
{
  int newPosition = motor.getPosition() + numberOfSteps;
  
  if (!controller.isRunning() && !rotator.isRunning())        // skip move command if motor is running already
  {
      printTxt("Requested number of steps: ", numberOfSteps);
      printTxt("             Resulting in (new) position  : ", newPosition);
      printTxt("             Moving from current position : ", motor.getPosition());
  
      // motor.setStepPinPolarity(HIGH);           // ????
      motor.setTargetAbs(newPosition);
      
      controller.move(motor);
      
      Serial.println("             Started Motor movement.");
      printTxt("             Motor now at position: ", motor.getPosition());
  }
  else
  {
      Serial.println("Ignored, Motor is already running");
  }
}

void handleCommands()
{
    if (Serial.available() > 0)                 // skip if the serial buffer is empty
    {
        char cmd = Serial.read();               // get one char from the buffer...
        switch (cmd)                            // ... and analyze it
        {
          // ------------------
          // move command
          // ------------------
          case 'p':
              moveToPosition(0);              
              break;
              
          case 'f':                               
              moveToPosition(spindleSPR);         // forward is ok
              break;

          // ------------------
          // Reverse move
          // ------------------
          case 'r':                               // reverse direction
              moveToPosition(-spindleSPR/2);      // reverse is NOT OK. Position will be correct, but motor not spinning counter clock wise !
              break;
              
          // ------------------
          // Start to rotate at the given rpm (using the rotator control)
          // ------------------            
          case 'g':
            {
              if (!rotator.isRunning() && !controller.isRunning())
              {
                // Async so the rotation motor can do its stuff
                printTxt("Grinding process started at speed : ", rotator.getCurrentSpeed());
                rotator.rotateAsync(motor);
              
                while(rotator.getCurrentSpeed() < spindleSpeed)
                {
                  printTxt("              ", rotator.getCurrentSpeed());
                  delay(50);
                }
                
                Serial.println("Full speed achieved.");
                printTxt("Rotator currentspeed (MAX): ", rotator.getCurrentSpeed());
              }
              else
              {
                printTxt("Command to grind ignored. Spindle already running", "");
              }
            }  
            
            break;

          // ------------------
          // Stop all movement
          // ------------------
          case 's':                               // stop command
              if (controller.isRunning())
              {
                controller.stopAsync();             // initiate stopping procedure
                Serial.println("Stopping motor");
              }
              
              if (rotator.isRunning())
              {
                rotator.stopAsync();
                Serial.println("Stopping rotator");
              }
              
              break;

          // ------------------
          // Blink a while
          // ------------------
          case 'b':
            Blink(5);

          // ------------------
          // HELP ME
          // ------------------
          case 'h':                               // help / usage command
          case 'u':
              Serial.println("\nUsage:");
              Serial.println("  f: move Motor Forward.");
              Serial.println("  r: move Motor Backward.");
              Serial.println("  g: start grinding process. Spindle up to speed.");
              Serial.println("  p: go to position 0.");
              Serial.println("     --------------------------------------------");
              Serial.println("  s: stop motor.");
              Serial.println("     --------------------------------------------");
              Serial.println("  b: blink the led.");
              Serial.println("  h: display this help.");            
              break;
  
          default:
              break;
        }
    }
}

void printTxt(String t1, String t2)
{
  Serial.print(t1);
  Serial.println(t2);
}

void Blink(int numberOfTimes)
{
  if (numberOfTimes <= 0) numberOfTimes = 1;

  for (int i = 0; i < numberOfTimes; i++)
  {
    digitalWrite(ledPin, HIGH);     // turn the LED on (HIGH is the voltage level)
    delay(500);                     // wait for half a second
    
    digitalWrite(ledPin, LOW);      // turn the LED off by making the voltage LOW
    delay(500);                     // wait for half a second
  }
  
}
 
Last edited:
The code in your first example should definitely work. I assume some electrical issue. E.g. The datasheet of the motors you linked requires 5-24V signals. The 3.3V output might be too small to drive the opto-coupled inputs directly. You can check by connect the dir input manually to 5V / 0V and see if the direction changes. Can you post a schematic / sketch showing how you wired everything? Did you check the settings of the motor? Looks like it has different control modes which can be set by software...
 
The code in your first example should definitely work. I assume some electrical issue. E.g. The datasheet of the motors you linked requires 5-24V signals. The 3.3V output might be too small to drive the opto-coupled inputs directly. You can check by connect the dir input manually to 5V / 0V and see if the direction changes. Can you post a schematic / sketch showing how you wired everything? Did you check the settings of the motor? Looks like it has different control modes which can be set by software...

Hi Luni,

Thanks for your reply !

This just seems like Chinese to me.

What I have came up with is connection-schema in annex.

(trying to find out how I connect an attachment to this thread ... hold on a minute - or two) .....

I assume also some electrical issue. I.e. trying to "reverse polarity" or do something crazy just doesn't seem to work.

What I have tried so far:
1. Dip switches to "automatic"
2. Dip switches to on-on-of-of .... and multiple variations of this one.
3. Reverse polarity (positive to negative .... as seen in the stargate movie ....)

I can "change" the direction when setting dip-switch 5 to on or off.

Hope You can see what might be wrong here ...

Have to prepare now for the next concert. Might not be able to respond immediately ... (The conductor won't be please if would be on the phone during the concert ....)

thanx !

Kris
 

Attachments

  • Schematic_Wiring_BassoonProfiler.pdf
    25.2 KB · Views: 27
  • Teensy_Module_Pins.pdf
    107.1 KB · Views: 25
  • 20211130_192957.jpg
    20211130_192957.jpg
    39.7 KB · Views: 36
It is quite difficult to help you remotely on this. Might be a very good idea to find a local guy with some electronics background to help you wiring it.

Anyway, lets give it a try: Looks like the Teensy breakout board is capable to drive those motor inputs. And, since the motor spins, the pulse signal arrives at the motor. Do you know why the DIR signal is wired with common 5V while the pulse signal is wired with common GND? It should work in both ways just curious why it is not wired in the same way for both signals. Do you think you can get a schematic of or at least more information about the breakout board?

I can "change" the direction when setting dip-switch 5 to on or off.

This is good.

Can you measure the voltage between GND and the orange wire connected to SW2 while your program runs? The voltage should change every second. Let us know what you see. If you don't have a meter, remove the orange wire from SW2 on the breakout board and connect it to GND / 5V (switch everything off before doing this). The direction should change depending on the voltage on this wire. If it doesn't, check if you have a good connection between SW2 and the motor, check for a broken cable etc.
 
Last edited:
I had a closer look at the drawing of that breakout board. Of course this is only wild guesswork, but from the parts on the board it looks like the DIR and PUL outputs are switched by some transistor (Q3 / Q3) the SW1/SW2 outputs might be connected to the Teensy pins directly? Anyway, if the above doesn't work you could try to connect the PUL+/- and DIR +/- of one motor directly to the PUL+/- DIR+/- terminals of the breakout board. In your sketch you'd have to change the Stepper constructor to
Code:
Stepper motor (3,2);

Of course this would only work for one motor but could exclude issues with the SW1/SW2 terminals.
 
Thanx Luni !

Anyway, lets give it a try:

I'll give it a try today and come back to it.

The cables should be fine. (all brand new cables).
Attached a complete view of the setup.

20211130_192716.jpg
 
Last edited:
Hi Luni.
Just tested this one:
Can you measure the voltage between GND and the orange wire connected to SW2 while your program runs?

See attacheed image.
Voltage reed 5v.
No change when idle and no change when running.Voltage.png
 
Hi Luni.
No change when idle and no change when running

Which explains why the direction doesn't change. Can you do a simple sketch just toggling pin15 every second and check with your meter if that appears on SW2? (don't forget to set the pinmode to output). I'd also check SW1, maybe the pin association was swapped in your drawing? If you don't see changes on SW2/SW1 if you toggle pin14/15 I'd call the manufacturer of the breakout board and ask for advice.

Edit: additionally measure directly on the Teensy pins 14/15.
 
I'll try.

Something like this should achieve the toggling on pin15 ?

Code:
void setup() {
  // put your setup code here, to run once:
  pinMode(15, OUTPUT);                            // Must not forget this one.
}

void loop() {
  // put your main code here, to run repeatedly:

    digitalWrite(15, HIGH);     
    delay(1000);                     // wait for a second
    
    digitalWrite(15, LOW);        
    delay(1000);                     // wait for a second

}

After setting the pin 15 or 14 to output (what I did not do the first time :() I have some sequential voltage readings
0 - 2 - 5 - 0 - 3 - 5 .....

On both pin 14 and pin 15 (not at the same time though).

A little thought of mine: could it be that powering the teensy board using the usb cable connected to the computer does not provide enough voltage to power the board and give the pulses needed ?
 
Last edited:
And what happens if you use the first example sketch you posted? If you set the target positions to 60000 it should move for about 1 second in each direction. You should be able to see that on the meter as well.

A little thought of mine: could it be that powering the teensy board using the usb cable connected to the computer does not provide enough voltage to power the board and give the pulses needed ?
I assume that you power the board with via its power connector right?

Screenshot 2021-12-01 144327.png
 
Hallo Luni.

I assume that you power the board with via its power connector right?

No. (not yet). I was powering it over USB to upload the program from the computer.
Yesterday I also contacted the vendor who is also very helpful. (and very patient with me !)

The board should be powered via its power connector.
And the GND from the motor(s) should be attached to the GND on the board.
I should have known this as the board is intended as a standalone board.

I'll give that a try and give some feedback afterwards.

Power_Suply.png
 
@Luni

Code:
for (int i = 0; i < 10; i++)
{
      serial.println ("Please don't blame me for I was wrong. :-)");
      
     for (int j = 0; j < 1000; j++)
      {
          serial.println.InCapitals("Thank you");
      }
}

Connecting the power to a correct power suply (and not powering the board through the USB) lets me spin the motor forward, backwards and every direction it should.

I can get it to spin up to 85.000 (checked with the rotator.getCurrentSpeed()).

forward and .... backward.


ps. quick question: should the motor not be able to run twice that speed according to the specs?
 
Connecting the power to a correct power suply (and not powering the board through the USB) lets me spin the motor forward, backwards and every direction it should.
He, he, the good old 'forgot to plug the power cord in' :))

I can get it to spin up to 85.000 (checked with the rotator.getCurrentSpeed()).
forward and .... backward.
ps. quick question: should the motor not be able to run twice that speed according to the specs?

Hm, what does 85.000 mean? 85 RPM? 85,000 steps per second? Fullsteps? Microsteps? How many steps per rev? ...

I didn't read the manual very thoroughly but the servos you are using are highly configurable. There also is some software to parameterize the driver. I'm afraid you'll need to read into the manual to get the best performance out of your servos. Or just ask the vendor for help. He probably knows his servos well and can tell you what you can expect and if/what optimizing of the settings will improve the performance.
 
Hi Luni


The 85.000 is the measurement I get back when calling the rotator.getCurrentSpeed();

Calculating it as follows:
Code:
const int rpm = 1500;
const int spindlePPR = 3200;                                             // Hardware settings pulse per revolution (dip switches)
const int spindleSPR = 200;                                             // steps per revolution (360/1.8°)
const int spindleAccel = 75000;                                         // spindle acceleration
constexpr signed spindleSpeed = (rpm * spindlePPR) / 60;                // steps per second

Apparently it has to do with the max of 150 khz the teensyboard can go.
My guess now is that lowering the "spindlePPR" to 800 instead of 3.200 will give lesser khz for a higher maximum speed.

(Although 1.600 rpm is fine since there will be a gear mounted on to it with a ratio of 1:1.9 (approx.) so the motor spins at 1.500 rpm and the grinding part spins at 2.850 rpm - which I hope will be sufficient)

The machine will look something like this ...
usage_final.png
 
Apparently it has to do with the max of 150 khz the teensyboard can go.

The T3.6 runs at 150MHz not kHz and TeensyStep is good for about 300kHz step rate. So, I doubt that the limitation comes from the Teensy side. If you have a scope you could try to measure the pulse signal and see if you find something strange at above 85kHz. If it is important to you I can do some measurements checking if there is something wrong with the library at >85kHz later today.

The issue might also be related to the circuitry on the break out board (unlikely). As I mentioned, If you really want/need to you improve the performance of your servos, you need to dig into the manual to optimize the settings for your motor. All this parametrization stuff is there for a reason...

I like that kind of machines. Would love to see some video showing it in action :)
 
I like that kind of machines. Would love to see some video showing it in action :)

Hopefully it will be finished in January. (purpose of it is to highly increase the accuracy of the grinded reed increasing sound quality etc.)
I'll certainly will post a video of it working.

The board is equipped with a Teensy 3.2

If you have a scope you could try to measure the pulse signal and see if you find something strange at above 85kHz
No other machines then a simple voltage meter and screwdriver.

I'll also give it a try to set the dip switches to 800 instead of 3.200 pulses per revolution.
With a RPM of 1.500 this will give (1500*800)/60 = 20.000 (pulses I guess, hence the kHz. Learned something new today)
With a RPM of 3.000 this will give (3000*800)/60 = 40.000
 
Hi Luni

Just gave it a try with the 800 pulses per revolution.
The motor spins up fine up to 3.000, 4.500 rpm (with the above formula);
(Don't know if the pulses correlates to 3.000 or 4.500 rpm but there is a distinct audible difference when spinning at 1.000, 1.500 or 3.000 rpm).

When the machine is ready I'll post a video of it.
In the mean time some more testing to do with connecting the second motor and a push-button to start the process.

I'll try not to forget to plug in the power chord :)
 
Back
Top