36V4 uncooperative

I have been browsing the answers to others. We have a solidly-soldered set of pins on the “left” side of the board (as shown in Pictures), plugged into a standard breadboard. We have a solidly-soldered set of terminal blocks on the other side (terminal blocks and header pins Do Not Play Well Together so we have the pins on only one side).

The testbed is currently an Arduino Nano; the program is compiled and uploaded via the Arduino IDE. The stepper is a NEMA-23 4.2A/phase motor. Input voltage is 36VDC via the VIN/GND pins on the terminal block. Both the motor power and the stepper are connected to the output pins, and we have verified that the one coil is connected to the A pins and the other coil is connected to the B pins, so we should not be seeing an open-circuit fault, and in any case, this would just show up as a fault, not as a nonresponsive controller.

Here are the relevant parts of the program:

#include  <HighPowerStepperDriver.h>

HighPowerStepperDriver driver;

static const int DriverSelectPin = 5;

void setup() {
  Serial.begin(115200);
  pinMode(DriverSelectPin,OUTPUT);
  Serial.print(1);

  driver.setChipSelectPin(DriverSelectPin);
  Serial.print(2);
  driver.resetSettings();
  Serial.print(3);
  driver.setCurrentMilliamps36v4(4200);
   Serial.print(4);
  

  Serial.println("setup complete");
}

This looks fairly vanilla to me. We have SDATO wired to MISO (Nano pin 12), SDATI wired to MOSI (Nano pin 11), SCLK wired to SCK (Nano pin 13). SCS is connected to Nano D5, as per the declaration of DriverSelectPin shown in the code.

When the program starts up, the serial monitor prints “12” and output stops. This means that driver.resetSettings() is not returning. I had expected to see “1234setup complete”.

I do not see anything obviously wrong with the circuit (although it is being done by my student about 15 miles away, we meet via Skype). We have gone over the wiring several times, carefully, and verified that all the pin numbers are correct. This Nano has previously run, with different code, an A4988 controller, so I believe it is fully working. Also note that it does print out 1 and 2, but not 3. So something is wrong, but we are now stuck on how to figure out what the problem is. Advice appreciated.

Hello.

It looks like you are not including the SPI.h library (or initializing SPI with SPI.begin()). I recommend looking at the examples from our High-Power Stepper Motor Driver library for Arduino to see how to initialize and enable the driver. If you still have problems, I recommend running the unmodified example programs, and if those don’t work it is likely a connection issue.

Additionally, please note that the High-Power Stepper Motor Driver 36v4 can deliver up to 4 A continuous per phase without a heat sink or forced air flow, and we strongly recommend against using a current limit higher than 4A unless you are careful to monitor the MOSFETs’ temperatures and/or restrict how long the driver uses the higher current limit. This motor driver has no meaningful over-temperature shut-off (while the DRV8711 IC has over-temperature protection, it is the external MOSFETs that will overheat first). An over-temperature condition can cause permanent damage to the motor driver.

Brandon

Thank you. I would have expected to have found HighPowerStepperDriver.begin() which would simply have called SPI.begin(), which would have made it apparent. I did not find a link to the examples, which I would have thought would have been prominently displayed somewhere. We willl try this some time in the next day or two depending on our schedules.

OK. We downloaded the SPI-based example. We changed the CSPin from 4 to 5 (consistent with our wiring) and changed the mA to 4000. No joy. No motor movement. So we replaced the NEMA-23 36V 4.2A stepper motor with a NEMA-17 12V 2A stepper motor, changed the mA to 2000 and set the power supply to 12V. Still no joy. I have commands to read and print the status register, and I get 0, so there are apparently no faults. So we have no idea what to do next.

Here is the new setup() and friends

#include  <SPI.h>
#include  <HighPowerStepperDriver.h>

static const int DriverSelectPin = 5;

HighPowerStepperDriver driver;

void setup() {
  
  SPI.begin();  // Required for Pololu 36V4 driver board
  
  Serial.begin(115200);
  
  pinMode(DriverSelectPin,OUTPUT);
  delay(1);
  //Serial.print(1);

  driver.setChipSelectPin(DriverSelectPin);
  //Serial.print(2);
  
  driver.resetSettings();
  driver.clearStatus();
  //Serial.print(3);
  
  driver.setCurrentMilliamps36v4(4000);
  //Serial.print(4);

  driver.enableDriver();

  pinMode(vrxAPin,INPUT);
  pinMode(vryAPin,INPUT);
  pinMode(swAPin,INPUT_PULLUP);

 
  Serial.println(F("setup complete"));
} // setup

Can you post pictures of your setup that show all of your connections as well as your full code that you are using to test the driver?

Also, have you tried running the example program from the library (with the current limit adjusted for your motor)? Please note that once the library is installed, the examples can be accessed through the Arduino IDE’s File > Examples menu as with standard Arduino libraries.

Brandon

I will ask my student to take some pictures and will post them later tonight or tomorrow, whenever he gets them to me.

OK, here’s the whole thing. In the photos, one of the photos shows the joystick control.

This code had previously been used to control a “classic” NEMA-17 stepper, using the A4988 board (also from Pololu). It worked perfectly. So we modified the code (the command table previously only went to 1/16, and it had MS1, MS2 and MS3 members; the new command table has more entries and uses the symbols from HighPowerStepper.h). So this code has been tested and works with another board. However, various attempts to cause the 36V4 to control the NEMA-23 stepper motor have been fruitless.

#include  <SPI.h>
#include  <HighPowerStepperDriver.h>

HighPowerStepperDriver driver;

//#undef F
//#define F(x) x

static const int vrxAPin = A7;
static const int vryAPin = A6;
static const int swAPin =  7;
static const int vrxBPin = A4;
static const int vryBPin = A1;
static const int swBPin =  6;

static const int DriverSelectPin = 5;

static const int potPin = A0;

static  int fractionStep = 8;// step interval is 1/fractionStep
static  int stepsPerRevolution =200* fractionStep;
static const int moveFast = 500;
static const int moveSlow = 800;
static const int moveVariable = -1;
static char stepMode = ' ';
static int moveDirection = 1;
static  int minWait = 50;
static  int maxWait = 3000;
 
//static const int driftX = 8;
//static const int driftY = 8;
static bool useJoystick = true;

static const int MAXTEST = 100;

/*************************************************************************
 * The nominal zero positions of the joysticks.  These will be recomputed
 * by the calibrate() procedure
 *************************************************************************/
static int vrxAZero = 508;
static int vryAZero = 516;

/**************************************************************************
 * class Joystick
 **************************************************************************/
class Joystick {
public:
  int XPin;  //analog input pin
  int YPin;  //analog input pin
  int swPin;  // switch pin

  int XZero;  // X Zero value 
  int YZero;  //Y Zero value

   int Xdrift;
   int Ydrift;

   Joystick ( int XP,int YP,int SPi,int XZ = 508,int YZ = 516,int XD = 8, int YD = 8)
   {
   XPin = XP;
   YPin = YP; 
   swPin = SPi;
   XZero = XZ;
   YZero = YZ;
   Xdrift = XD;
   Ydrift = YD;
   }

   void calibrate()
   {
    XZero = average(XPin);
    YZero = average(YPin);   
   }

   void showcalibrate()
   {
    Serial.print(F("x = "));
    Serial.print(XZero);
    Serial.print(F(" y = "));
    Serial.print(YZero);
   }

   /*******************************************************************
    * Joystick::getXWait
    * Inputs:
    *    bool & nothing: Set 'true' if there is nothing to do
    *    bool & direction: Set 'true' for positive motion, false for negative motion
    *    
    * Effect:
    * Computes the "wait time" to control the speed of the X-axis
    * This is done by reading the X-position potentiometer, and computing
    * the absolute value from the zero point
    *             X0
    * 0           |         1023
    *             V
    * -X0...................1023-X0
    *         |
    *********************************************************************/
   int getXWait(bool & nothing, bool &  direction)
   {
      int vrx = analogRead(XPin);
      int speed = map( vrx, 0, 1023, - XZero, 1023 - XZero);
      int abspeed = abs(speed);
      nothing = abspeed == 0;
      int limit = vrx < XZero ? XZero : 1023 - XZero;
      int wait = map (abspeed, 0, limit, maxWait, minWait);
      direction = speed > 0;
      return  wait;
   }

  
   int getX ()
    {
      return analogRead(XPin);
    }
   int getY ()
    {
      return analogRead(YPin);
    } 
   int getsw ()
    {
      return analogRead(swPin);
    }
    /************************************************
     * inDriftX, inDriftY
     * Inputs:
     *      int x (or y): The x- (or y-) coordinate read from the joystick
     * Result: bool
     *       true if the value is within the nominal 
     *       "drift" of the zero  point
     ************************************************/
    bool inDriftX(int x )
    {
    return (abs(x - XZero) <= Xdrift); 
    }
        bool inDriftY ( int y )
    {
    return (abs(y - YZero) <= Ydrift);  
    }
protected:
    int average(int Pin)
    {
    long Center = 0;
    for(int i = 0; i < MAXTEST; ++ i)
        {
        Center += analogRead(Pin);  
        }
    return  Center / MAXTEST;     
    }
}; // class Joystick

Joystick JSleft(vrxAPin,vryAPin,swAPin);
Joystick JSright(vrxBPin,vryBPin,swBPin);

static bool debug = false;
static bool showStep = false;
/***********************************************************
 * uSteps
 * 
 * This is the table of microstep values and the corresponding
 * command names.  This table will be printed out as part of the
 * 'help' message
 ***********************************************************/
typedef struct {
    char name;               // command letter
    int minWait;             // minimum delay in microseconds
    HPSDStepMode Mode;       // the value to use in setStepMode
    int fraction;            // human-readable fraction number
} MSTABLE;

MSTABLE uSteps[] = {
  //cmd  |minWait| Mode                      | fraction
  //-----+-------|---------------------------+----------
    {'w',     530, HPSDStepMode::MicroStep1,     1},     //  [0]
    {'h',     220, HPSDStepMode::MicroStep2,     2},     //  [1]
    {'q',      70, HPSDStepMode::MicroStep4,     4},     //  [2]
    {'e',       0, HPSDStepMode::MicroStep8,     8},     //  [3]
    {'s',       0, HPSDStepMode::MicroStep16,   16},     //  [5]
    {'V',       0, HPSDStepMode::MicroStep32,   32},     //  [6]
    {'X',       0, HPSDStepMode::MicroStep64,   64},     //  [7]
    {'Y',       0, HPSDStepMode::MicroStep128, 128},     //  [8]
    {'Z',       0, HPSDStepMode::MicroStep256, 256},     //  [9]
    {0}         // EOT                                   // [10]
}; 


 static int offset = 0;

/*************************************************************
 * calibrate
 * 
 * Effect:
 *    Computes the "at rest" position of the joystick potentiometer
 *    It is nominally 512, but there is no guarantee
 * Notes:
 *    This is currently called by explicit user command.  In a
 *    user-input-free environment, this should probably be called
 *    from setup() to establish the current best-guess value
 **************************************************************/
 
 void calibrate()
 {
  Serial.println(F("CALIBRATION STARTING. DO NOT TOUCH JOYSTICK"));
  JSleft.calibrate();
  //JSright.calibrate();
  

  Serial.print(F("Calibration complete"));
  Serial.println();
  JSleft.showcalibrate();
  //JSright.showcalibrate();
  Serial.println();
 } // calibrate

 /*******************************************************************
  * setStep
  * 
  * Inputs:
  *     char step: The step interval, one of the commands in the table
  * Result: bool
  *     true if the step mode was set successfully, or is already correct
  *     false if the step mode is not recognized
  ********************************************************************/
  
bool setStep(char step)
  {
   if(step == stepMode)
     return true; // not changed because already set

   // Look up the command in the table
   for(int i = 0; uSteps [i].name != 0 ; i++)
    { /* search step table */
      if(uSteps[i].name == step)
      { /* valid command */
        driver.setStepMode(uSteps[i]. Mode);
        stepMode = step;
        fractionStep = uSteps[i].fraction;
        stepsPerRevolution = 200 * fractionStep;
        minWait = uSteps [i].minWait + offset; 
        minWait = max(minWait,0);
        if(debug)
          { /* debug output */
            Serial.print(F("step size set to '"));
            Serial.print(step);
            Serial.print(F("' 1/"));
            Serial.print(fractionStep);
            Serial.println();
          } /* debug output */
        
        return true;  // successfully changed
       } /* valid command */
     } /* search step table */
  return false;
} // setStep

/****************************************************************************
 * getVariableWait
 * Inputs:
 *         bool & nothing: set to 'true' if nothing to be done
 *         bool & direction: 'true' for 'forward', 'false' for 'backward'
 * Result: int
 *         a variable Wait interval,in microseconds, based on the potentiometer
 *         a negative value indicates a reverse direction
 * Notes:
 *         In potentiometer mode, direction is set by the 'r' command and is ignored
 *         In potentiometer mode, nothing is meaningless and is not set
 *         
 *         'forward' and 'backward' are defined by how the motor is wired in
 *         (phase and phase orientation matter) and therefore cannot be said to
 *         be "clockwise" or "counterclockwise", but simply two directions which
 *         are opposite
 *****************************************************************************/
 
 int getVariableWait(bool & nothing, bool &  direction)
  {
   if (!useJoystick)  
     return map( analogRead(potPin), 0, 1023, minWait, maxWait);

   // For the joystick, read the joystick x,y values
   return JSleft.getXWait(nothing, direction);
 } // getVariableWait
 
/**********************************************************************
 * move
 * inputs:
 *   int motor: the motor number(1 = x, 2 = y,3 =z)
 *   long distance: number of steps to move ( + = cw - = ccw)
 *   int wait: The delay between steps
 *             If < 0, reads the potentiometer or joystick
 *             If > 0, the actual delay time in ms
 *   Notes:
 *       At the moment, since there is only one motor, the motor parameter
 *       is ignored.
 **********************************************************************/

void move(int motor, long distance, int Wait)
{
   driver.setDirection( distance >= 0 ?  true : false);
   // Serial.println(distance);
   for (long i = 0; i < abs(distance); i++) {
      if (Serial.available() )
         return;    // If  user has typed a command, abort the loop

      bool nothing;
      bool direction;
      
      int loopWait = Wait > 0 ? Wait : getVariableWait(nothing, direction);
      
      if( useJoystick)
        { /* joystick motion */
          static int lastloopWait = 0;
          static int lastnothing =-1;
          static int lastdirection = -1;
          
          if (debug && (nothing != lastnothing ||
                        direction != lastdirection ||
                        loopWait != lastloopWait))
              { /* trace */
                Serial.print(F("loopWait = "));
                Serial.print(loopWait);
                lastloopWait = loopWait;
                Serial.print(F(" nothing = "));
                Serial.print(nothing);
                lastnothing = nothing;
                Serial.print(F(" direction = "));
                Serial.print (direction);
                lastdirection = direction;
                
                Serial.println();
              } /* trace */
              
          if (nothing)
             return;
         driver.setDirection( direction ? true : false);
      }  /* joystick motion */
       
      driver.step();
      if (showStep) 
      {
      static int count = 0;  // Keep lines short
      count++;
      if(count % 50 == 0)    // if value modulo is zero, we have printed out enough on this line
        Serial.println(); 
      
        Serial.print(direction ? F(">") : F("<"));
      }
    }
} // move

/******************************************************************
 * setup
 * Initializes the various states required
 * 
 ******************************************************************/
void setup() {
  
  SPI.begin();  // Required for Pololu 36V4 driver board
  
  Serial.begin(115200);
  
  pinMode(DriverSelectPin,OUTPUT);
  delay(1);
  //Serial.print(1);

  driver.setChipSelectPin(DriverSelectPin);
  //Serial.print(2);
  
  driver.resetSettings();
  driver.clearStatus();
  //Serial.print(3);
  
  driver.setCurrentMilliamps36v4(4000);
  //Serial.print(4);

  driver.enableDriver();

  pinMode(vrxAPin,INPUT);
  pinMode(vryAPin,INPUT);
  pinMode(swAPin,INPUT_PULLUP);

 
  Serial.println(F("type m for help"));
} // setup

static const int Wait = 500;
char ticket = 's';
bool changed = false;
bool query = false;
static const long shortRevs = 2;
static const long longRevs = 100;
static const int dt = 10;

/********************************************************************
 * help
 * 
 * Effect:
 *    Prints out the help message to remind us of the commands
 ********************************************************************/
void help()
{
  Serial.println(F(__FILE__)); 
  Serial.println(F(__DATE__ __TIME__));
  Serial.println(F("m  this message"));
  Serial.println("?  current status");
  Serial.print(F("+  add "));
  Serial.print(dt);
  Serial.println(F("us to step wait time"));
  Serial.print(F("-  subtract "));
  Serial.print(dt);
  Serial.println(F("us from step wait time"));
  Serial.println(F("c  calibrate joystick"));
  Serial.println(F("d  toggle debug Mode"));
  Serial.println(F("D  toggle show-step Mode"));
  Serial.println(F("F  clear faults"));
  if(! useJoystick)
    Serial.println ( F("j  set Joystick mode"));
  if(useJoystick)  
    Serial.println ( F("p  set potentiometer mode "));
  if(! useJoystick)
    Serial.println(F("r  reverse direction"));
  Serial.println(F("S  clear status"));
  Serial.print(F("t  set revolutions to "));
  Serial.println(shortRevs);
  Serial.print(F("T  set revolutions to "));
  Serial.println(longRevs);
  for(int i = 0; uSteps [i].name != 0 ; i++)
  {
    Serial.print(uSteps [i].name);
    Serial.print(F("  set 1/"));
    Serial.print(uSteps [i].fraction);
    Serial.println(F(" step")); 
  }
} // help

/********************************************************************
 * showStatus
 * Inputs:
 *    uint8_t status: The status bits from readStatus or readFaults
 * Effect:
 *    displays the bits as symbolic status
 ********************************************************************/

void showStatus(uint8_t status)
{
    if(status != 0)
    {
      /********************************************************************
       * STATUS
       * Inputs:
       *     x: The status flag shift value HPSDStatusBit::x
       *     s: The textual explanation of the bit
       * Effect:
       *     Generates the string 
       *          0xDD NAME explanation 
       *     for the bit in the status flag value 'status' at position x
       *     DD is the status bit in hexadecimal
       *     NAME is the name of the status bit, e.g., "OTS"
       *     explanation is the description of the status bit
       * Notes:
       *     The string provided as the s argument must not use F(); that
       *     is provided in the body of the macro
       *     The \ ***MUST*** be the last character on the line, nothing may
       *     follow it, even a space.
       *********************************************************************/
  
#define STATUS(x, s) if(status & (1 << (uint8_t)(HPSDStatusBit::x))) \
                      {\
                      Serial.print(F("   0x"));\
                      Serial.print(1 << (uint8_t)HPSDStatusBit::x,HEX);\
                      Serial.println(F(" " #x " " s));\
                      }
    STATUS(OTS,"overtemperature shutdown");
    STATUS(AOCP,"channel A overcurrent shutdown");
    STATUS(BOCP,"channel B overcurrent shutdown");
    STATUS(APDF,"channel A predriver fault"); 
    STATUS(BPDF,"channel B predriver fault");
    STATUS(UVLO,"undervoltage lockout");
    
    // Note that for faults, these two bits will always be zero
    STATUS(STD,"stall detected");
    STATUS(STDLAT,"latched stall detected");
         
    }
}

 static  long revs = 100;
/**************************************************************
 * loop
 * 
 * Effect:
 *    The main polling loop.  If there are characters at the serial
 *    port, process them first.
 ***************************************************************/
void loop() 
{
  if(Serial.available())
  {  /* serial pending */  
   char ch = Serial.read();
   if( ch <= ' ')
     return; // ignore spaces and control characters
     
   changed = true;
   query = false;
   
   switch(ch)
   { /* ch */
    case'?':
      query = true;
      break;
      
    case '+':
      offset += dt;
      return;
      
   case '-':
      offset -= dt;
      return;
      
   case 'c':
      calibrate();
      return; 
      
   case 'd':
      debug = !debug;
      Serial.print(F("debug "));
      Serial.println(debug ? F("ON"): F("OFF"));      
      return;

   case 'D':
      showStep = !showStep;
      Serial.print(F("show-step "));
      Serial.println(showStep ? F("ON"): F("OFF"));      
      return;
      
   case 'F':
        {
          driver. clearFaults();
  
          uint8_t faults = driver.readFaults();  // verify that they were cleared and not stuck
          Serial.println(F("Faults cleared"));
          showStatus(faults);
        }
      return;
      
   case 'j':
      useJoystick = true;
      return;
      
   case 'p':
      useJoystick = false; 
      return;  
      
   case 'r':
      if(! useJoystick)
          {
           moveDirection = - moveDirection;
           changed = true;
          }
      return;
      
   case 'S':
      driver.clearStatus();
      Serial.println(F("status cleared"));
      {
        uint8_t status = driver.readStatus();
        showStatus(status);
      }
      return;  
      
   case't':
       revs = shortRevs;
       return;
       
   case'T':
       revs = longRevs;
       return;
       
   case 'm':
       help();
       return;
       
   default:
      // It might be a step request, or complete nonsense
      ticket = ch;
      break;
   } /* ch */
  } /* serial pending */

  if(!query && !setStep(ticket))
    { /* complete nonsense */
      Serial.print(F("unknown command'"));
      Serial.print(ticket);
      Serial.print(F("'"));
      Serial.println();
      return;
    } /* complete nonsense */
  
  if(query || (debug && changed))
  { /* report status */
    Serial.print(query ? F("status '") : F("changed '"));
    Serial.print(stepMode);
    Serial.print(F("' mw="));
    Serial.print(minWait);
    
    Serial.print(F(" vw="));
    bool nothing;
    bool direction;
    Serial.print(getVariableWait(nothing, direction));
    
    Serial.print(F(" direction = "));
    Serial.print(direction);
    
    Serial.print(useJoystick ? F(" Joystick mode") : F(" potentiometer mode"));
    
    uint8_t status = driver.readStatus();
    Serial.print(F(" status = 0x"));
    Serial.print(status,HEX);
    
    uint8_t faults = driver.readFaults();
    Serial.print(F(" faults = 0x"));
    Serial.print(faults,HEX);
    
    Serial.println();
    
    if(status != 0)
       { /* has status */
        Serial.println(F("Status/Faults"));
        showStatus(status);
       } /* has status */
  } /* report status */

  // Clear the changed and query flags
  
  changed = false;
  query = false;
  
  if (useJoystick)
  { /* joystick mode */
      static int lastvrxA = 0;
      static int lastvryA = 0;
      static int lastswA = -1;
      
      int vrxA = JSleft.getX();
      int vryA = JSleft.getY();
      int swA = JSleft.getsw();
      
      if(JSleft.inDriftX(vrxA)&&
         JSleft.inDriftY(vryA))
         return;   // ignore values within the "drift range" of the joystick
     
      
      if (debug && (vrxA != lastvrxA ||
          vryA != lastvryA ||
          swA != lastswA))
          { /* debug trace */
          Serial.print(F("vrxA = "));
          Serial.print(vrxA);
          lastvrxA = vrxA;
                                                                                                                       
          Serial.print (F(" vryA = "));
          Serial.print ( vryA);
          lastvryA = vryA;
          
          Serial.print (F(" swA = "));
          Serial.print (swA);
          lastswA = swA;
          Serial.println(); 
          } /* debug trace */
          
      move(0, 1, moveVariable);
    } /* joystick mode */
  else
    { /* potentiomenter mode */
     move(0,moveDirection * revs * stepsPerRevolution, moveVariable);// will cause it to turn revs.
    } /* potentiomenter mode */
} // loop

The photos are attached. My student took several. The power supply shown is 36V @ 10A. The NEMA-23 motor is rated 24V-48V @ 4.2A/phase. We can see the program uploaded; the ? command tells us that the status flags are 0x00. There are C and F commands to clear status and clear faults. We had to use “m” to get the help because “h” was already allocated to “half-step”.







Yes, we tried the example program (the SPI example) and nothing happened

There is a lot going on in your code, but if the “BasicSteppingSPI” example is not working, I recommend getting that running correctly first. When you ran that example, did you change the CSPin to 5 to match your setup? Could you try running that example again without the motor connected and see if you can measure any voltage at the driver’s motor outputs?

Also, could you try printing the result of “verifySettings()” to the Serial Monitor at the end of the setup() function, and tell us what is returned? For example, add the following code at the end of setup():

Serial.begin(115200);
Serial.println(driver.verifySettings());

Brandon

yes, we changed the select pin in BasicSteppingSPI to pin 5, as I indicated in my message, and it does not work. I would love to get it working, because then I would know that the remaining problems were in my code. But it does not move the stepper. We will try your suggestions at our next session (delayed because of a crisis in my student’s life, may be several days before he gets back to me) and add the code you suggested. Thank you, and the delay is not intentional, just an accident of life.

Yes, this is complex code, and it represents a couple months’ effort to build it all, but it was working perfectly with the 4988 and a NEMA-17. I am having serious upload problems at my side, and I want to get it running with a NEMA-8 using the 36V4.

It took many weeks, but my student has finally recovered (he’s also retired, and has health issues). We put it all together again, and using the latest version of my program, it works, for a while. Then it stops. If we take down the serial monitor and bring up the serial monitor, it resumes, and works for a while, and stops again. It looks like bringing up the serial monitor is resetting the board. I put in some additional printout, and did the verifySettings you requested. The output is as shown below (the 474 and 477 come from a macro.

#define Here() Serial.print(__LINE__)
There is no stall that we can detect, since the motor is just spinning under no load. The chip documentation suggests that we might want to change one of the parameters to the chip, but there is no external interface provided for that.

com14

Closing and reopening the Serial Monitor will restart the Arduino Nano (and other Arduino boards based on the ATmega328). Does your system always run for the same amount of time before stopping each time you reset the Arduino? Could you try running the BasicSteppingSPI example from our library and see if that stops working with your setup after a similar amount of time?

Brandon

We’ll give that a try tonight. It doesn’t run the same amount of time, and there does not seem to be any pointer arithmetic causing a reset (there isn’t any in the program) or having a stack overflow clobber the heap. I’ve tried most tricks I know to isolate either of those cases, and got a negative.

Weird. First it came up with the verifySettings value as 0, but seemed to run. For a while. Using the BasicSteppingSPI code. Then, we changed the step from 1/32 to 1/8, and verifySettings started returning 1 and it ran just fine.

I fixed a bug in our code that might have been causing the failure, and so far it is now working. Had a && and should have had a ||. Bleah! Thanks for your patience. if we have further problems, I’ll get back to you.

1 Like

Well, we were overly optimistic. We found that even the BasicSteppingSPI sketch runs only for a couple minutes and then the motor stops.

I put some tracing into my code, and we found that we are calling sd.step() (for sd the motor object) just fine, while the motor stops moving after a couple of minutes. The trace output I added continues to print out, so I know the function is still being called. So the signals are being sent to the 36V4, but somehow the numbers are not doing anything.

We found out that whole-step requires 8000us delay; half-step works at 6000us; quarter-step at 4000us; eighth step at 3000. We put these values in our table and use them to select the delay during stepping. With smaller values, e.g., 3000us, whole, half, and quarter stepping the motor just sits there and vibrates but does not move. That’s fine, since we have the values in the table and we select the delay time to match the step size. But it still just moves and then goes dead. Whole-step went dead after the first turn; the reverse turn was dead and the motor never moved again. Until we reset the board by restarting the serial monitor.

It you try my code, use “m” to turn on motor debug output. You should get 1> or 1< for each call on step(). We are using the nano. We have not measured the output voltages to the motors.

Sorry, hit ‘send’ before attaching the latest source code.

We are using a NEMA-34 motor and set the current limit to 4000.

36v4 (3).ino (23.9 KB)

The demo code stopping after it runs for approximately 5 minutes is concerning. I am worried it might be overheating; could you try running the demo in full-step mode with the current limit set to 3000mA and see if that gives you different results?

As far as the behavior you observed when you adjusted the delay, it sounds like you are adjusting the delay that determines the step rate. If that is the case, please note that the maximum speed is going to be mainly limited by your particular motor and operating voltage, although other factors in your setup can impact it too, such as the current limit, acceleration/deceleration limiting, decay mode, and what kind of load is connected to your stepper motor. You can find some additional detail in this post by Ben, but ultimately, it does not sound like it is related to your problem.

Brandon

Thanks, we’ll give it a try later tonight.

Yes, we are adjusting the delay between the step rate, If it is too short, the motor does not have time to move to the new position before the next signal comes in, so it sort of oscillates back and forth within a step, more or less. So we introduce some microseconds delay so the motor has time to reach its intended position. We found that with the “classic” NEMA-17 stepper, we had delays like 800us for full-step, and 0 for 1/8 step and below. With 800us on the NEMA-34 motor, it just vibrates at 1/8 step or larger. We tossed in a few numbers which I cited and it at least gives the motor time to settle into position. In reading the status, we get a status code of 0x0C, which if I recall are STD and STDLAT status codes, but the motor continues to run, but eventually stops. We do not see the overtemperature or overcurrent errors. The parameters you mention seem to have no interface specifications. Note that after a startup, verifySettings() returns 0 the first time, 1 once we have changed the step size. I will check the post, but our problem is the unexplained stopping.

Well, we tried it. We set the SteppingSPI example to full steps, set the current limit to 3000mA, and the motor ran for about 30 seconds.

We always get the stall status and the latched stall status bits set. And even when I issue a clearStatus() call, the bits remain on. They are on when the motor is turning, and they are on when the motor stops. As I indicated, I know I am sending step commands to the motor, so the program has not crashed due to some heap damage, stack overflow, or other reason. It just sits there sending step commands out, and nothing happens.

So, having established this, we made the same changes in my program, and again, the motor ran for about 30 seconds and stopped. Only a reset would get it running again. What I have included here is a screen shot of the output to the serial monitor. The ? command will print out the status, and the F command clears the status bits, yet the STD and STDLAT bits are both set even after the clear.

If you have any other suggestions of what we should be looking for, or other diagnostic information that might be useful, we are meeting again Sunday evening and can do further experiments. My student does not have an oscilloscope, but does have a DVM, if that can help. If you have the patience to put up with these questions, we have the patience to try any experiment you want us to try.

The 497 and 500 numbers printed out are from the Here() macro I put in, which prints out __LINE__.

status indicates a status report; 'w' means whole-step mode is set. MinWait is the minimum interstep time. vw is the variable-wait time, which is based on the distance the joystick is from (0,0); close to center is large; fully pushed up or down modifies x timing to vw=0. Since we only have one motor at the moment, we have not bothered calling the y-axis code.
X=490 is the reading of the ADC for x. Joystick fully up is 1023; fully down is 0. The Xdrift is the hysteresis on being centered; we have found that 8 captures the residual error based on the position following a release after full extension in either + or - direction. So it is considered “dead center” if X is anywhere from 482 to 498, with the calibrated 0 at 490.

The

is a status report when the motor stopped. What is odd is that verifySettings() returns 0 even though the motor is moving.

shows what happens if I use the F command to clearStatus(). We tried it twice. My student reported “the motor is quite hot” after we had been playing with it for about 20 minutes. And this was after we had set the current limit to 3000mA (the motor is rated for 4.2A per phase at 12V).

Thank you for your continuing efforts on our behalf.

Hello.

For now, I would like to focus on the library examples since we can be confident that they should work and there aren’t any bugs in the code. As noted on the product page for the High-Power Stepper Motor Driver 36v4, the driver’s SPI interface is more likely to be affected by electrical noise from the driver and stepper motor when using high input voltage and high current limits. Could you try running the BasicSteppingSPI example with the driver powered at a much lower voltage and a lower current limit (e.g. a 12V and the current limit set to 1A, if practical)? Then if that seems to work without issues you could try gradually raising them, and I can suggest some measures that might allow you to use higher voltages and currents more successfully.

By the way, it is not necessarily surprising that the motor still gets hot with 3A, since many electronics and electromechanical components are rated for operation at temperatures well above what would be comfortable to touch (over 100°C).

Brandon