Five phase Vexta stepper driver (1000 steps/rev)

I recently obtained a small laboratory spectrophotometer that had been discarded, and was surprised that the diffraction grating was directly driven by a 5-phase, ten wire Vexta motor. The optics were in perfect shape and useful for other projects, but there is little information on the web about how to drive a five phase stepper, and there are no working examples that I could find with Arduino.

Of course, you can buy a five phase driver from Oriental Motor Company (Vexta manufacturer) for about USD $200, but another option is to use an Arduino Pro Mini, and three much less expensive brushed DC motor drivers from Pololu.

The motor specs: Vexta PX33M-A-C6 0.21A, 33 Ohms per phase, 0.36 degrees/step. Ten wires.

The low current rating and moderate winding resistance means that direct drive from 5 to 6V is possible, avoiding the need for a chopper stepper driver. I decided to use three Pololu DRV8835 dual full bridge modules (only five H-bridges are used, leaving one free for other uses), and with dead simple code it is capable of executing 500 steps/sec from dead stop, without skipping a single step. Half step drive is available, for 2000 steps/revolution, capable of better than 500 steps/second.

See it move 1000 steps in real time.!

Vital information below, used as a guide in creating the working example.

  1. There is confusion on the web about motor coil and wiring color code with lead assignment. I started with this diagram, which supposedly reveals the coil and winding start/finish order:
    10wire_pentagon_connection

But the motor connector had white/yellow and grey/black reversed from the sequence above. The driver works with swapped connections (as long as both pairs of the two connections are reversed) but obeying the connector wire order resulted in the smoothest and presumably correct operation. That is, swap white/yellow and black/gray.

My decision to swap those leads is supported by the alternative assignment of wire colors and winding identifications in the PDF file below. Evidently Oriental Motor is not consistent with wire color codes. 5_Phase_Penta_Connection.pdf (44.9 KB)

  1. Coil excitation sequence, half and full step.

  2. Wiring diagram for two of the phases (micro used was the Pro Mini). The complete pin assignments and subsequent connections are detailed in the code below. Image from Pololu product page: Pololu - DRV8835 Dual Motor Driver Carrier

  1. TOTALLY UNOPTIMIZED but fully functional code. Note that the drive tables are cyclic permutations of each other, so only one is required (ten bytes of storage in the optimized version).
// five phase drive for Vexta PX33M-A-C6 0.21A, 33R per phase, 0.36 degrees/step
// S. J. Remington 10/2020

// Totally unoptimized code!

// 3x Pololu DRV8835 dual motor driver
// **IN/IN mode selected**
// Truth Table
// IN1 IN2 OUT1 OUT2 
// 0   0   open open
// 1   0   H    L
// 0   1   L    H

// Vexta PK PX, wire colors in order around the motor​
//A - blue > red
//B - white > yellow   (reversed on motor connector, polarity switched)
//C - brown > purple
//D - black > gray     (reversed on motor connector, polarity switched)
//E - orange > green
// smoother action with white/yellow and black/gray both reversed

// drive sequences from 10_wire_sequence.png
// NOTE that these tables are cyclic permutations of each other, so only one is actually required.
// This is the dead simple, brute force version. Optimized version to be posted later
/*
  // half step
  //             1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
  int AB[20] = { 1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 1, 1, 1, 1, 1, 1, 1};
  int CD[20] = {-1,-1,-1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,-1,-1,-1,-1,-1,-1};
  int EF[20] = { 1, 1, 1, 1, 1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 1, 1, 1};
  int GH[20] = {-1,-1,-1,-1,-1,-1,-1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,-1,-1};
  int JK[20] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0};
*/
// full step (1000 steps/revolution)
int AB[10] = {  0, -1, -1, -1, -1, 0, 1, 1, 1, 1};
int CD[10] = { -1, 0, 1, 1, 1, 1, 0, -1, -1, -1};
int EF[10] = {  1, 1, 0, -1, -1, -1, -1, 0, 1, 1};
int GH[10] = { -1, -1, -1, 0, 1, 1, 1, 1, 0, -1};
int JK[10] = {  1, 1, 1, 1, 0, -1, -1, -1, -1, 0};
//

int index = 0;
int index_max = 10;

void setup() {

  //pin driver -> motor assignments
  pinMode(2, OUTPUT); //A blue, I1, O1 MD1A
  pinMode(3, OUTPUT); //A red, I2, O2, MD1A
  pinMode(4, OUTPUT); //B yellow, I1, O1, MD1B
  pinMode(5, OUTPUT); //B white, I2, O2, MD1B
  pinMode(6, OUTPUT); //C brown, I1, O1, MD2A
  pinMode(7, OUTPUT); //C purple, I2, O2, MD2A
  pinMode(8, OUTPUT); //D gray, I1, O1, MD2B
  pinMode(9, OUTPUT); //D black, I2, O2, MD2B
  pinMode(11, OUTPUT); //E orange, I1, O1, MD3A
  pinMode(12, OUTPUT); //E green, I2, O2, MD3A

}

void loop() {  //execute 1000 steps at full speed, from dead stop
  for (int i = 0; i < 1000; i++) {
    if (AB[index] > 0) {
      digitalWrite(2, 1);
      digitalWrite(3, 0);
    }
    if (AB[index] == 0) {
      digitalWrite(2, 0);
      digitalWrite(3, 0);
    }
    if (AB[index] < 0) {
      digitalWrite(2, 0);
      digitalWrite(3, 1);
    }

    if (CD[index] > 0)  {
      digitalWrite(4, 1);
      digitalWrite(5, 0);
    }
    if (CD[index] == 0) {
      digitalWrite(4, 0);
      digitalWrite(5, 0);
    }
    if (CD[index] < 0)  {
      digitalWrite(4, 0);
      digitalWrite(5, 1);
    }

    if (EF[index] > 0)  {
      digitalWrite(6, 1);
      digitalWrite(7, 0);
    }
    if (EF[index] == 0) {
      digitalWrite(6, 0);
      digitalWrite(7, 0);
    }
    if (EF[index] < 0)  {
      digitalWrite(6, 0);
      digitalWrite(7, 1);
    }

    if (GH[index] > 0)  {
      digitalWrite(8, 1);
      digitalWrite(9, 0);
    }
    if (GH[index] == 0) {
      digitalWrite(8, 0);
      digitalWrite(9, 0);
    }
    if (GH[index] < 0)  {
      digitalWrite(8, 0);
      digitalWrite(9, 1);
    }

    if (JK[index] > 0)  {
      digitalWrite(11, 1);
      digitalWrite(12, 0);
    }
    if (JK[index] == 0) {
      digitalWrite(11, 0);
      digitalWrite(12, 0);
    }
    if (JK[index] < 0)  {
      digitalWrite(11, 0);
      digitalWrite(12, 1);
    }
    delay(2); //500 steps/second OK
// decrement index to drive in the reverse direction
    index++;  
    if (index == index_max) index = 0;
    if (index < 0) index = index_max;
  }
  delay(500);
}

I’ll post optimized code when I figure out the best way to proceed.

For the pentagon wiring option, five half bridge drivers are used. Improved step sequences for the pentagon connection are shown in the PDF file below from Oriental Motor.

vexta_pentagon_phase_sequence.pdf (59.2 KB)

3 Likes

This is the storage-optimized version.

//indexing tables optimized, half step mode selected
// five phase drive for Vexta PX33M-A-C6 0.21A, 33R per phase, 0.36 degrees/step
// S. J. Remington 10/2020

// 3x Pololu DRV8835 dual motor driver
// **IN/IN mode selected**
// Truth Table
// IN1 IN2 OUT1 OUT2
// 0   0   open open
// 1   0   H    L
// 0   1   L    H

// Vexta PK PX, wire colors -> APPARENT phase and coil polarity assignments
//A - blue > red        (start > finish)
//B - yellow > white
//C - brown > purple
//D - gray > black
//E - orange > green

// drive sequences from 10_wire_sequence.png
// half step (2000 steps/rev). Set index_max=20, skip=8
//                     1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
  int coil_drive[20] = { 1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 1, 1, 1, 1, 1, 1, 1};
  int index_max = 20;
  int skip = 8;

/*
// full step (1000 steps/revolution), set index_max=10, skip=4
int coil_drive[10] = {  0, -1, -1, -1, -1, 0, 1, 1, 1, 1};
int index_max = 10;
int skip = 4;
*/

//
// pin assignment table: coil, {start,finish}
//                       A       B       C       D       E
int pin_table [5][2] = {{2, 3}, {4, 5}, {6, 7}, {8, 9}, {11, 12}};
int index = 0;

void setup() {
  int i;
  for (i = 0; i < 10; i++) pinMode(pin_table[i], OUTPUT);  //motor control pins
}

void loop() {

  int k, permuted_indices[5];

  //execute 2000 steps at full speed, from dead stop
  for (int i = 0; i < 2000; i++) {
    permuted_indices[0] = index;
    permuted_indices[1] = (permuted_indices[0] + skip) % index_max;
    permuted_indices[2] = (permuted_indices[1] + skip) % index_max;
    permuted_indices[3] = (permuted_indices[2] + skip) % index_max;
    permuted_indices[4] = (permuted_indices[3] + skip) % index_max;
    for (int j = 0; j < 5; j++) { //loop over coils
      k = permuted_indices[j];
      if (coil_drive[k] > 0) {
        digitalWrite(pin_table[j][0], 1); // plus
        digitalWrite(pin_table[j][1], 0);
      }
      if (coil_drive[k] == 0) {
        digitalWrite(pin_table[j][0], 0); // off
        digitalWrite(pin_table[j][1], 0);
      }
      if (coil_drive[k] < 0) {
        digitalWrite(pin_table[j][0], 0); // minus
        digitalWrite(pin_table[j][1], 1);
      }
    } // end for j
    delay(2); //500 steps/second OK
    index++;  //forward
//    index--;  //reverse
    if (index >= index_max) index = 0;
    if (index < 0 )index = index_max - 1;
  }
  delay(500); //pause after one revolution for skipped step test.
}
1 Like

Hi, Jim.

Thanks for sharing your experience and code for controlling your 5 phase stepper motor! I don’t think I have come across any tutorials or code for a 5 phase motor either, so I’m sure this will be helpful for others. Do you have any specific plans for the motor?

-Claire

Hi, Claire:

In addition to the interesting challenge, I plan to use the motor as intended, to drive the diffraction grating for an art piece that involves constantly changing spectral illumination.

I like the wash and variation of “pure” colors better than RGB LED effects, which can’t seem to realistically simulate rainbow effects.

The original motor driver was part of a rather large PCB and could not be salvaged. It used 3 x PBL3771 stepper drive chips.

Cheers, Jim

1 Like

Here is a photo of the final driver on a protoboard. It has been working very reliably!

1 Like

Thanks for sharing the photo. We would love to see pictures or video of the final project too when it is ready!

-Claire