DIY IRONLESS LINEAR SERVO-MOTOR

by Vulcaman in Workshop > CNC

65802 Views, 357 Favorites, 0 Comments

DIY IRONLESS LINEAR SERVO-MOTOR

1.JPG
DSC02579.JPG
DSC02584.JPG
DSC02600.JPG
DSC02629.JPG
DSC02641.JPG

Hi,
in this Instructable I want to show you, how to build your own Linear-Servo-Motor for Linear-Movement-Applications.


But at first the story about this Instructable:

When I visited one of the biggest trade faires for Automation here in Germany, I saw a lot of Linear-Motors in Industry Applications. It was quite astonishing how fast these Motors can move with an incredible precision.

I thought it would be really cool, if I could addapt these kind of motor in a Laser or 3D-Printer Application. Sadly these Motors are very expensive (>1000€ per piece). So buying a Linear-Motor is not an option anymore. But after some research I thought it will be possible to build my own Linear-Motor. Theoretecly a Linear-Servo-Motor is just a three phase sychronous motor with a closed loop position feedback. So I started to create CAD-Drawings and Electronics. After one month of research and improvements I can say, I have built my own working Ironless Linear-Servo-Motor. However there are some points which need to be improved especially in the position regulation. This project helped me a lot to understand, how a Linear-Motor works in general, and how to programm a closed-loop controller for it.


Specification:

Travel-Distance: 290mm

max. Travel-Speed: 200mm/s (at 24V, I think there is much more possible, but my coils are getting to hot above 24V)

accuracy: 0.3mm (remember there is just a 400pulse/rev encoder)

cost: <100€ if you have all the tools like CNC-Mill and 3D-Printer at home.

Videos:

Fast movements; position is set in the Arduino-File:

Fixed position; the Motor tries to withstand external forces to keep his position:

### If you like my Instructable, please vote for me in the Epilog-Contest 10###

### You can see this motor live at Maker Faire Ruhr 2019 ###

The Theory of the Linear Motor

Theoretectly a Linear Motor is just an unrolled three phase Motor. You controll the Linear-Motor like a rotary motor by connecting a three phase sinusiodle current at each of the coils. The coils will create a periodic moving magnetic field, which will result in a force which will drive the motor. For a better imagination, please take a look at this Wikipedia article. Sadly the infomations, which are necessary to build an Ironless Linear Motor aren't descriped that well in this article, so I have written down my own experiences, while building this motor. At frist it sounds simple "just three coils between some magnets", but after some tests, I could say it was really hard to find the right parameters:


The arrangement of the coils to the magnets:

The coils needs to be arranged to the magnets like seen above, this kind of arrangement will cerate the optimal force to the three coils . Because I have choosen to build an ironless type linear motor, that means that there is no iron or any other material with a high permability inside the coils, there are a few points you need to consider about, before start building your own motor:

  • The distance between the lower and upper magnets:

One of the main problems of a motor is the gab of air between the coils and magnets . On the one hand the magnetic field between the magnets will be increased, by decreasing the distance between them. On the other hand, there are still the coils between the magnets, which needs to be fixed in there position and also need to withstand the applied current. After some experiments with different kinds of coil fixtures and distances, I found out that the best distance between the magnets is 6mm (This is not the mathematical perfect distance, but for me it is the closest distance I could reach if you consider that I need to create the fixture and the coils by myself).

  • The Iron back circuit:

As said above the resistance of the magnetic flux will be increased by low permability materials like air. But if you will use a high permability material like Iron, the resistance for the magnetic flux will drop significantly. The conclusion is to use some iron sheets from the outside to mount the magnets. Just because of two sheets of iron, the magnetic flux between the two magnets will be increased.

  • The coils:

The installed coils have a dimension of 16x26mm and are made out of 0.2mm copper isolated wire. The coils are just 3mm thick. You will find more information about the coils in step 5.

Mechanical-Parts

DSC02646.JPG
DSC02648.JPG

The complete motor is designed with Fusion 360. Below you will find all requiered parts and files of the motor:

Fusion 360 File:

Standart-Parts:

QuantityDescriptionLink Price
1x20x40x400mm aluminium extrusion
Dold-Mechatronik3,50€
1x350mm MGN9 Linear rail with MGN9H Wagon
Aliexpress 12,88€
1x
2m GT2 Belt 6mm width
Aliexpress 0,72€
56x10x20x3mm N35 neodym magnets
Aliexpress 19,01€
6xF623ZZ flanged ball bearings
Aliexpress 2,51€
1xGT2 Pulley 20 Teeth 6mm Bore
Aliexpress 2,79€

Nuts, Screws and Washers:

QuantityDescriptionWhere to buy
Price
4xM5x20mm DIN912 cylinderhead screw
local hardware store
-
2xM5x10mm DIN912 cylinderhead screw

local hardware store

-
6xM4x20mm DIN912 cylinderhead screw

local hardware store

-
4x
M4x10mm DIN912 cylinderhead screw

local hardware store

-
2xM3x30mm DIN912 cylinderhead screw

local hardware store

-
2xM3x25mm DIN912 cylinderhead screw

local hardware store

-
10xM3x16mm DIN912 cylindergead screw

local hardware store

-
30xM3x8mm DIN912 cylinderhead screw

local hardware store

-
5xM5 T-Slot-Nut

Aliexpress

5,33€
4xM4 T-Slot-Nut

Aliexpress

5,33€
18xM3 T-Slot-Nut

Aliexpress

5,33€
4xM3 Nut

local hardware store

-
4xM5 washer

local hardware store

-
10xM4 washer

local hardware store

-
25xM3 washer

local hardware store

-

CNC-Milled-Parts:

All installed aluminium parts are milled on my diy CNC-Router. The most complex part to machine is the carriage fixture, because this part requiered a two side machining. The steel parts for the forcer are handmade, because my CNC machine has not the capability to mill steel. You can download all the CAD-Files at the bottom of this step.

QuantityDescriptionHow the part looks like
1x

Carriage

1x

forcer

1x

Carriage_top_1

1x

carriage_top_2

1x

encoder_plate

1x

spacer

2x

foot

1x

pcb_plate

1x

steel_plate_top

1x

steel_plate_bottom

3D-Printed Parts:

The 3D-Printed parts are made out of PLA with a resolution of 0.1mm. All requiered .stl files are aviable at the bottom of this step. If you don't have a 3D-Printer, you can buy the 3D-Printed-Parts here.

QuantityDescriptionHow the part looks like
1x

forcer_top.stl

1x

forcer_bottom.stl

1x

encoder_spacer.stl

2x

bumper.stl

4x

pcb_spacer.stl

4x

pcb_foot.stl

Electrical-Parts

Electronic Parts for the Motor:

QuantityDescriptionLink Price
1xRotary Encoder 400pulse/rev
Aliexpress11,41€
3x100m 0,2mm copperwire
Aliexpress 6,62€
3x
1m Wires 22AWG (black , red , yellow )
Aliexpress 3,30€
9xterminals
local hardware store
0,20€


Electronic Parts for the PCB:

Here are all required parts for the Linear Motor. I tried to source all parts as cheap as possible.

QuantityDescriptionName on PCB
Link Price
1xArduino Nano
U1
Aliexpress 1,77€
1xL6234 Three phase H-Bridge
U2
Aliexpress 3,00€
8x1k Resistor
R1-R8
Aliexpress 0,53€
1xPinheader
JP1-JP4
Aliexpress 0,48€
1x2-Pin screw-terminal
J1
Aliexpress 0,82€
1x3-Pin scew-terminal
J2
Aliexpress 1,25€
1x7805 Linear Voltage Regulator
IC1
Aliexpress 0,86€
2x1N4148 Diode
D1, D2
Aliexpress 0,82€
2x0.1µF capacitor
C1, C7
Aliexpress 1,20€
1x0.33µF capacitor
C6
Aliexpress 1,20€
1x10nF capacitor
C3
Aliexpress 1,20€
1x220nF capacitor
C2
Aliexpress 1,25€
1x100µF polarized capacitor
C4
Aliexpress 1,24€
1x1µF polarized capacitor
C5
Aliexpress 0,62€

Here are all the files for the requierd PCB. I have attached all files for manufacturing: gerber files , eagle cad files and even etch templates, if you want to create your PCB with the toner transfer methode. I have created the PCB by a professionell manufacture. The PCB is just single side, so it will be easy to make.

QuantityDescriptionTop View
Bottom View
1x

PCB

Building the Motor: the Magnetic Rail

DSC02651.JPG

What you need for this step:

QuantityDescription
48x

10x20x3mm N35 neodym magnets

6x

M4x20mm DIN912 cylinderhead screw

6x

M4-washer

1x

"spacer" aluminium part

1x

steel_plate_top (in my case painted black)

1x

steel_plate_bottom (in my case painted black)

1x

20x40x400mm aluminium extrusion


What you have to do:

At frist you have to take the upper steel plate and place 24 magnets with alternating polarity on it. For the right distance of 3,33mm between the magnets I've created an allignment tool (See picture [2] below). Once all the magnets are in the right position, you have to fix them at their place with some super glue. Now repeat this procedure with the bottom steel plate.


Now you have to combine the upper and the lower steel-plate by using the six M4 Screws. You do that by using the "spacer" aluminium part. Because the magnets are so strong, I recommend to use a piece of wood or something similar to protect the magnets while assembling the steelplates.

The Coils

1.JPG

What you need for this step:

QuantityDescription
3x

100m x 0.2mm diameter isolated copper wire

1x

"forcer" aluminium part

6x

M4-washer

some

kapton tape

1x

selfmade coil tool


This is one of the most complicatest steps of the motor. I've personally needed around ten iterations, after I have found the right dimesion of the spools, which actually worked. You have to find the right parameters between current tollerance and diameter of the coil. If these two values fit together you will have a good coil.

Because there is no ferro-magnetic material in the "forcer", it will not amplifiy the magnetic field, so the field out of the coils needs to be strong enough to move the motor.

Specifications of my coils:

  • 0.2mm copper wire
  • 15 [Ohm] resistance
  • +-100m of wire

Now I will show you how I have made the coils:

What you have to do:

At first you should print out my tool to wind the coils. It will simplify the process of the spool winding. So at first take the winding tool and attach some baking paper on both sides of the tool. This will be usefull in the next steps.


After that I am using a drilling machine to wind the wires on the tool. The wires need to fill the complete space between the two plates. Once finished, you can use some super glue to keep the wires in position and because of the backing paper, the glue will not stick to the fixture ;).


Once the glue is dried, you can remove the fixture carefully. The 3D-printed inlay of the coil is not going to be removed, it will stay there for ever.


You need to repeat this step three times. Finally you have to take the "forcer" aluminium part and place the three coils inside the three pre-milled pockets. To hold the coils in place I have used some kapton tape. The Advantage of kapton tape is, that it is very thin but also heat resistant, which is ideal for this application.

Downloads

The Carriage

DSC02670.JPG

What you need for this step:

QuantityDescription
1x

assembled coil module

1x

"Carriage" aluminium part

1x

"Carriage_top_1" aluminium part

1x

"Carriage_top_2" aluminium part

1x

cable-chain

1x

forcer_top.stl

1x

forcer_bottom.stl

6x

M3x8mm DIN912 screws

4x

M3x30mm DIN912 screws


What you have to do:

At frist you have to attach the coil module to the "carriage" alumnium part. You do that by using two M3x8mm screws.


After that you have to connect the coils to the wires. The coils need to be connected in triangle configuration. The connection is simply made by a terminal connector.


Then it is time to close the connection box. For that you have to use the "forcer_top.stl" file.


Finally attach the cable chain to the upper aluminium plate.

The Encoder Plate

DSC02660.JPG

What you need for this step:

QuantityDescription
1x

"encoder_plate" aluminium part

1x

"encoder_spacer.stl" 3D-printed part

6x

F623ZZ flanged ball bearings

1x

GT2 Pulley 20 Teeth 6mm Bore

3x

M3x16mm DIN912 cylinderhead screw

3x

M3x16mm DIN912 cylinderhead screw

6x

M3 washer

1x

Rotary Encoder 400pulse/rev


What you have to do:

At first you have to slide the GT2 Pulley on the encoder. Then you need to fix the Pulley by using the allen screws inside the pulley.


Now take the encoder and connect it to the "encoder_plate". Do that by using the three M3x16mm screws and the encoder_spacer.


In the following steps the bearings for the timing belt are going to be attached to the "encoder_plate":


Now put the bearings, screws and washers together. Repeat this three times:


Finally connect the bearings to the encoder plate:

Bringing All Parts Together

DSC02689.JPG

What you need for this step:

QuantityDescription
1x

assembled encoder plate

1x

assembled magnetic rail

1x

assembled carriage

1x

350mm MGN9 Linear rail with MGN9H Wagon

1x

2m GT2 Belt 6mm width

2x

"foot" aluminium part

18x

M3x8mm DIN912 cylinderhead screw

18x

M3 T-Slot-Nut

4x

M4x10mm DIN912 cylinderhead screw

2x

M5x10mm DIN912 cylinderhead screw

4x

M5x20mm DIN912 cylinderhead screw

2x

M5 T-Slot-Nut

2x

"bumper.stl" 3D-printed part


What you have to do:

At first you have to put the linear rail at the front of the
"magnetic-rail" module. After that attach the two bumpers on both sides of the rail. The bumpers will prevent the wagon from falling out.


Now it is time to attach the "foot" aluminium parts to the "magnetic-rail" module. For the connection, I have cut four M5-threads inside the aluminium extrusions. The alumnium parts are connected by four M5x20mm screws.


For the next step you need to place the "encoder-plate" module on the "magnetic-rail" module. The connection is made by four M4x10mm screws.


Now you have to connect the "heart" of the motor, the carriage. For the connection to the linear rail, you have to use the four M3x8mm screws. The cable chain is connected by two M3x8mm screws.


Finally the GT2 belt needs to be attached to the rotary encoder. And you are done! The mechanical part of the motor is compelted. Now it's time to step over in electronics and programming :-) .

The PCB

Schematic.jpg
DSC02641.JPG
DSC02644.JPG
PCB_Oben.jpg

The motor is mainly controlled by an Arduino Nano and the L6234 motor driver chip. As you can see in the schematic I have also break out some pins, so that there will be a connectivity for a step/dir interface (not implemented yet).


For the builing of the circuit I recommend to manufacture a PCB. You can do this by yourself with the toner transfer methode or you can order it with the gerber files by a professionell manufacture like I did. All the requierd files are available in the "Electrical-Parts" step.

Because I could only purchase ten PCBs at one time, I will sell some of these PCBs in my onlineshop for only 2€.

Downloads

Programming the Arduino

While I was experimenting with the first prototype of the linear motor, I took some inspiration from this article: berryjam.eu, this guy uses the same L6234 chip like me and he successfully move a brushless motor slow and with precision. The problem with this kind of motor controll is, that there is no feedback where the rotor is located. But if you want to drive a brushless motor or Linear Motor the fast way, you need the information, where the rotor is located, to switch the coils just at the perfect position. In brushless ESC controllers this is often done by HAL-Sensors. But for Linear-Motors with a position feed-back this is not the best option, because you only know where the coils are, when they are in movement.Also the resolution of the position feed-back isn't really accurate.

So for my application, the linear motor, I have tried a different way: I installed a rotary encoder, which is connected to the linear motor slider by a belt. This is used to measure the position of the coils, but also to read out the actual position where the slider is located. While using this technic I have solved both problems, the perfect switching of the coils and also the knowledge, where the slider is actually located. So I wrote a small programm on the arduino which will excatly do this kind of motor controll.

The complete code:

 #include <PID_v1.h>

const int encoder0PinA = 2 ;
const int encoder0PinB = 3 ;

volatile int encoder0Pos = 0;

const int EN1 = 5;
const int EN2 = 6;
const int EN3 = 7;
 
const int IN1 = 9;
const int IN2 = 10;
const int IN3 = 11;

double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

// SPWM (Sine Wave)
int pwmSin[72] = {127, 138, 149, 160, 170, 181, 191, 200, 209, 217, 224, 231, 237, 242, 246, 250, 252, 254, 254, 254, 252, 250, 246, 242, 237, 231, 224, 217, 209, 200, 191, 181, 170, 160, 149, 138, 127, 116, 105, 94, 84, 73, 64, 54, 45, 37, 30, 23, 17, 12, 8, 4, 2, 0, 0, 0, 2, 4, 8, 12, 17, 23, 30, 37, 45, 54, 64, 73, 84, 94, 105, 116 };

enum phase {PHASE1, PHASE2, PHASE3};
int count[] = {0,24,48};

int *pos_U = pwmSin;
int *pos_V = pwmSin + 24;
int *pos_W = pwmSin + 48;

const double abstand = 27; //24

int directionPin = 4;
int stepPin = 12;

double step_position = 0.0;

int test;

double position_in_mm = (encoder0Pos) / 40.00;


 
void setup() {
  pinMode(encoder0PinA, INPUT);
  pinMode(encoder0PinB, INPUT);

  // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);

  // encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);

  step_position = 0;

  

  setPwmFrequency(IN1); // Increase PWM frequency to 32 kHz  (make unaudible)
  setPwmFrequency(IN2);
  setPwmFrequency(IN3);
 
  pinMode(IN1, OUTPUT); 
  pinMode(IN2, OUTPUT); 
  pinMode(IN3, OUTPUT); 
  
  pinMode(EN1, OUTPUT); 
  pinMode(EN2, OUTPUT); 
  pinMode(EN3, OUTPUT); 
 
 
  digitalWrite(EN1, HIGH);
  digitalWrite(EN2, HIGH);
  digitalWrite(EN3, HIGH);

  analogWrite(IN1,*pos_U);
  analogWrite(IN2,*pos_V);
  analogWrite(IN3,*pos_W); 
  delay(2000);
  analogWrite(IN1,0);
  analogWrite(IN2,0);
  analogWrite(IN3,0); 

  
  encoder0Pos = 0 ; 
  Input = encoder0Pos / 40.00 ;
  Setpoint = step_position;
  myPID.SetOutputLimits(-1000, 1000); 
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(1);
  unsigned long previousMillis = 0;       

}


unsigned long previousMillis = 0;
const long interval = 500;
int ledState = LOW;
int i = 0;


void loop() {

int positions[2] = { -100.0 , 0};

myPID.SetTunings(15,0,0.4); //val_1,0,val_


Input = encoder0Pos / 40.00;
myPID.Compute();
drive(Output/1000);
Setpoint = positions[i];
unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (i < 1) {
      i++;
    } else {
      i = 0;
    } 
  }
  
}

double newmap(double x, double in_min, double in_max, double out_min, double out_max){

  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void drive(double scale_factor){
  
if(scale_factor < 0.00){
double  temp = -scale_factor;
temp = (temp - 0.00) * (1.0 - 0.1) / (1.00 - 0.00) + 0.1;

test =- ( count[0] - berechne() + 24) ; // +24
  shift(&pos_U, test , 72, PHASE1); 
  shift(&pos_V, test, 72, PHASE2); 
  shift(&pos_W, test, 72, PHASE3);

  analogWrite(IN1,*pos_U * temp );
  analogWrite(IN2,*pos_V * temp );
  analogWrite(IN3,*pos_W * temp);  
return;
}

if(scale_factor > 0.00){
test = (- count[0] + berechne() + 24) ;
scale_factor =(scale_factor - 0.00) * (1.0 - 0.1) / (1.00 - 0.00) + 0.1;
  shift(&pos_U, test , 72, PHASE1); 
  shift(&pos_V, test, 72, PHASE2); 
  shift(&pos_W, test, 72, PHASE3);
  
  analogWrite(IN1,*pos_U * scale_factor );
  analogWrite(IN2,*pos_V * scale_factor );
  analogWrite(IN3,*pos_W * scale_factor); 
 
return;
}

if(scale_factor == 0.00)

return;

}

int berechne(){
 double position_in_mm = (encoder0Pos) / 40.00;
 int vielfaches = position_in_mm / abstand;
 double phaseshift2 = position_in_mm-(vielfaches*abstand);
 // Serial.println(phaseshift2);
double phaseshift3 = (phaseshift2 - 0) * (72 - 0) / (abstand - 0) + 0;
 //Serial.println(phaseshift3);
 return phaseshift3;
 
}

//######################## Shift-Array########################

void shift(int **pwm_sin , int shift_distance , int array_size, phase phase_number){
  if(shift_distance == array_size)
  return;
  
  if(shift_distance > 0){
  if(count[phase_number] + shift_distance < array_size){
  *pwm_sin = *pwm_sin + shift_distance;
   count[phase_number] += shift_distance ;
  }
  else
  {
    int temp =count[phase_number] + shift_distance - array_size;
    *pwm_sin = *pwm_sin - count[phase_number];
    *pwm_sin = *pwm_sin + temp;
    count[phase_number] = temp;
    
  }
  return; 
  }

  
  if(shift_distance < 0){
    int temp_distance = array_size + shift_distance;
    shift(pwm_sin, temp_distance , array_size, phase_number); 
  }

  
  if(shift_distance = 0 );
  return;
}






//########################### ENCODER-INTERRUPT#########################################
void doEncoderA() {
  // look for a low-to-high on channel A
  if (digitalRead(encoder0PinA) == HIGH) {

    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinB) == LOW) {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;         // CCW
    }
  }

  else   // must be a high-to-low edge on channel A
  {
    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinB) == HIGH) {
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }
  //Serial.println (encoder0Pos, DEC);
  // use for debugging - remember to comment out
}

void doEncoderB() {
  // look for a low-to-high on channel B
  if (digitalRead(encoder0PinB) == HIGH) {

    // check channel A to see which way encoder is turning
    if (digitalRead(encoder0PinA) == HIGH) {
      encoder0Pos = encoder0Pos + 1;         // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;         // CCW
    }
  }

  // Look for a high-to-low on channel B

  else {
    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinA) == LOW) {
      encoder0Pos = encoder0Pos + 1;          // CW
    }
    else {
      encoder0Pos = encoder0Pos - 1;          // CCW
    }
  }
}

//#################### PWM-Motor#######################

void setPwmFrequency(int pin) {
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | 0x01;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | 0x01;
    }
  }
  else if(pin == 3 || pin == 11) {
    TCCR2B = TCCR2B & 0b11111000 | 0x01;
  }
  
}

Now I will explain you the main procedure of my arduino programm:

  1. The coils needs to be alligend to a predefined point, that the arduino knew, where the magnets are located. This is made by the putting a three phase voltage to the coils. So the slider will rast inside the magnetic field automaticly. After that the position of the motor is defined as zero. For further movements the position will be captured by an interrupt on Pin D2 and D3 now.
  2. The attached sinusiodal voltage needs to be sychronised with the magnet-positions. For that application, I have used the function berechne()

 int berechne(){
 double position_in_mm = (encoder0Pos) / 40.00;
 int vielfaches = position_in_mm / abstand;
 double phaseshift2 = position_in_mm-(vielfaches*abstand);
 double phaseshift3 = (phaseshift2 - 0) * (72 - 0) / (abstand - 0) + 0;
 return phaseshift3;
} 

The function returns the right index of the pwm array, so that there is always the right field orientation between the coils and the magnets.

3.With this information I am able to drive the motor. This is done by the function drive() :

void drive(double scale_factor){
if(scale_factor < 0.00){
double  temp = -scale_factor;
temp = (temp - 0.00) * (1.0 - 0.1) / (1.00 - 0.00) + 0.1;

test =- ( count[0] - berechne() + 24) ; // +24
  shift(&pos_U, test , 72, PHASE1); 
  shift(&pos_V, test, 72, PHASE2); 
  shift(&pos_W, test, 72, PHASE3);

  analogWrite(IN1,*pos_U * temp );
  analogWrite(IN2,*pos_V * temp );
  analogWrite(IN3,*pos_W * temp);  
return;
}

if(scale_factor > 0.00){
test = (- count[0] + berechne() + 24) ;
scale_factor =(scale_factor - 0.00) * (1.0 - 0.1) / (1.00 - 0.00) + 0.1;
  shift(&pos_U, test , 72, PHASE1); 
  shift(&pos_V, test, 72, PHASE2); 
  shift(&pos_W, test, 72, PHASE3);
  
  analogWrite(IN1,*pos_U * scale_factor );
  analogWrite(IN2,*pos_V * scale_factor );
  analogWrite(IN3,*pos_W * scale_factor); 
 
return;
}

if(scale_factor == 0.00)

return;

}

}

This function recieves a double value which stands for the speed and the direction.The actual movement will be created by the function shift with the following analogWrite(). I simply shift the PWM-Array by a 1/3 periode, which causes a movement in the positiv direction. The speed of the motor is controlled by the scale_factor(). Which is the amplitude of the sinusiodal

4. Now there is only one last essential function: The PID controll loop. For that purpose I have used an allready finished PID-libary which can be loaded by the Arduino libary-manager. The PID-loop looks at the difference between the actual position and the desired position. The output will be a double value from -1.0 - 1.0 which can be used by the drive function.


I have to say this is not the best arduino code. Yes it works, but there are still some problems to solve especially the velocity and positioning regulation loop. I am also on the way to implement an interface with step and direction signals, but there are still some problems to solve like acceleration ramps and constant velocity. I am trying to update the software in the next time. So stay tuned for an update and please leave some suggestions, how I could improve the code :-)

The complete Arduino code can be downloaded below. The file is tested with Arduino IDE 1.8.2 .

Troubleshooting and Future Plans

Troubleshooting

Problem: The motor will not move correct, but the magnets in the magnetic field are changing in some way, while pushing the carriage by hand.

Solution: The magnets and the coils are not synchronised to each other. The simplest way to do this is by software.

At first you can print count[0] and berechne() inside your serial console, but make sure the drive function is uncomment. These two values should always be the same if they are not, please adjust the encoder0Pos in the void setup().


Problem: The encoder will not output a stable position

Solution: The encoder cable screen needs to be grounded, otherwise you will have a lot of noise effects which creates unstable signals.


Future Plans

  1. Update the firmware for better position and velocity controll.
  2. Upgrade to a STM32 Microcontroller for more peformance.
  3. Build a second motor and use both inside a CNC-Controlled machine.