Output Devices

Controlling a Stepper Motor

Group Assignment Page

This week’s group assignment covers the usage of benchtop power supply, multimeter, oscilloscope and logic analyzer. We learned how to use these tools for debugging purposes.

Trials on a Breadboard

Wiring

This week, I decided to try to set up a stepper motor with the Xiao and make a circuit board. I had never worked with a stepper motor before, so I wanted to try everything on a breadboard first. To do this, I followed this tutorial.

The components I was using were as follows:

I followed the tutorial for the wiring. The TMC2208 used in the video and the one we had available at FabLab were different. This page has the written explanations of the abbreviations on the chip. I used this to figure out which output was which.

wiring scheme wiring on breadboard

At first, I wanted to power the stepper with the 5V output from the Xiao, but I realized that this was not viable and I needed an external power source. I used an 12V adapter for this. When setting it up, we need to be very careful with the colors of the wires connecting to the AC supply.

The attaching of the wires using the screws should be done BEFORE you plug the adapter in. After this, you can plug the adapter, and measure the voltage with a multimeter. Pay attention that the V+ and V- line up with the multimeter reading.

color codes of wires

wiring 12v adapter checking 12v adapter with multimeter

The circuit draws power from two different sources. The Xiao board draws power from the USB connection of the computer. The TMC2208 is connected to the 3.3V output of the Xiao. The stepper draws power from the 12V adapter. Keep in mind that the grounds for the 3.3V and 12V power sources are different, as shown in the drawing above.

Figuring out the connections of the servo motor was also a challenge for me. It has two sets of wires connected to each other in pairs. It was a challenge to figure out how exactly I was supposed to connect them to the driver. With some help from Yuhan and the stepper’s data sheet, this is how I connected them at the end:

connecting stepper's wires

Setting Motor Current

The TMC2208 driver has a built-in feature that allows us to adjust the reference voltage according to the current limit of the motor. It is outlined here in this tutorial.

Firstly, we check the max current of the stepper motor. According to the datasheet it is 400mA (0.4 A). to calcuate the reference voltage needed, we can use the calculator in the tutorial or the calculator here. They give roughly the same result. From the calculation we learn that the reference voltage should be 0.61V.

Before we start measuring the reference voltage, we have to disconnect the motor since it can easily get harmed during the process. Then we connect the USB power source and 12V adapter power source. According to the tutorial, we should put one end of the multimeter to the motor ground on the chip, and one end in the Vref pin.

wiring setup how to measure ref voltage

When I tried this, I could not get a reading on the multimeter. With Yuhan’s advice, I tried putting the (+) end of the multimeter to the potentiometer on the chip instead. This should give us the same reference voltage reading.

how to measure ref voltage not working how to measure ref voltage working

Our aim is to make this reading 0.61V, since this was the result of our calculation. With small screwdriver, or tweezer’s end, we turn the potentiometer and measure again until we get 0.61V.

adjusting potentiometer

Testing the Code

After I adjusted the reference voltage, I plugged the motor back in and started to work on the code to make the stepper turn.

wiring setup

This is the first code I wrote following the tutorial. It did nothing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int stepPin = D4;
int dirPin = D5;


void setup() {
  pinMode(D4,OUTPUT);
  pinMode(D5,OUTPUT);

}

void loop() {
  digitalWrite(dirPin,HIGH);

  for(int x=0; x<200; x++){
    digitalWrite(stepPin,HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin,LOW);
    delayMicroseconds(500);    
  } 

  delay (1000);

  digitalWrite(dirPin,LOW);

  for(int x=0; x<400; x++){
    digitalWrite(stepPin,HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin,LOW);
    delayMicroseconds(500);    
  } 

  delay (1000);
}

I tried adding serial.println into the for loops for debugging. So it could print turning right and turning left if the for loops were being executed. It printed correctly, so the code was being executed. But the motor still did not turn.

I tried downloading libraries from Arduino IDE, specifically “TMC2208Stepper” and “TMCStepper”. I tried using examples from both libraries. They still did not work.

I tried looking up guides from Yuhan’s documentation on stepper motors, which led me to this video. I replicated the code from the video, as well as adding an ENABLE_PIN and connecting it to the EN pin on the TMC2208. It still did not work.

With Yuhan’s help the next day, I managed to get the stepper to work. The two changes that solved it were:

  1. Connecting the grounds between Motor Power Supply (12V) and Logic Power Supply (3.3V)
  2. Setting up an “ENABLE_PIN”, connecting it between the “En” pin in the TMC and a digital pin in Xiao. And it has to be configured in void setup() as pinMode(ENABLE_PIN, OUTPUT); and digitalWrite(ENABLE_PIN, LOW);

Below is the code that made it work. The delay(10) controls the speed of the turning. If it gets smaller, the motor turns faster. digitalWrite(DIR_PIN, LOW) controls the direction. LOW turns clockwise, HIGH turns counter-clockwise.

Turning motor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
int DIR_PIN = D5;
int STEP_PIN = D4;
int ENABLE_PIN = D6;

void setup() {
  Serial.begin(19200);
  pinMode(STEP_PIN,OUTPUT);
  pinMode(DIR_PIN,OUTPUT);
  pinMode(ENABLE_PIN,OUTPUT);
  digitalWrite(ENABLE_PIN, LOW);

}

void loop() {
  digitalWrite(DIR_PIN, LOW);
  digitalWrite(STEP_PIN, HIGH);
  digitalWrite(STEP_PIN, LOW);
  delay(1);
}

Next, I wanted to turn it in a controlled manner. Following the tutorial, I gradually advanced the code. In the code below, the motor does one complete turn clockwise. interval controls the speed of the turning motion (higher = slower). steps controls how many steps the motor takes, (or how much it turns). By trial and error, I found out that the motor I had requires 385 steps to make a 360 degree turn. while(true) makes the loop stop when it does a single turn.

One single turn

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int DIR_PIN = D5;
int STEP_PIN = D4;
int ENABLE_PIN = D6;

void setup() {
  Serial.begin(19200);
  pinMode(STEP_PIN,OUTPUT);
  pinMode(DIR_PIN,OUTPUT);
  pinMode(ENABLE_PIN,OUTPUT);
  digitalWrite(ENABLE_PIN, LOW);

}

void loop() {
  digitalWrite(DIR_PIN, LOW);
  simpleMove(385);
 /* digitalWrite(DIR_PIN, HIGH);
  simpleMove(385); */

  while(true);
}

void simpleMove(int steps){
  int interval = 3000;
  for (int i=0; i < steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(interval);
  } 
}

Adding Potentiometer

I moved on to adding the potentiometer. After I wired it to the 3.3V of the XIAO and common GRD, I wrote the code to control the motor with the turning of the potentiometer.

My aim was to make the motor turn 1 step if the potentiometer’s value was different than a few microseconds before. I tried the code below, but the issue was the 0-1024 scale of the potentiometer was too sensitive, and the analog reading was constantly fluctuating. This meant that the previous potentiometer value was always different, even if it was not turning; leading the motor to constantly try to move.

The code below was my first attempt at doing this. It did not work because it didn’t account for these fluctuations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 int DIR_PIN = D5;
int STEP_PIN = D4;
int ENABLE_PIN = D6;
int POT_PIN = D1;
int potValue;
int prevPotValue =0;
int interval=3000;

void setup() {
  Serial.begin(19200);
  pinMode(STEP_PIN,OUTPUT);
  pinMode(DIR_PIN,OUTPUT);
  pinMode(ENABLE_PIN,OUTPUT);
  pinMode(POT_PIN, INPUT);
  digitalWrite(ENABLE_PIN, LOW);

}

void loop() {
  potValue=analogRead(POT_PIN);
  Serial.println(potValue);

  if(potValue>prevPotValue){
   moveClock(1);
  }else if(potValue<prevPotValue){
    moveCounterClock(1);
  } 

  prevPotValue = potValue;  
}

void moveClock(int steps){
  digitalWrite(DIR_PIN, LOW);
  for(int i=0; i<steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(interval);
  }
}

void moveCounterClock(int steps){
  digitalWrite(DIR_PIN, HIGH);
  for(int i=0; i<steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(interval);
  }
}

So I tried to map the scale of the potentiometer value to be less sensitive. I used the code below to debug the mapping in the serial monitor, instead of risking the mechanics of the stepper motor.

Here are the variables that can be changed to have better control over the motor:

  1. The last value in the map, adjustPot=map(potValue,0,1024,0,100) controls how sensitive the potentiometer is going to be. This also has an effect on the rest of the variables, so it is best to leave it at a rough value that you like and fine tune with the other variables.
  2. adjustPot+1 and adjustPot-1 values in the if statements, prevent the motor from stepping when the potentiometer is not turning but the value is fluctuating.
  3. delay(13) gives a delay between the analog readings. This controls when the program actually registers a potentiometer turn as a step (the if statements being true or false). When this value is too low or too high, it causes problems with registering these turns. It’s best to find a middle-ground sweet spot for this.

Debugging potentiometer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void loop() {
  potValue=analogRead(POT_PIN);
  adjustPot=map(potValue,0,1024,0,100);
  
  Serial.print("adjustPot: ");
  Serial.print(adjustPot);

  if(adjustPot+1<prevAdjustPot){
    Serial.println(" // Turning: COUNTERCLOCKWISE"); 
  }else if(adjustPot-1>prevAdjustPot){
    Serial.println(" // Turning: CLOCKWISE");
  }else{
    Serial.println(" ");
  }

  delay(13);

  prevAdjustPot=adjustPot;
}

And here is the full final code that made it work.

Working motor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
int DIR_PIN = D5;
int STEP_PIN = D4;
int ENABLE_PIN = D6;
int POT_PIN = D1;
int potValue;
int adjustPot;
int prevAdjustPot=0;
int interval=3000;

void setup() {
  Serial.begin(19200);
  pinMode(STEP_PIN,OUTPUT);
  pinMode(DIR_PIN,OUTPUT);
  pinMode(ENABLE_PIN,OUTPUT);
  pinMode(POT_PIN, INPUT);
  digitalWrite(ENABLE_PIN, LOW);  
}

void loop() {
  potValue=analogRead(POT_PIN);
  adjustPot=map(potValue,0,1024,0,100);
  
  Serial.print("adjustPot: ");
  Serial.print(adjustPot);

  if(adjustPot+1<prevAdjustPot){
    Serial.println(" // Turning: COUNTERCLOCKWISE"); 
    moveCounterClock(10);
  }else if(adjustPot-1>prevAdjustPot){
    Serial.println(" // Turning: CLOCKWISE");
    moveClock(10);
  }else{
    Serial.println(" ");
  }

  delay(13);
  
  prevAdjustPot=adjustPot;  
}

void moveClock(int steps){
  digitalWrite(DIR_PIN, LOW);
  for(int i=0; i<steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(interval);
  }
}

void moveCounterClock(int steps){
  digitalWrite(DIR_PIN, HIGH);
  for(int i=0; i<steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(interval);
  }
}

Making the Circuit Board

Milling

After making sure that the circuit works, I designed a circuit board for it. I used KiCad for this.

schematic schematic

In the PCB editor, I realized that the holes for the TMC2208 were too big, since I planned to solder headers to the holes. In order to make them the same size as the XIAO’s holes, I edited the holes’ properties. We can access the properties by right clicking and then we edit “Hole shape- diameter” to be 0.8mm.

editing holes

This time for milling I used Roland MDM-40. The online tutorial for it is a bit outdated so I still followed this tutorial for setting up the machine. The interface was a bit different however, and the final settings for that are below. It is best practice to reduce the Cutting Speed to %50 in the beginning of the cut, and increase it afterwards.

CNC interface CNC interface

In the first cut, the bottom part of the circuit was too shallow.

failed cut

To solve this, I placed the copper to more in the middle of the machine. And I did the Z height zeroing more to the middle of the circuit board.

placing in the middle final board

Assembling

I soldered headers to the board to mount the TMC and XIAO.

final board final board

I then placed all the components in place and connected them with jumper cables.

connecting with cables- front connecting with cables- back

However, when I connected the XIAO to the computer and plugged in the 12V adapter, the code I uploaded did not turn the motor. I tried debugging with various methods. The serial monitor was registering that the potentiometer was turning, so the problem was with the motor. I checked with a multimeter and verified that power was going to the motor. So it was something else.

While debugging, I found out that when I connect the ENABLE_PIN to GND, the motor suddenly starts turning. However, when I touch the end of the cable to the solder, it stops. This made me realize that it was a soldering issue, as the ENABLE_PIN was not completely connected. After re-doing the solder it worked.

Debugging

Here is how the final product looks and works:

connecting with cables- back

Final Version

Source Files

Week 9- Output Devices