Jump to content

Banner.jpg.b83b14cd4142fe10848741bb2a14c66b.jpg

YARF - Yet Another Robo Focuser.


NickK

Recommended Posts

Also..

DRV8825 data sheet

ƒSTEP Step frequency 250kHz

tWH(STEP) Pulse duration, STEP high 1.9μs

tWL(STEP) Pulse duration, STEP low 1.9μs

tSU(STEP) Setup time, command before STEP rising 650ns

tH(STEP) Hold time, command after STEP rising 650ns

tENBL Enable time, nENBL active to STEP 650ns

tWAKE Wakeup time, nSLEEP inactive high to STEP input accepted 1.7ms

So with 1000ns per μs, then the enable time is actually very very quick (a step needs 3800ns to perform +650ns setup time). The rate at which the ardunio could operate stepping means it could be possible to enable-step-disable.. I wonder if you could use something to connect the step and the enable pin perhaps with a capacitor and a transistor to drain it as a latch. That way you could switch the power on only for each step (from a driver point of view) - probably the effect on the motor would mean it needs more time..

Still nice to know the enable is very quick.

Link to comment
Share on other sites

  • Replies 81
  • Created
  • Last Reply
58 minutes ago, ChrisLX200 said:

You may not even need to leave the coils energised with that high ratio box, it likely wouldn't slip though clearly it's the better option. 60deg is well within spec for these motors, I hate to think what my NEMA17 motors run at inside the 3D printer - the bed sits at 110deg and the extrusion motor is right next to the hot end at 240deg ;-) Yes, there are small fans but I wouldn't want to touch the motors!

ChrisH

However what effect would the motor have on the scope/air if the hot air rises across the line of sight.. ;)

I think that a modified stepper library will work really well - simply have the library perform enable/disable after each step, or if that's not convenient even just put a timer so no activity caused system to disable then re-enable on the next step call. If the speed for enable and stepping is needed then it's possible to 'abuse' the PWM and hardware timers in the Arduino so that each pulse of a PWM causes the ENABLE to be active during the step pulse with setup and teardown in there too...

The existing ardunio standard stepper library simply manually bit-bangs the pins using delay between digitalWrites step high & low. There's nothing stopping a digitalWrite on the enable around those two given the speed of the enable on the DRV8825. Hmm... 

Ok, I think I'll order the DRVs along with the other bits. Then test with the desk PSU before deciding which UBEC will work - it may be with the micro stepping that the 12V works better and I can try with both 9 & 12V. If the modified driver library works with ENABLE then it should work nicely - I'll see if I can recompile the ardunio libraries as the library is in C++.

Link to comment
Share on other sites

The NEMA 17 motors on my 3D printers are on the outside and don't get hot - the UP Plus 2 printer uses fan cooling for its extruder motor but the other motors do get quite hot even though in the open air.  The UP uses NEMA 14 motors (less efficient).

Link to comment
Share on other sites

Woo.. so I've used an implementation of the stepper library direct in the sketch implementation:

	#ifndef Stepper_h
	#define Stepper_h
	// library interface description
	class Stepper {
	  public:
	    // constructors:
	    Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int enablePin1, int enablePin2);
	    // speed setter method:
	    void setSpeed(long whatSpeed);
	    // mover method:
	    void step(int number_of_steps);
	    int version(void);
	  private:
	    void stepMotor(int this_step);
	    int direction;            // Direction of rotation
	    unsigned long step_delay; // delay between steps, in ms, based on speed
	    int number_of_steps;      // total number of steps this motor can take
	    int pin_count;            // how many pins are in use.
	    int step_number;          // which step the motor is on
	    // motor pin numbers:
	    int motor_pin_1;
	    int motor_pin_2;
	    int motor_pin_3;
	    int motor_pin_4;
	    int motor_pin_5;          // Only 5 phase motor
	    int enablePin1;
	    int enablePin2;
	    unsigned long last_step_time; // time stamp in us of when the last step was taken
	};
	#endif
	
	Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int enablePin1, int enablePin2)
	{
	  this->step_number = 0;    // which step the motor is on
	  this->direction = 0;      // motor direction
	  this->last_step_time = 0; // time stamp in us of the last step taken
	  this->number_of_steps = number_of_steps; // total number of steps for this motor
	  // Arduino pins for the motor control connection:
	  this->motor_pin_1 = motor_pin_1;
	  this->motor_pin_2 = motor_pin_2;
	  // setup the pins on the microcontroller:
	  pinMode(this->motor_pin_1, OUTPUT);
	  pinMode(this->motor_pin_2, OUTPUT);
	  // When there are only 2 pins, set the others to 0:
	  this->motor_pin_3 = 0;
	  this->motor_pin_4 = 0;
	  this->motor_pin_5 = 0;
	  this->enablePin1 = enablePin1;
	  this->enablePin2 = enablePin2;
	  
	  // pin_count is used by the stepMotor() method:
	  this->pin_count = 2;
	}
	/*
	 * Sets the speed in revs per minute
	 */
	void Stepper::setSpeed(long whatSpeed)
	{
	  this->step_delay = 60L * 1000L * 1000L / this->number_of_steps / whatSpeed;
	}
	/*
	 * Moves the motor steps_to_move steps.  If the number is negative,
	 * the motor moves in the reverse direction.
	 */
	void Stepper::step(int steps_to_move)
	{
	  int steps_left = abs(steps_to_move);  // how many steps to take
	  // determine direction based on whether steps_to_mode is + or -:
	  if (steps_to_move > 0) { this->direction = 1; }
	  if (steps_to_move < 0) { this->direction = 0; }
	  
	  // decrement the number of steps, moving one step each time:
	  while (steps_left > 0)
	  {
	    unsigned long now = micros();
	    // move only if the appropriate delay has passed:
	    if (now - this->last_step_time >= this->step_delay)
	    {
	        digitalWrite(enablePin1, HIGH);
	        digitalWrite(enablePin2, HIGH);
	      // get the timeStamp of when you stepped:
	      this->last_step_time = now;
	      // increment or decrement the step number,
	      // depending on direction:
	      if (this->direction == 1)
	      {
	        this->step_number++;
	        if (this->step_number == this->number_of_steps) {
	          this->step_number = 0;
	        }
	      }
	      else
	      {
	        if (this->step_number == 0) {
	          this->step_number = this->number_of_steps;
	        }
	        this->step_number--;
	      }
	      // decrement the steps left:
	      steps_left--;
	      // step the motor to step number 0, 1, ..., {3 or 10}
	      if (this->pin_count == 5)
	        stepMotor(this->step_number % 10);
	      else
	        stepMotor(this->step_number % 4);
	    } else {
	        digitalWrite(enablePin1, LOW);
	        digitalWrite(enablePin2, LOW);
	    }
	  }
	}
	/*
	 * Moves the motor forward or backwards.
	 */
	void Stepper::stepMotor(int thisStep)
	{
	    switch (thisStep) {
	      case 0:  // 01
	        digitalWrite(motor_pin_1, LOW);
	        digitalWrite(motor_pin_2, HIGH);
	      break;
	      case 1:  // 11
	        digitalWrite(motor_pin_1, HIGH);
	        digitalWrite(motor_pin_2, HIGH);
	      break;
	      case 2:  // 10
	        digitalWrite(motor_pin_1, HIGH);
	        digitalWrite(motor_pin_2, LOW);
	      break;
	      case 3:  // 00
	        digitalWrite(motor_pin_1, LOW);
	        digitalWrite(motor_pin_2, LOW);
	      break;
	    }
	}
	/*
	  version() returns the version of the library:
	*/
	int Stepper::version(void)
	{
	  return 5;
	}
	 
	// Stepper motor
	const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
	// for your motor
	// Ardunio Motor Shield values (board pins -> L298 -> output)
	const int dirA = 12; //D12 -> P13 in3 -> out3 (B)
	const int dirB = 13; //D13 -> P7 in1 -> out1 (A)
	const int pwmA = 3; //D3 -> enable A (high to provide power, or PWM to provide pulse control, or low to disable)
	const int pwmB = 11;//D11 -> enable B (high to provide power, or PWM to provide pulse control, or low to disable)
	const int brakeA = 9; //D9 -> (dirA e brakeA) -> in2 -> out2 (A)
	const int brakeB = 8; //D8 -> (dirB e brakeB) -> in4 -> out4 (B)
	const int senA = 0; //A0 sense A
	const int senB = 1; //A1 sense B
	
	// focuser RPM speeds
	// stepper library works better with higher RPM speeds and
	const int stepSpeedFastAndFurious = 200; // unreliable, used for moving quick but may loose position
	const int stepSpeedFast = 90; // fast and most likely accurate
	const int stepSpeedMedium = 10; // accurate
	const int stepSpeedSlow = 3; // sloow and accurate
	// initialize the stepper library on pins 8 through 11:
	// ^^ this depends on your stepper, the values are coil sequences.
	// For the motor shield L298 this is in1,in2,in3,in4 for bipolar (although dirA, dirB also work)
	Stepper focuserStepper(stepsPerRevolution, dirA, dirB, pwmA, pwmB);
	void setup() {
	  // put your setup code here, to run once:
	  Serial.begin(9600);
	  // Setup Bipolar Stepper - set up pin directions and power settings
	  pinMode(pwmA, OUTPUT);
	  pinMode(pwmB, OUTPUT);
	  pinMode(brakeA, OUTPUT);
	  pinMode(brakeB, OUTPUT);
	  digitalWrite(pwmA, HIGH);
	  digitalWrite(pwmB, HIGH);
	  digitalWrite(brakeA, LOW);
	  digitalWrite(brakeB, LOW);
	  
	  Serial.println("simulated calibation");
	  focuserStepper.setSpeed(200);
	  focuserStepper.step(1);
	}
	void loop() {
	  focuserStepper.step(1);
	  delay(1);

	}
	

Link to comment
Share on other sites

Temp with the change above when running 33degC at 9V which is a lot less than the non-ENABLE control version!

So apart from the pulse timing - the idea works :D Naturally the fun part is that that shaft takes time to accelerate and it may be better with the ENABLE working along side that.

 

Bah- mistake in code.. hmmm .. no so working.. more the pulse width

Edit: so ok.. the enable=high at the start of the step operation and enable=low at the end of the step() function works. However the inter-step toggling is outside of the normal bit-banging I think you'd need to use the hardware timers and be more flexible in that the enable pulse high/low needs to be not a PWM..

However running with just the step() enable level toogling at 9V still results in a cooler operation as soon as the stepper is idle it's Power is cut. And running the stepper is cooler than having it static.

So that's actually a workable option from the example! I've removed the 4&5 unipolar code to make it smaller and more readable. However just add the analogWrite() lines in and the constructer changes to add additional enable pin parameters into the stepper library code.. and you have a cooler running stepper that switches off when idle.

	void Stepper::step(int steps_to_move)
	{
	  int steps_left = abs(steps_to_move);  // how many steps to take
	  // determine direction based on whether steps_to_mode is + or -:
	  if (steps_to_move > 0) { this->direction = 1; }
	  if (steps_to_move < 0) { this->direction = 0; }
	  
	  analogWrite(enablePin1, 255); // enable PWM
	  analogWrite(enablePin2, 255);
	 
	  // decrement the number of steps, moving one step each time:
	  while (steps_left > 0)
	  {
	    unsigned long now = micros();
	    // move only if the appropriate delay has passed:
	    if (now - this->last_step_time >= this->step_delay)
	    {  
	      // get the timeStamp of when you stepped:
	      this->last_step_time = now;
	      // increment or decrement the step number,
	      // depending on direction:
	      if (this->direction == 1)
	      {
	        this->step_number++;
	        if (this->step_number == this->number_of_steps) {
	          this->step_number = 0;
	        }
	      }
	      else
	      {
	        if (this->step_number == 0) {
	          this->step_number = this->number_of_steps;
	        }
	        this->step_number--;
	      }
	      // decrement the steps left:
	      steps_left--;
	      // step the motor to step number 0, 1, ..., {3 or 10}
	        stepMotor(this->step_number % 4);
	    }
	  }
	 
	  analogWrite(enablePin1, 0); // disable PWM
	  analogWrite(enablePin2, 0);
	}
	

 

Link to comment
Share on other sites

It seems that what is required is a delay after making the step before setting enabled to LOW. I assume the current is required to accurately hold the spindle vs inertia and magnetic flux.

 

	  bool enabled=false;
	 
	  // decrement the number of steps, moving one step each time:
	  while (steps_left > 0)
	  {
	    unsigned long now = micros();
	    // move only if the appropriate delay has passed:
	    if (now - this->last_step_time >= this->step_delay)
	    {  
	      // get the timeStamp of when you stepped:
	      this->last_step_time = now;
	      // increment or decrement the step number,
	      // depending on direction:
	      if (this->direction == 1)
	      {
	        this->step_number++;
	        if (this->step_number == this->number_of_steps) {
	          this->step_number = 0;
	        }
	      }
	      else
	      {
	        if (this->step_number == 0) {
	          this->step_number = this->number_of_steps;
	        }
	        this->step_number--;
	      }
	      // decrement the steps left:
	      steps_left--;
	      // step the motor to step number 0, 1, ..., {3 or 10}
	        stepMotor(this->step_number % 4);
	        if(!enabled) {
	          analogWrite(enablePin1, 255);
	          analogWrite(enablePin2, 255);
	        }
	    //    analogWrite(enablePin1, (this->step_number % 2)?0:255);
	    //    analogWrite(enablePin2, (this->step_number % 2)?255:0);
	        enabled=false;
	    }
	  }
	  delay(10); <<<<
	  analogWrite(enablePin1, 0);
	  analogWrite(enablePin2, 0);
	

Link to comment
Share on other sites

Also the final issue is step position - as the power is off it's easy to knock the stepper to a point where it will jump following the next enable=high. That can be as simple as rotating the stepper or a shift in the force to the gearbox shaft. So the refocusing between exposures may find that the focus jumps a few steps on powering up again.

 

I probably have my calculations wrong but .. if you looked at the spec, then 3.8*0.67= 2.55W/coil = ~5W in total.

Chopper driver is running 12V with 670mA (chopped coils 2x 8W max is likely to be less on average, say 2x5W=10W).
L289 will put in 9V*2A (2x18W=36W) or 12V*2A (2x24W=50W) hence the heat levels. If you look at when it was running at 5V and no real heat build up, 5V 2A (2x10W=20W)
DRV8825 if limited using the pot to 670mA would be 9V 670mA = 2x6W (12W) or 12V 670mA =2x8W (16W)

So looking at that (even if the values are wrong - they're relative perhaps) and so limiting the current has a massive effect on heating.

 

Link to comment
Share on other sites

So.. measuring the current for the coil isn't a straightforward multimeter in series.

Instead.. you have to measure over a known resistance - well the sensing resistor on the motherboard is just that and the Analogue ADC lines are connected to them.

This site has an interesting program: http://www.elecrow.com/wiki/index.php?title=Motor%26Stepper_Shield

Drive Current Measurement

When using the shield to drive motors, sometimes you will want to get the actual drive current, for example, if the DC motors get locked by something, the drive current will get very large, maybe destroy the platform and DC motors. There are 2 current sample resistor on the motor shield, with resistance 0.5 ohm, with these resistor you can easily get the driver curernt.

So I've adapted it for my pins:

    // Define the motor_1 direction;
	    digitalWrite(dirA, HIGH);   
	    digitalWrite(dirB, HIGH);
	    digitalWrite(pwmA, HIGH);
	    digitalWrite(pwmB, HIGH);
	   //  Define the motor_1 speed;
	    //analogWrite(9,100);
	//    digitalWrite(9, HIGH); 
	    
	//    // Define the motor_1 direction;    
	//    digitalWrite(, HIGH); 
	//    digitalWrite(13, LOW); 
	//    //  Define the motor_1 speed;
	//    //analogWrite(10,150);
	//    digitalWrite(10, HIGH); 
	    
	    delay(1000); //wait for one second;
	    //Detect the drive current;
	    
	    int sensor1= analogRead(A4);
	    int sensor2= analogRead(A5);
	    float motor1_current=(float)sensor1/1024*5/0.5;
	    float motor2_current=(float)sensor2/1024*5/0.5;
	    Serial.print("Drive current of motor_1 is: ");
	    Serial.println(motor1_current);
	    Serial.print("Drive current of motor_2 is: ");
	    Serial.println(motor2_current);
	    delay(4000);               // wait for 4 seconds
	    // disable
	    digitalWrite(dirA, LOW);   
	    digitalWrite(dirB, LOW);
	    digitalWrite(pwmA, LOW);
	    digitalWrite(pwmB, LOW);
	

Link to comment
Share on other sites

Well that lost part of my update. The R3 shield uses A0 and A1 for sensing.

Unplugged Vin gives

Drive current of motor_1 is: 0.16
	Drive current of motor_2 is: 0.16
	Drive current of motor_1 is: 0.16
	Drive current of motor_2 is: 0.16
	Drive current of motor_1 is: 0.16
	Drive current of motor_2 is: 0.16

9V Vin gives

Drive current of motor_1 is: 3.47
	Drive current of motor_2 is: 3.34
	Drive current of motor_1 is: 3.29
	Drive current of motor_2 is: 3.17
	Drive current of motor_1 is: 3.25
	Drive current of motor_2 is: 3.14
	Drive current of motor_1 is: 3.21
	Drive current of motor_2 is: 3.10
	Drive current of motor_1 is: 3.20
	Drive current of motor_2 is: 3.10
	Drive current of motor_1 is: 3.15
	Drive current of motor_2 is: 3.04
	Drive current of motor_1 is: 3.16
	Drive current of motor_2 is: 3.06

Hmm this doesn't look right considering the driver chip manages 2A max per coil...

12V Vin gives

Drive current of motor_1 is: 4.83
	Drive current of motor_2 is: 4.66
	Drive current of motor_1 is: 4.59
	Drive current of motor_2 is: 4.43
	Drive current of motor_1 is: 4.46
	Drive current of motor_2 is: 4.31
	Drive current of motor_1 is: 4.38
	Drive current of motor_2 is: 4.24
	Drive current of motor_1 is: 4.34
	Drive current of motor_2 is: 4.19
	Drive current of motor_1 is: 4.32
	Drive current of motor_2 is: 4.18

.. that would be 50W..

So I think there's something afoot with the calibration - possibly it's only designed to measure motors rathe than coils.. but you'd expect it non-stepping to measure the current just as it would do a motor attached (no stepping).

 

 

 

Link to comment
Share on other sites

So checking the documentation for R3 and the L298 (outputs -1 to +2V), the R3 output goes through a component that then (as documented) means it's calibrated to 3.3V = 2A.

The fun is that some Arduino boards have a default analogue reference voltage of 3.3V and some have 5.0V. So the max scale of a analogRead() = 1024 can mean 3.3V or 5V depending on the Arduino board (not the motor board). However for the UNO it's 5V. So when analogRead(A0) = 1024 it's reading 5V.

So it's just a little matter of scaling.

	    
	    int sensor1= analogRead(A0);
	    int sensor2= analogRead(A1);
	    // documentation says 3.3 = 2A calibrated on R3 motor board.
	    // but the analogue reference is 5V on the UNO.
	    // so a value of 1024 = 5V for the UNO but 2.0 = 3.3V on on the motor board.
	    // 1V = (1024.0/5.0)
	    //  (3.3f/2.0f) number of volts per A.
	    // A = (sensor/(1024.0/5.0)) / (3.3/2.0f)
	   
	    float motor1_current=(float)sensor1 / (1024.0f/5.0f);
	    if(sensor1>0.0f)
	      sensor1 = sensor1 / (3.3f/2.0f);
	      
	    float motor2_current=(float)sensor2 / (1024.0f/5.0f);
	    if(sensor2>0.0f)
	      sensor2 = sensor2 / (3.3f/2.0f);
	          
	    Serial.print("Drive current of motor_1 is: ");
	    Serial.println(motor1_current);
	    Serial.print("Drive current of motor_2 is: ");
	    Serial.println(motor2_current);
	    delay(4000);               // wait for 4 seconds

Link to comment
Share on other sites

It seems that if you use the code<> then it cuts everything off after the first code..

And you get, no Vin connected:

 

Quote

Drive current of motor_1 is: 0.08


Drive current of motor_2 is: 0.08

 

Looking good.. you could say that this is 0.08=0V.. possibly.. but it's floating so I won't for the moment..

Next 9V

 

Quote

Drive current of motor_1 is: 1.81


Drive current of motor_2 is: 1.75
Drive current of motor_1 is: 1.75
Drive current of motor_2 is: 1.69
Drive current of motor_1 is: 1.72
Drive current of motor_2 is: 1.67

 

Looks good.. 15.5W/coil

12V gives:

 

Quote

Drive current of motor_1 is: 2.47


Drive current of motor_2 is: 2.38
Drive current of motor_1 is: 2.34
Drive current of motor_2 is: 2.26
Drive current of motor_1 is: 2.28
Drive current of motor_2 is: 2.20

 

Hmm.. Perhaps there's a little 10% error margin? Or there's a something odd.. however appears that the initial inrush from connecting the power.. (eek!)

 

Quote

Drive current of motor_2 is: 2.10


Drive current of motor_1 is: 2.17
Drive current of motor_2 is: 2.09
Drive current of motor_1 is: 2.16
Drive current of motor_2 is: 2.09
Drive current of motor_1 is: 2.16
Drive current of motor_2 is: 2.09
Drive current of motor_1 is: 2.16
Drive current of motor_2 is: 2.08
Drive current of motor_1 is: 2.16
Drive current of motor_2 is: 2.08
Drive current of motor_1 is: 2.15
Drive current of motor_2 is: 2.08

 

It seems to level out at about the 2.08-2.15 A..

Removing the pwm LOW to save power between loops.. it is solid at (note the 0.08 again..):

 

Quote

Drive current of motor_1 is: 2.16


Drive current of motor_2 is: 2.08
Drive current of motor_1 is: 2.15
Drive current of motor_2 is: 2.08
Drive current of motor_1 is: 2.12
Drive current of motor_2 is: 2.05

 

So that's 25.8W/coil... at 12V!!!!

Running 5V.. gives:

 

Quote

Drive current of motor_1 is: 0.87


Drive current of motor_2 is: 0.84
Drive current of motor_1 is: 0.85
Drive current of motor_2 is: 0.82
Drive current of motor_1 is: 0.85
Drive current of motor_2 is: 0.82
Drive current of motor_1 is: 0.85
Drive current of motor_2 is: 0.82

 

 

So that's 850mA at 5V = 4.25W/coil. No wonder it was cool running. 

So the L298 could use some power management... and the current limit setup to 670mA for the DRV8825 would mean although constant current modulated for the micro stepping.. Using 12V would mean 8W/coil and using 9V would mean 6W/coil. DRV8825 looks like the way to go.. (the DRV minimum 8.2V gives 5.4W/coil)

Just for reference using the manufacturer 'rated' voltage/current. 3.8V * 670mA = 2.546W/coil but that assumes a continuous current like the L298.

Happy now... 

EDIT: 0V is 0 through 5V is 1023.. not 1024.. that may explain the 0.08.. 

Link to comment
Share on other sites

Just for reference - some interesting (advanced) topics for PWM using hardware timers (rather than bit banging in code using digitalWrites with HIGH/LOW and delay between):

http://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

Interesting code in the comments section here: http://www.instructables.com/id/Arduino-Hardware-PWM-for-stepper-motor-drives/

The PWM gives you the pulse width, you can then scale that with the velocity of the drives - naturally that would only work for direct ardunio controlled stepping pulses (or enables). It then gets quite complicated as you need to put the delays for the L298 and the delays for the code to execute onto the hardware pin of the ardunio PIC. Then multiply that by the need to vary the frequency (compress the 'wave form' of all those steps) depending on the velocity of the stepper motor.

Also one last thing tonight that struck me. If you create an acceleration/velocity controller then you will need to have the capability of putting a breaking current in. That's possible if you can put 12V at 2A to slow the stepper faster than if you're stepper is limited to 670mA by the DRV for example. However I assume the voltage makes up for it in some way... curiosity.. 

 

Link to comment
Share on other sites

Woke up at 4am.. I have an idea for a micro-stepping in software.

1. As the sensing A0/A1 can provide samples of the current being provided.

2. Make a routine that runs as fast as possible that acts like a chopper circuit (most operate at 30-50kHz sampling/action frequency). Note it does not control the pulse width or frequency of pulses - it's there to control the current
2a. routine loops - sample A0/A1, compare A0/A1 value to the voltage value required in the micro stepping table at the position set - if lower enable power / if higher disable power. 
2b. the routine input a position on the table that's pre-scaled to the maximum current i.e. the value in the table is the sine wave of the voltage over the sensing resistor (V/R=I), the max normal holding current could be 670mA
2c. if need be for a short time there could be a overdrive current allowed to a set value to assist acceleration and more importantly deaccelleration for higher velocity handling.
2d. the sense sample values are made available for reading (although they can be updated at any time) - this helps maintain control and understand when the maximum velocity limit is reached.

The chopper limits the current by switching the power on/off rapidly (PWM) which allows 12V to be used on a 3.8V stepper without overheating it - it also acts to control the current for the micro stepping.

3. Second routine that operates at the pulse handling with an acceleration/velocity limit/de-accelation for the requested number of steps. The calling function can put a limit on speed but the routine itself has a governor based on the sensing sample values (A0/A1) passed. This is because as the motor speeds up, the back EMF gets higher that resists the current being driven. The slower the stepper the the more time the back EMF has to dissipate and so the more current is delivered. More current = more magnetic flux = more torque. So by allowing a limit to be set the calling routine can maximise torque by limiting speed. Next thing to point out - do away with the idea of pulse widths - the table is now the pulse driver so movement within the table back/forth results in a micro step, the jump in the table results in the size of step (full/half through to 1/32 but dictated by the speed of the chopper routine in point 2). The acceleration/de-acceleration are difficult and may require that overdrive to overcome the inertia with the load on the end of the shaft (back to torque hence the slow start and finish to provide maximum acceleration/braking).
3a. The calling routine gives the number of steps, this routine works out the planned acceleration/de-acceleration profile up to the passed limit parameter however the dynamic sensing can detect approaching the limit of current (current sensed drops = less torque) so when it reaches say a 75% limit it will then stop accelerating. It is at this time the overdrive could be used to assist the the de-acceleration. The capability of running with 12V that the chopper gives makes it easier to overcome the back EMF.

It's possible to have an emergency brake that enables overdrive and cancels the acceleration/velocity to zero until the current is at the overdrive max. At which point the routine can then reduce the overdrive until it's at the rated amount. The lack of stepping means the stepper will immediately attempt to brake with maximum force then return to rated current to idle. This means if the limit switches get engaged before the stepper whilst the stepper is at high velocity it will stop and clamp down as hard as it can to provide a maximum de-accelertion, then set to idle even zero current if available so that the stepper isn't attempting to step to a blocked position. 

3b. The routine needs to be called on a frequency (or preferably faster) that matches the velocity. This is because it needs to maintain the stepping at the rate required by the velocity.

 

So the two routines are a bit of a juggling act - the (2) chopper needs to called fast to control the current. The second routine needs to called at least as fast as each (micro)step of the current velocity.

There is a 3rd routine - for everything else.. the idea is that this gets executed when the system has time... this is where the I/O such as I2C or serial for controlling.. and the routine that simulates the these calls to move/seek to different positions (only called once the (2) has finished.

To test the idea I'll make it into a program, use the loop but with a counter. Every loop the chopper(2) routine gets called, every 100 loops the stepper(3) routine gets called and every 10000 the everything else loop (3) gets called. The idea being is that the program loop will operate at the maximum speed of the UNO (minus interrupts).

Then if that works I'll switch the routines to timer interrupts and see if I can operate in the background on those .. possibly attempt to use the hardware PWM (although it's not that controllable).

 

Link to comment
Share on other sites

I had a spare couple of hours this morning and created a software chopper/acceleration based stepper controller program:

 

	/* Stepper movement plan
	             .............................. speedLimit (maximises torque)
	             .............................. (dynamic) currentLimit
	               /                         \
	              /                           \
	             /                             \
	       -----+                               +----=
	       [<mt>|<-----a------>|<------d------->|<mt>] maxTorqueMargins/accel/deaccel
	       [<--------------requestedSteps----------->]
	
	*/

 

Interesting that looking at it at the moment I'm getting 10,000 loops/sec so that's 'chopping' at 10kHz without using hardware timers.

Quote

For a 16 MHz Arduino the ADC clock is set to 16 MHz/128 = 125 KHz. Each conversion in AVR takes 13 ADC clocks so 125 KHz /13 = 9615 Hz. That is the maximum possible sampling rate, but the actual sampling rate in your application depends on the interval between successive conversions calls.

So the application may call ADC sampling at 10kHz the real sampling rate is clocked at 9kHz?. Still better than nothing! However : http://yaab-arduino.blogspot.fr/2015/02/fast-sampling-from-analog-input.html

This means it's possible to increase the sample rate, however I'd expect the has an impact on the performance of normal loops. So.. the results of using the linked register prodding:

%210 <-- bit numbers
%001 615kHz sample rate = 20kHz looping (chopping)
%101 38kHz sample rate = 10kHz looping (chopping)
%110 19kHz sample rate = 6.5kHz looping (chopping)
%111 9.6kHz sample rate = 6.5kHz again..

Seems odd that you get a faster rate you get a faster loop.. perhaps the analogRead() call blocks (waits) for the next ADC conversion as dictated by it's clocking.. %001 max speed it is! I think I can cope with 20kHz chopping.. that's fast as the chopping in the DRV8825! I had to double check that.. and I hope that is right!

Reading the article further.. it appears I'm right, there's an interrupt way of reading samples - letting the ADC 'run free', processing the ADC complete interrupts. This then simply updates the read global variables. I know that the rate of looping without ADC calls is just over 20kHz so I'm not likely to recover much in terms of time but what I will get is efficiency.

 

Link to comment
Share on other sites

I've almost completed this (running on the Arduino UNO) after catching a couple of hours here and there - although I don't have the stepper itself here (just the Uno).

The performance seems to be around 12kHz at the moment - that's chopping current, acceleration/deacceleration with dynamic current/velocity limiting and 32 microstepping. I hope to have a chance to run this with the stepper soon.

I still think it would be good to use the DRV simply because it's a known entity and runs comfortably at 20-30kHz chopping _but_ from my understanding the DRV doesn't have ramp control - so this work will simply add a layer on top of the DRV.

 

Link to comment
Share on other sites

If this were a telescope drive project I could see the need for high speed slewing - and thus benefits of ramping/accelleration. However, with a focus motor your critical movements are all going to be short (20-50 steps each?) and rarely do you need to rack the focuser from one end of travel to the other. The UNO/L293D combination I use on my scope is perfectly usable, the NANO/DRV8825 test circuit will run much faster if asked (but to little benefit for this application).

ChrisH

Link to comment
Share on other sites

12 hours ago, ChrisLX200 said:

If this were a telescope drive project I could see the need for high speed slewing - and thus benefits of ramping/accelleration. However, with a focus motor your critical movements are all going to be short (20-50 steps each?) and rarely do you need to rack the focuser from one end of travel to the other. The UNO/L293D combination I use on my scope is perfectly usable, the NANO/DRV8825 test circuit will run much faster if asked (but to little benefit for this application).

ChrisH

True! Part of it was - could it be done in software? (the inner geek) I'll get the DRV modules as it's a known/proven entity but it's interesting to understand the issues.

 

Link to comment
Share on other sites

Wow. Although I won't use my software micro stepping/chopping software driver (~12kHz) on the final focuser - the result is at 12V the stepper is as cold as it is at 5V. So I think this could work nicely.

Instead of a tick, tick, tick for each step.. it's more screech, screech, screech as the chopper cuts in plus the sound makes a repeating cycling noise (the micro stepping).

 

Link to comment
Share on other sites

I've ordered a set (5x) DRV8825 stepper controllers, the UBEC for the 13.5>5V power step down, I've also ordered a very awkward sized 7mm x 6mm flexible shaft coupler for the pentax to stepper.

I'll pop into a maplin or another local electronics shop and pick up a set of 100uF capacitors. Just need to get a set of screws for the stepper NEMA11 bracket (should have ordered the matching ones but hey..).

 

Link to comment
Share on other sites

Ok I've been playing with the TFT screen today but.. also researching the driver area of this focuser whilst I wait for things to be delivered.

There's a couple of bits that need doing:

1. INDI focuser driver - this should be easy to adapt the moonlite indi driver so that it supports a connection to an ardunio board with a protocol. It needs updating with 32 step, no need for full/half stepping here. The limit check switches will also need programming in.

2. ARDUNIO firmware - there's a "moonlite clone" software that can be adapted however it's for 4 step unipolar steppers. This will need some updating but given the experience with the software I don't see this taking too long. This will drive a DRV8825 stepper controller rather than software current drive/microstep. I also want to put the limit check switches in here.

Annoyingly it looks like I will need to RMA my C2 as the HDMI port has stopped working (sounds like a dry solder joint) but in the mean time I have my ubuntu indi install in a VM on the Mac so development can continue.

 

Looking at the Ardunio code it uses the Accel stepper library. Which by itself is interesting - it's very similar to mine but doesn't cope with sensing current and limiting the acceleration to provide a minimum torque. I use a distance to stop is easily calculated in realtime  s = (velocityEnd-velocityStart)/2a at every loop so that it knows when the current limit or defined limit impacts the possible deceleration. I've also put in margins so that a large load is given chance to start or stop moving at maximum torque. One thing nether of us have done is to look at micro-stepping to the nearest full step then running full stepping for speed until near the end at which point revert to micro stepping.

That's the annoying bit - unless a resistor is added in the coil supply so that it can be used as a sensing resistor, the only time the ardunio sees a problem with the stepper is when the DRV8825 sets the FAULT pin to high.

However the DRVs are due on friday ... so I want to get a INDI stepper motor driver done before it's arrival. I'll mimic the moonlite (just set to FULL step but running at 1/32) so then all I need todo is run the ardunio code specific for the 1/32 and DRV... then later redo the driver to allow stepping changes via the UI.

 

Link to comment
Share on other sites

The DRV8825 arrived late yesterday. Stealing a 16V 220uF from an old DVD rom drive I have in bits for parts I jerry rigged up all the components. I'll get some strip board and solder up a proper version but.. it works with the arduino driver I've written!

Although the pins sit nice on the digital I/O 0-7 the arduino design uses the D0 and D1 ports for RX/TX serial that links the USB-UART usually used for sketch downloads and the Serial library. Not a problem just shifted it up for now.

From the data sheets, Texas Instruments demonstrate how to read the sense resistors using a multi meter by using logic ground and the sense pins (two next to each other are connected making it a handy probe point). With my 670mA/coil max and the Pololu DRV8825 carrier board having 0.1ohm resistors it's easy to calculate the required voltage being 0.34V. Using the multimeter on those points and turning the variable resistor whilst at stand still but enabled (can't turn the stepper shaft) it's possible to set the current limit.

The proof is in the pudding - the stepper is cool/cold to touch running at both full step and 1/32 step for long periods.

The DRV has a 45deg home angle that is step1 for full stepping and step 17 for micro stepping at 1/32. This means when you switch on the power to the stepper will be the home angle. Something to think about if you park your focuser and power down.

Speedwise - the DRV chip can cope with the ardinuo nicely. The DRV does have a longer signal timing after going high and after low (1.9us) so a minimum time is basically a delay(2) is needed between them and after. At full step the stepper rotates with the 100:1 gearbox giving a decent 1:1 focuser speed. At 1/32 micro step the 100:1 gearbox shaft turns very very slowly.  I will see how fast by counting the rate at which the steps are output from the arduino but from the stepper I think that's about 30rev/min max speed.

Just to recap with 80mm focuser travel, a 1:1 focuser covering that in about 2.6 turns of the knob:  80mm travel/2.6 turns = 30mm per revolution of the 1:1 focuser, with the 100:1 gearbox that's 30/100 =  0.3 mm per stepper revolution. So it seems I'm out by a factor of 10 some where (perhaps original calculations)..

Full step:  0.3mm per rev / 200 full steps per rev =  0.0015 mm per full step (1.5 microns) with 53333 steps full focuser travel

1/32 microstep: 0.3mm per rev / (200 full steps per rev * 32 microsteps per full step) =  0.0000468 mm per 1/32 micro step (0.048 microns) or 1.7 million steps for the focuser travel may take a while...

Now given there's a 1.5 degree backlash in the gearbox (max) and even more on the focuser... the important point here is being able to control that. Fine focus for solar is very important :D

 

Link to comment
Share on other sites

Well... S has been ill so I've been juggling that and didn't get out to maplins to get the bits.. but I have the indiserver with a moonlite focuser using my ardunio program to drive the DRV and stepper.

It's a little slow - I'm not sure if that's INDI, Kstars (i.e. you push the focus in button and it takes a while for it to then go through the remote indiserver through the serial connection at 9600 baud and finally start stepping.

Also it may be I'm not used to Ekos (kstars) and was expecting immediate response.

 

Either way the driver works :D and the UBECs (voltage step downs) have arrived :D so just now need to get the bracket made and the coupler delivered..

 

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. By using this site, you agree to our Terms of Use.