Stepper Motor Test Controller

I am trying a project that will use motors to drive the movements of an animatronic instead of my normal pneumatics that I have been using for the last 17 years.  But I wanted to build up some test joints to prove out the joints and motors before I finalized a design.  To do this I decided I needed a small device to drive stepper motors for the test arms.  So was born the Stepper Motor Test controller.  Lets get building.

 

   
Circuit board fresh from the manufacturing.  Time to start adding parts starting with the shortest and working to the tallest ones. As this is just a one off build, it was not worth having solder paste stencils made.  so for this one i am just putting small dabs of solder paste on the smd pads.  once the parts are placed I can use a fine tiped soldering iron or my hot air reflow gun to melt the solder and affix the parts
Using tweezers and a magnifying lamp I have places all the smd parts.  time to heat things up post heating.  note the solder paste is all melted and flux is around most of the parts.  now is a good time to do a little cleaning, as once the taller parts are in place it will be much harder to clean up the extra flux from the paste.
With the smd soldered I moved to the thru hole parts going headers then terminal blocks with the tall caps last.  Now I like to do some testing to make sure everything is all good.  I start by applying power and checking voltages at various points.

Now with some initial testing done, it is time to inset the pre-made modules. Here I am using the Pololu High Current DRV8825 carrier (other pin compatible versions will also work depending on your motor choice) and the Sparkfun ESP32 Thing.  The ESP32 is dev board based on the Espressif’s ESP32 and includes WiFi, Bluetooth and a 32bit microprocessor among other things. 

More importantly I am using the ESP32 Thing as I start learning the Arduino IDE.  There is a ESP32 Arduino Core that can be added to the IDE and one can then program the Thing just like any other Arduino device.  Though most Arduino’s are based on an 8 bit AVR micro so the thing has a bit more horse power and integrated WiFi.

 
After a little programing everything is working.  Now I can get on with figuring out and building a test arm with stepper motors to see how that works instead of pneumatics that I have been using for the last fifteen years to drive animatronics.  
Below is the code I have put together for the Thing, it is largely based on the sample for an encoder and is far from effecient but this device just does not need to do a lot at this point.  Later I will likely test position feedback so the controller will become more important.  But just to drive the stepper drivers I could have just used a switch for direction and linked the A side of the encoder to the step pin of the stepper driver to create a pulse.  

#define ENC1_A 25
#define ENC1_B 26
#define ENC2_A 27
#define ENC2_B 14
#define ENC3_A 12
#define ENC3_B 13

#define motor1_dir 2
#define motor1_step 15
#define motor2_dir 4
#define motor2_step 0
#define motor3_dir 16
#define motor3_step 17

//#define GPIO_INPUT_GET(gpio_no) ((gpio_no < 32)? ((gpio_input_get()>>gpio_no)&BIT0) : ((gpio_input_get_high()>>(gpio_no – 32))&BIT0))

#include <rom/gpio.h>

void setup()
{
/* Setup encoder pins as inputs */
pinMode(ENC1_A, INPUT); // OR INPUT_PULLUP
digitalWrite(ENC1_A, HIGH);
pinMode(ENC1_B, INPUT);
digitalWrite(ENC1_B, HIGH);
pinMode(ENC2_A, INPUT); // OR INPUT_PULLUP
digitalWrite(ENC2_A, HIGH);
pinMode(ENC2_B, INPUT);
digitalWrite(ENC2_B, HIGH);
pinMode(ENC3_A, INPUT); // OR INPUT_PULLUP
digitalWrite(ENC3_A, HIGH);
pinMode(ENC3_B, INPUT);
digitalWrite(ENC3_B, HIGH);

/* Setup stepper driver pins as outputs */
pinMode(motor1_dir, OUTPUT);
digitalWrite(motor1_dir, LOW);
pinMode(motor1_step, OUTPUT);
digitalWrite(motor1_step, LOW);
pinMode(motor2_dir, OUTPUT);
digitalWrite(motor2_dir, LOW);
pinMode(motor2_step, OUTPUT);
digitalWrite(motor2_step, LOW);
pinMode(motor3_dir, OUTPUT);
digitalWrite(motor3_dir, LOW);
pinMode(motor3_step, OUTPUT);
digitalWrite(motor3_step, LOW);

Serial.begin (115200);
Serial.println(“Start”);
}

void loop()
{
static uint8_t counter1 = 0; //this variable will be changed by encoder input
int8_t tmpdata1;
tmpdata1 = read_encoder1();
if( tmpdata1 ) {
Serial.print(“Counter1 value: “);
Serial.println(counter1, DEC);
if( tmpdata1 > 0 ) { digitalWrite(motor1_dir, HIGH);} else {digitalWrite(motor1_dir, LOW);}
digitalWrite(motor1_step, HIGH);
counter1 += tmpdata1;
}

static uint8_t counter2 = 0; //this variable will be changed by encoder input
int8_t tmpdata2;
tmpdata2 = read_encoder2();
if( tmpdata2 ) {
Serial.print(“Counter2 value: “);
Serial.println(counter2, DEC);
if(tmpdata2 > 0 ) { digitalWrite(motor2_dir, HIGH);} else {digitalWrite(motor2_dir, LOW);}
digitalWrite(motor2_step, HIGH);
counter2 += tmpdata2;
}

static uint8_t counter3 = 0; //this variable will be changed by encoder input
int8_t tmpdata3;
tmpdata3 = read_encoder3();
if( tmpdata3 ) {
Serial.print(“Counter3 value: “);
Serial.println(counter3, DEC);
if(tmpdata3 > 0 ) { digitalWrite(motor3_dir, HIGH);} else {digitalWrite(motor3_dir, LOW);}
digitalWrite(motor3_step, HIGH);
counter3 += tmpdata3;
}

delayMicroseconds(4);
digitalWrite(motor1_step, LOW);
digitalWrite(motor2_step, LOW);
digitalWrite(motor3_step, LOW);
delayMicroseconds(6);
}

/* returns change in encoder state (-1,0,1) */
int8_t read_encoder1()
{
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t old_AB1 = 0;
static uint32_t curval1 = 0;
/**/
old_AB1 <<= 2;
curval1 = gpio_input_get();
old_AB1 |= ( ( (curval1 & 1<< ENC1_A ) >> ENC1_A | (curval1 & 1<< ENC1_B ) >> (ENC1_B – 1) ) & 0x03 );
return ( enc_states[( old_AB1 & 0x0f )]);

}

int8_t read_encoder2()
{
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t old_AB2 = 0;
static uint32_t curval2 = 0;
old_AB2 <<= 2;
curval2 = gpio_input_get();
old_AB2 |= ( ( (curval2 & 1<< ENC2_A ) >> ENC2_A | (curval2 & 1<< ENC2_B ) >> (ENC2_B – 1) ) & 0x03 );
return ( enc_states[( old_AB2 & 0x0f )]);
}

int8_t read_encoder3()
{
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t old_AB3 = 0;
static uint32_t curval3 = 0;
old_AB3 <<= 2;
curval3 = gpio_input_get();
old_AB3 |= ( ( (curval3 & 1<< ENC3_A ) >> ENC3_A | (curval3 & 1<< ENC3_B ) >> (ENC3_B – 1) ) & 0x03 );
return ( enc_states[( old_AB3 & 0x0f )]);
}