Dual MC33926 Arduino Shield and 1209 Stepper Motor

Hello,

Below is a sample code to run a stepper motor with the MC33926 Motor Driver Shield (pololu.com/catalog/product/2503). Additionally this code shows how you can adjust the size of the step between full step, half step and quarter step. See the comments in the code for more detail.

#include "DualMC33926MotorShield.h"

DualMC33926MotorShield md;


#define QUARTER_STEP	1
#define HALF_STEP		2
#define FULL_STEP		4

unsigned char stepMode = FULL_STEP;


// Advances the stepper motor by one step either clockwise or counterclockwise
// with the direction specified by the argument dir (0 or 1).  The size of the
// step depends on stepMode and can either be a full step, a half step, or a
// quarter step.  Full stepping is produced by repeating a four-state cycle
// in which both coils are always energized to carry the same magnitude of current
// but the direction of the current is sequentially switched.  Running through the
// four-state cycle in the reverse order reverses the direction of rotation.  The
// general equation for coil current should be as follows:
// coil 1 current = I * sin(a)
// coil 2 current = I * cos(a)
// When full stepping, the four states are: 
// forwards: a = 0, 90, 180, 270 degrees
// reverse:  a = 0, 270, 180, 90 degrees
// half stepping comes from: a = 0, 45, 90, 135, 180, 225, 270, 315 degrees
// quarter stepping comes from a = the 16 multiples of 22.5 from 22.5 to 360 deg
void one_step(unsigned char dir)
{
	// this static variable lets us remember what step we're on so we
	// can change to the appropriate next state in the sequence
	static unsigned char step = 0;

	// compute the next step based on the direction argument dir
	// and the step mode.  Full stepping skips half and quarter steps,
	// and half stepping skips quarter steps.  Quarter stepping cycles
	// through all 16 steps.
	if (dir == 1)
		step += stepMode;
	else
		step -= stepMode;

	switch (step & 15)
	{
		case 0:	// full step (both coils energized at 71%)
			md.setSpeeds(180, 180);
			break;
		case 1:	// quarter step (coil 1 at 38% and coil 2 at 92%)
			md.setSpeeds(98, 236);
			break;
		case 2: // half step (coil 1 at 0% and coil 2 at 100%)
			md.setSpeeds(0, 255);
			break;
		case 3: // quarter step
			md.setSpeeds(-98, 236);
			break;
		case 4: // full step
			md.setSpeeds(-180, 180);
			break;
		case 5: // quarter step
			md.setSpeeds(-236, 98);
			break;
		case 6: // half step
			md.setSpeeds(-255, 0);
			break;
		case 7: // quarter step
			md.setSpeeds(-236, -98);
			break;
		case 8: // full step
			md.setSpeeds(-180, -180);
			break;
		case 9: // quarter step
			md.setSpeeds(-98, -236);
			break;
		case 10: // half step
			md.setSpeeds(0, -255);
			break;
		case 11: // quarter step
			md.setSpeeds(98, -236);
			break;
		case 12: // full step
			md.setSpeeds(180, -180);
			break;
		case 13: // quarter step
			md.setSpeeds(236, -98);
			break;
		case 14: // half step
			md.setSpeeds(255, 0);
			break;
		case 15: // quarter step
			md.setSpeeds(236, 98);
			break;
	}
}


// This is a blocking function that repeatedly takes a single step and then
// delays for step_delay_us microseconds.  When it finishes, the stepper motor
// coils will continued to be energized according to the final step so that
// the stepper motor maintains its position and holding torque. 
void multistep(int steps, unsigned int step_delay_us)
{
	unsigned char dir = 1;
	if (steps < 0)
	{
		dir = 0;
		steps = -steps;
	}

	while (steps--)
	{
		one_step(dir);
		delayMicroseconds(step_delay_us);
	}
}

void setup()
{
	md.init();
}


void loop()
{
	if (stepMode == FULL_STEP)
		stepMode = HALF_STEP;
	else
		stepMode = FULL_STEP;
	multistep(400, 5000);
	delayMicroseconds(500);
	unsigned char i;
	for (i = 0; i < 4; i++)
	{
		multistep(-100, 2000);
		delayMicroseconds(100);
	}
}

This code was adapted from the stepper-motor1 example for the Orangutan, which can be found at this link: github.com/pololu/libpololu-avr … or1/test.c

- Takuya Jeremy

1 Like

Thank you all for the help - this is exactly what I was looking for! I’ll try to get this working tomorrow - I forgot my shield at the office - and let you know if I’ve had success.

jwatte: I tried your solution first as a basic sketch. Thanks for the help: this works great for me:

#include "DualMC33926MotorShield.h"

DualMC33926MotorShield md;
const int delay_time = 50;
int forward[4][2] = {{200, 0}, {0, 200}, {-200, 0}, {0, -200}};
int reverse[4][2] = {{0, 200}, {200, 0}, {0, -200}, {-200, 0}};
void stopIfFault()
{
  if (md.getFault())
  {
    Serial.println("fault");
    while(1);
  }
}

void setup()
{
  Serial.begin(115200);
  Serial.println("Dual MC33926 Motor Shield: Stepper");
  md.init();
}

void loop()
{
  step_motor(reverse);
}
void step_motor(int dir[4][2]){
  int i = 0;
  for (i = 0; i < 4; i++){
    md.setM1Speed(dir[i][0]);
    md.setM2Speed(dir[i][1]);
    delay(delay_time);
  }
  return;
}

Takuya, thanks for taking the time to share that. I’ll give it a try this evening.

Hello.

Please note that the example code Jeremy (Takuya) posted above has one mistake and one caveat regarding usage that should be mentioned. First, it seems to be treating the maximum motor speed as 255, but the DualMC33926MotorShield library he is using has a maximum motor speed of 400, so all the motor speed values should be scaled up accordingly. This brings me to the caveat:

In its current form, there’s no provision for limiting the maximum coil voltage, which could damage stepper motors with rated voltages below the driver voltage. A better version of this program would have a constant defined at the beginning (or an extra function argument) that sets the maximum speed, and oneStep() would use appropriately scaled speeds based on this maximum.

- Ben

I took Ben’s feedback and improved the code. Please look at the comments in the code carefully. You will have to set the percentOutput value to meet the specifications of your motor.

#include "DualMC33926MotorShield.h"
DualMC33926MotorShield md;

// If you want to use the VNH5019 Dual Motor Shield instead, comment out the two lines
// above and uncomment the two lines below. 
// #include "DualVNH5019MotorShield.h"
// DualVNH5019MotorShield md;

// The constant below will scale the peak output voltage to the motor by the percentage 
// declared.  For example, if you want the peak voltage to the motor to be equal to VIN,
// set percentOutput to 100.  If you want the peak voltage to the motor to be 80% of VIN, 
// set percentOutput to 80.  You should see what voltage the stepper motor is rated for 
// and set percentOutput appropriately.  The value of percentOutput should be between 0 
// and 100. 
const byte percentOutput = 50; 

#define QUARTER_STEP   1
#define HALF_STEP      2
#define FULL_STEP      4
unsigned char stepMode = FULL_STEP;

// This function will set the voltage applied to each coil. 
inline void set_speeds(int m1speed, int m2speed)
{
	md.setSpeeds(m1speed/2*percentOutput/50, m2speed/2*percentOutput/50);
}

// Advances the stepper motor by one step either clockwise or counterclockwise
// with the direction specified by the argument dir (0 or 1).  The size of the
// step depends on stepMode and can either be a full step, a half step, or a
// quarter step.  Full stepping is produced by repeating a four-state cycle
// in which both coils are always energized to carry the same magnitude of current
// but the direction of the current is sequentially switched.  Running through the
// four-state cycle in the reverse order reverses the direction of rotation.  The
// general equation for coil current should be as follows:
// coil 1 current = I * sin(a)
// coil 2 current = I * cos(a)
// When full stepping, the four states are: 
// forwards: a = 0, 90, 180, 270 degrees
// reverse:  a = 0, 270, 180, 90 degrees
// half stepping comes from: a = 0, 45, 90, 135, 180, 225, 270, 315 degrees
// quarter stepping comes from a = the 16 multiples of 22.5 from 22.5 to 360 deg
void one_step(unsigned char dir)
{
   // this static variable lets us remember what step we're on so we
   // can change to the appropriate next state in the sequence
   static unsigned char step = 0;

   // compute the next step based on the direction argument dir
   // and the step mode.  Full stepping skips half and quarter steps,
   // and half stepping skips quarter steps.  Quarter stepping cycles
   // through all 16 steps.
   if (dir == 1)
      step += stepMode;
   else
      step -= stepMode;

   switch (step & 15)
   {
      case 0:   // full step (both coils energized at 71%)
         set_speeds(283, 283);
         break;
      case 1:   // quarter step (coil 1 at 38% and coil 2 at 93%)
         set_speeds(153, 370);
         break;
      case 2: // half step (coil 1 at 0% and coil 2 at 100%)
         set_speeds(0, 400);
         break;
      case 3: // quarter step
         set_speeds(-153, 370);
         break;
      case 4: // full step
         set_speeds(-283, 283);
         break;
      case 5: // quarter step
         set_speeds(-370, 153);
         break;
      case 6: // half step
         set_speeds(-400, 0);
         break;
      case 7: // quarter step
         set_speeds(-370, -153);
         break;
      case 8: // full step
         set_speeds(-283, -283);
         break;
      case 9: // quarter step
         set_speeds(-153, -370);
         break;
      case 10: // half step
         set_speeds(0, -400);
         break;
      case 11: // quarter step
         set_speeds(153, -370);
         break;
      case 12: // full step
         set_speeds(283, -283);
         break;
      case 13: // quarter step
         set_speeds(370, -153);
         break;
      case 14: // half step
         set_speeds(400, 0);
         break;
      case 15: // quarter step
         set_speeds(370, 153);
         break;
   }
}

// This is a blocking function that repeatedly takes a single step and then
// delays for step_delay_us microseconds.  When it finishes, the stepper motor
// coils will continued to be energized according to the final step so that
// the stepper motor maintains its position and holding torque.
void multi_step(int steps, unsigned int step_delay_us)
{
   unsigned char dir = 1;
   if (steps < 0)
   {
      dir = 0;
      steps = -steps;
   }

   while (steps--)
   {
      one_step(dir);
      delayMicroseconds(step_delay_us);
   }
}

void setup()
{
   md.init();
}

void loop()
{
   if (stepMode == FULL_STEP)
      stepMode = QUARTER_STEP;
   else
      stepMode = FULL_STEP;
   multi_step(400, 5000);
   delayMicroseconds(500);
   for (byte i = 0; i < 4; i++)
   {
      multi_step(-100, 2000);
      delayMicroseconds(100);
   }
}

-Jeremy

1 Like

I’ve been tinkering with this code and the mc33926 shield for a few days now. I can run this stepper motor with no problem when it is connected half-winding, but I want to use all 4 coils by connecting them in series configuration. Like this:
When I try to run the motor I get the same result after everything I do. The motion has no strength and is not consistently going in one direction. I was wondering if you think this might be because the set_speeds values are conflicting and cancelling out one another in this wire configuration. How do you figure out these values for this setup?

Hello.

You should be able to configure your 8-wire stepper motor to a 4-wire configuration like in the picture. Do you have the correct wires tied together? If the coils are not connected correctly, it might lead to unexpected behavior. Could you tell us more about your stepper motor? Could you provide a link to its datasheet? What are you using to power the motor and driver? Could you post pictures of your setup?

- Jeremy

Your comment that it should work makes me realize that my problem is the stepper motor. One of the sets of coils isn’t insulated. Essentially connecting inside the motor. What do you think about that?
I can’t take pictures at this time. I have a motor I believe is specially made for a printer so no data sheet can be found.I wanted to repurpose it for my project instead of buying a new one. (sanyo denki 103h7125-0641) Power supply is Mean Well SP 240-24

I am not sure I understand what you mean by the coils are not insulated, and that they are connected inside the motor. If you get a chance to post pictures, hopefully they will clarify the situation.

- Jeremy

I bought a new motor and that fixed my old issue. Now my project is almost finished. The thing holding me back is the step_delay_us setting. How do you come up with the values for this. I tried a few calculations and I tried to make a chart of them. I can’t see the pattern.

Hello.

I am not entirely sure I understand what it is you are asking; can you clarify? As you can see inside Jeremy’s code, step_delay_us is a parameter of multi_step() that determines the step rate used during the multi-step. The program sets step_delay_us to 5000 and 2000 inside loop().

-Jon

If I want to take 4 seconds to make one turn that’s 50 delays per rotation. So I set the value to 80000 because that’s 4000000/50. That worked, but I wanted it to go even slower. So I tried 6000000/50 to get a delay of 1200000 but the speed increased. After that I added another delay to to get the right speed. Why did the speed increase?

Incredibly, my new 425 oz motor wasn’t strong enough. I plan to step up the power with this motor. automationtechnologiesinc.co … 30-4BM.pdf It seems to be right on the cusp of the shields capability. Do you recommend anything?

That behavior makes it seem like an integer overflow, where the value your code tries to store into the unsigned int is larger than the maximum value it can store. To overcome this, you might consider making delays in larger increments of time. For example, you could change

delayMicroseconds(step_delay_us);

to

delay(step_delay_us);

which would make the delay 1000 times greater - in milliseconds instead of microseconds.

And you could probably rename step_delay_us to step_delay_ms to be more accurate.

As for the stepper motor you linked to, it looks like it draws 3A per coil, which is pushing the limits of what the MC33926 can handle continuously.

-Jon

I tried to run the motor with the mc33926 shield. It worked during testing. When I went to put it all together I made some mistakes. I was soldering with the arduino plugged in and I ruined it. I also cut a wire and it sparked. I got a new arduino and I want to get a new mc33926.

My questions are will the shield handle 3 amps continuously like it says?
Will heatsinks and a fan allow it to handle the current better?
Does current increase if the torque is being resisted?

On another note, I want to thank Pololu for this forum. It has answered other questions I’ve had and I’m happy to be a part of it.

In our tests with the driver at ambient temperatures with no additional cooling it was able to handle 3A continuously. However, the exact amount of current you will be able to pull might depend on your setup. Adding a heat sink and providing external cooling can help the motor driver handle more current safely.

Yes, a brushed DC motor will draw more current when a larger load is place on it like that.

-Jon

Hi,

is it possible to use the Dual MC33926 Motor Driver Carrier with an arduino to drive a stepper motor? If so, what changes in the code and how to wire it?

Thanks a lot

Hello.

It is possible to use the Dual MC33926 Motor Driver Carrier with an Arduino controller to drive a stepper motor; however, the code Jeremy posted above will not work directly since it is intended for the Dual MC33926 Motor Driver Shield for Arduino, which has additional circuitry to control it with DIR/PWM signals. You can see the extra components used by comparing the schematic diagrams on each board’s product page. One solution might be to add that circuity to your setup so it functions like the shield.

Alternatively, you could modify the code to use the appropriate control signals. This would involve changing the way the setSpeeds() command works in the library or changing the setSpeeds() commands in each case of the switch statement to the equivalent commands for the Dual MC33926 Motor Driver Carrier.

Brandon

1 Like

Above is the code I used. It is Jermey’s code with void loop() altered. I just want to turn a stepper motor (nema 23) one way, pause for a little, then turn it back to its original position (turn the other way). It works if I take out the delay between the multi_step functions. However with the delay it turns then delays then the next turn is in the same direction. How can I get this to turn one way, delay, then turn the other way (opposite direction)?

Also, no matter how long I try to delay it for, after a certain number about 1000 (delay(1000):wink: it wont delay any longer.
Thank you for any help I really need it.

Hello, jsolarek.

Can you provide more details about your setup (e.g. Arduino board, motor shield, power supplies, stepper motor electrical specification, and connections) and post close-up pictures clearly showing how you have everything connected? Does your driver get hot? If you reduce the delay argument in your multi_step commands (e.g. 1000 instead of 5000), does it work with the delay(1000)?

- Amanda