Site Tools


projects:cnc:4th_axis

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
projects:cnc:4th_axis [2025/04/11 17:02] – [Arduino software using the FastAccelStepper library] adminprojects:cnc:4th_axis [2025/04/15 00:07] (current) – [A manual controller for a spindle motor] admin
Line 4: Line 4:
 Movement control is done using a potentiometer and button. With the potentiometer the speed and direction can be set, while the button allows to rotate at a specific angle, after which the motor stops. Movement control is done using a potentiometer and button. With the potentiometer the speed and direction can be set, while the button allows to rotate at a specific angle, after which the motor stops.
  
-After powering up, it is required to either rotate the potentiometer to the center position (speed: 0) or press the button to rotate exactly 90 degrees. This is done to make sure that the spindle initially only rotates, when the user explicitly acknowledges. Afterwards the button can be pressed at any moment to rotate another 90 degrees angle further. While the stepper motor is in pause state, to commence moving at a certain speed, it is necessary to first move the potentiometer to the center position from which the direction and speed can than be set accordingly.+After powering up, it is required to either rotate the potentiometer to the center position (speed: 0) or press the button to rotate exactly a configured amount of degrees. This is done to make sure that the spindle initially only rotates, when the user explicitly acknowledges. Afterwards the button can be pressed at any moment to rotate the same amount of degrees further. A BCD-switch is used to configure the angle. While the stepper motor is in pause state, to commence moving at a certain speed, it is necessary to first move the potentiometer to the center position from which the direction and speed can than be set accordingly.
  
 Project summary: Project summary:
-  * Code runs on an arduino (nano).+  * Code runs on an arduino Nano V3.0.
   * Connected to an [[https://www.mechapro.de/shop/Schrittmotor-Steuerungen/Einzelachsen-Takt-Richtung-offene-Bauform/HP-Step-pro-1-Kanal-4A-Mikroschritt-Endstufe::135.html|HP-Step.pro stepper controller]].   * Connected to an [[https://www.mechapro.de/shop/Schrittmotor-Steuerungen/Einzelachsen-Takt-Richtung-offene-Bauform/HP-Step-pro-1-Kanal-4A-Mikroschritt-Endstufe::135.html|HP-Step.pro stepper controller]].
   * With a 4k7 potentiometer on A0, direction and speed can be set.   * With a 4k7 potentiometer on A0, direction and speed can be set.
-  * When using a button on D8 (to GND), the axis rotates certain degrees (currently hard-coded as 90 degrees) in the direction it was rotating previously and stops afterwards, regardless of the potentiometer setting.+  * When using a button on D8 (to GND), the axis rotates certain degrees (which can be configured with a BCD switch) in the direction it was rotating previously and stops afterwards, regardless of the potentiometer setting.
   * To start motor movement, either press the switch, or move the potentiometer to the center position, after which the motor will rotate continuously when moving the potentiometer any further.   * To start motor movement, either press the switch, or move the potentiometer to the center position, after which the motor will rotate continuously when moving the potentiometer any further.
-  * If the indicator led is blinking fast, it will indicate that the potentiometer need to be positioned at the center first. This is to prevent any unwanted motor rotation.+  * If the indicator led is blinking fast, it will indicate that the potentiometer need to be positioned at the center first. This is to prevent any motor rotation you probably do not want. 
 +  * As a latest addition, a 2-digit BCD-switch is connected to inputs A1-A5,D2,D3,D10 with the common of the switches to ground. With this switches the rotation angle can be set. The arduino internal pull-up is used at these ports, so no additional resistors are required
  
 The documentation of the stepper controller can be found here: [[https://www.mechapro.de/pdf/hpsteppro_doku_2016_04.pdf | hpsteppro_doku_2016_04.pdf]] The documentation of the stepper controller can be found here: [[https://www.mechapro.de/pdf/hpsteppro_doku_2016_04.pdf | hpsteppro_doku_2016_04.pdf]]
Line 24: Line 25:
 | CN4,5  | /Off  | Power off stepper drivers  |  5  | | CN4,5  | /Off  | Power off stepper drivers  |  5  |
 | CN4,6  | /Sleep  | Reduces motor current to 25% from nominal during low state  |  6  | | CN4,6  | /Sleep  | Reduces motor current to 25% from nominal during low state  |  6  |
-| CN4,7 + CN4,8  | +5v  | This pin is not connected but rewired to the internal 5v supply of the stepper controller and used to power the Arduino nano standalone   +5v  |  +| CN4,7 + CN4,8  | +5v  | This pin was originally not connected (NC) and now repurposed to power the arduino controller from the internal 5v supply of the stepper controller  |  +5v  |  
 | CN4,9 + CN4,10  | GND  | Ground  |  GND  | | CN4,9 + CN4,10  | GND  | Ground  |  GND  |
 | CN7.5  | /Reset  | Reset  |  13  | | CN7.5  | /Reset  | Reset  |  13  |
  
 ==== Arduino software using the FastAccelStepper library ==== ==== Arduino software using the FastAccelStepper library ====
-<code c>+<code cpp>
 //---------------------------------- //----------------------------------
 // https://github.com/gin66/FastAccelStepper/blob/master/src/FastAccelStepper.h // https://github.com/gin66/FastAccelStepper/blob/master/src/FastAccelStepper.h
 // https://github.com/gin66/FastAccelStepper // https://github.com/gin66/FastAccelStepper
 +// FastAccelStepper documentation:
 +// https://github.com/gin66/FastAccelStepper/blob/master/extras/doc/FastAccelStepper_API.md
 // //
 // Arduino Hardware settings: // Arduino Hardware settings:
 // Processor: ATmega328P (regular, not the Old bootloader) // Processor: ATmega328P (regular, not the Old bootloader)
-// Board: Arduino Nano+// Board: Arduino Nano 3.0
 // Port: /dev/ttyUSB0 // Port: /dev/ttyUSB0
 // //
 // Dependency: // Dependency:
-// Install the FastAccelStepper library by Jochen Kiemes (currently version 0.31.5)+// Install the FastAccelStepper library by Jochen Kiemes (currently version 0.31.6)
  
    
Line 54: Line 57:
    
    
-// pins numbers+// pin numbers definition: 
 +// Number corresponds to name Dxx as on silkscreen and used in the function 
 +// digitalWrite(pin_number). For example: 
 +// 13 corresponds to D13, 9 corresponds to D9
 const uint8_t rst_pin = 13; // rst pin for HP-Step.pro const uint8_t rst_pin = 13; // rst pin for HP-Step.pro
 const uint8_t rxd_pin = 12; // rx pin for some kind of tty communication const uint8_t rxd_pin = 12; // rx pin for some kind of tty communication
Line 66: Line 72:
 const uint8_t led_pin =  7; // signal led to indicate angular mode connected between D7 and GND const uint8_t led_pin =  7; // signal led to indicate angular mode connected between D7 and GND
    
-const uint8_t adj_pin = A0; //Analog pin with 4k7 lin. potentiometer+// A0 corresponds with a #define to decimal 14, PIN_A0 is similar but a const uint instead. 
 +// All input pins use the internal pull-up. 
 +const uint8_t adj_pin = PIN_A0; // Analog pin A0 with 4k7 lin. potentiometer
 const uint8_t rot_pin =  8; // connect a button (switch to ground) to rotate (90) degrees const uint8_t rot_pin =  8; // connect a button (switch to ground) to rotate (90) degrees
- + 
 +// 2-digit bcd-wheel to set rotation angle. Common is connected to ground 
 +const uint8_t bcd10 = PIN_A1; 
 +const uint8_t bcd20 = PIN_A2; 
 +const uint8_t bcd40 = PIN_A4; 
 +const uint8_t bcd80 = PIN_A3; 
 +const uint8_t bcd01 = PIN_A5; 
 +const uint8_t bcd02 = 2; 
 +const uint8_t bcd04 = 10; 
 +const uint8_t bcd08 = 3; 
 // stepper definitions // stepper definitions
 const uint8_t stp360 = 200; // number of steps for stepper motor to rotate 360 degrees const uint8_t stp360 = 200; // number of steps for stepper motor to rotate 360 degrees
    
 // connected geometry (if stepper has a gear with another gear) // connected geometry (if stepper has a gear with another gear)
-const uint8_t lg = 60; // number of teeth of large gear +const uint8_t pg = 60; // number of teeth of primary gear 
-const uint8_t sg = 10; // number of teeth of small gear+const uint8_t sg = 10; // number of teeth of secondary gear 
 +const uint8_t steps_for_3deg = stp360 * 4 * (pg/sg) / 120; // smallest exact step is 3 degrees and corresponds with 40 clk pulses
    
 // storage for potentiometer samples, rotation direction, blink time // storage for potentiometer samples, rotation direction, blink time
 static uint16_t pos[NUM_SAMPLES]; static uint16_t pos[NUM_SAMPLES];
-static uint8_t n; // samples array index +static uint8_t n;                  // samples array index 
-static uint64_t LedPrevMillis = 0;        // will store last time LED was updated+static uint32_t LedPrevMillis = 0; // will store last time LED was updated
 enum patterns {LED_OFF, BLINK_SLOW, BLINK_FAST, LED_ON}; enum patterns {LED_OFF, BLINK_SLOW, BLINK_FAST, LED_ON};
 static enum patterns led_ptrn = BLINK_FAST; static enum patterns led_ptrn = BLINK_FAST;
Line 90: Line 109:
  
 // button debounce // button debounce
-const uint8_t min_debounce_ms = 100; // 100 ms debounce time+const uint8_t min_debounce_ms = 20; // 20 ms debounce time
 uint32_t btnPrevMillis; uint32_t btnPrevMillis;
    
Line 113: Line 132:
   digitalWrite(off_pin,LOW);   digitalWrite(off_pin,LOW);
   pinMode(rot_pin,INPUT_PULLUP);   pinMode(rot_pin,INPUT_PULLUP);
- + 
 +  // initialization for bcd wheel 
 +  pinMode(bcd10,INPUT_PULLUP); 
 +  pinMode(bcd20,INPUT_PULLUP); 
 +  pinMode(bcd40,INPUT_PULLUP); 
 +  pinMode(bcd80,INPUT_PULLUP); 
 +  pinMode(bcd01,INPUT_PULLUP); 
 +  pinMode(bcd02,INPUT_PULLUP); 
 +  pinMode(bcd04,INPUT_PULLUP); 
 +  pinMode(bcd08,INPUT_PULLUP); 
   Engine.init();   Engine.init();
   stepper = Engine.stepperConnectToPin(clk_pin);   stepper = Engine.stepperConnectToPin(clk_pin);
Line 132: Line 161:
    
 void move_degrees(uint32_t angle) { void move_degrees(uint32_t angle) {
 +  static int8_t step_counter = 0; // compensation counter. Based on consecutive triple calls give integer accuracy.
   stepper->stopMove();   stepper->stopMove();
   while (stepper->isRunning()); // wait for the motor to come to a full stop   while (stepper->isRunning()); // wait for the motor to come to a full stop
-  int32_t steps = 200 * 4 * (lg/sg) / (360/angle)+   
-  int32_t final_pos stepper->targetPos() + stp_direction steps;+  // formula: angle * 200 * 4 * (ratio) / 360 = 40 * angle 
 +  // where ratio = 60/10 
 +  uint16_t steps    = steps_for_3deg * angle / 3
 +  uint8_t remainder steps_for_3deg * angle % 3; 
 + 
 +  // Motor cannot step 13.3333 or 26.6666 steps. Therefore only integer values 
 +  // are used and a compensation is added once every three calls. 
 +  // 0 -> 13.333 -> 26.666 -> 40 will then become: 0 -> 13 -> 27 -> 40 
 +  // for 1 degree angle rotations. All larger (integerrotations are then just 
 +  // a multiple of this schema. 
 +  switch (remainder) { 
 +    case 0: 
 +      // leave result unchanged 
 +      break; 
 +    case 1: 
 +      steps += (stp_direction == FORWARD) ? (step_counter == 1) : (step_counter == 2); 
 +      break; 
 +    case 2: 
 +      steps += (stp_direction == BACKWARD) ? (step_counter != 1) : (step_counter != 2); 
 +      break; 
 +  } 
 + 
 +  // precise movement based on natural numbers
   stepper->setSpeedInHz(MAXSPEED);   stepper->setSpeedInHz(MAXSPEED);
-  stepper->move(stp_direction * steps); // now move +/- 90 degrees +  stepper->move(stp_direction * (int32_t)steps); // cast for negative sign, move +/- 90 degrees 
-  while ( stepper->isRunning()); // wait for the motor to come to a full stop+ 
 +  while (stepper->isRunning()); // wait for the motor to come to a full stop 
 + 
 +  // correction counter since we are not using floating point 
 +  if (step_counter >= 2 && stp_direction == FORWARD) { 
 +    step_counter = 0; 
 +  } else if (step_counter <= 0 && stp_direction == BACKWARD) { 
 +    step_counter = 2; 
 +  } else { 
 +    step_counter += (stp_direction == FORWARD); 
 +  }
 } }
    
Line 177: Line 239:
   return calc_average();   return calc_average();
 } }
- + 
 +uint8_t read_bcd_wheel(void) { 
 +  return 10 * (!digitalRead(bcd10) |  
 +               !digitalRead(bcd20) << 1 | 
 +               !digitalRead(bcd40) << 2 |  
 +               !digitalRead(bcd80) << 3) + 
 +              (!digitalRead(bcd01) | 
 +               !digitalRead(bcd02) << 1 | 
 +               !digitalRead(bcd04) << 2 | 
 +               !digitalRead(bcd08) << 3); 
 +
 uint16_t calc_average(void) { uint16_t calc_average(void) {
   uint16_t sum = 0;   uint16_t sum = 0;
Line 240: Line 313:
 } }
    
-void handle_angular_rotation(uint16_t angle, uint16_t *avg, uint16_t *avg_prev) {+void handle_angular_rotation(uint16_t *avg, uint16_t *avg_prev) {
   led_ptrn = LED_ON;   led_ptrn = LED_ON;
   handle_led_ptrn();   handle_led_ptrn();
Line 247: Line 320:
   uint16_t pos = analogRead(adj_pin);   uint16_t pos = analogRead(adj_pin);
   if (get_direction(pos) != STOP) stp_direction = get_direction(pos);   if (get_direction(pos) != STOP) stp_direction = get_direction(pos);
-  move_degrees(90); // use direction from last movement+  move_degrees(read_bcd_wheel()); // use direction from last movement
   rotation_mode = ANGULAR;   rotation_mode = ANGULAR;
 } }
Line 262: Line 335:
 { {
   uint16_t blink_interval;   uint16_t blink_interval;
-  
-  if (led_ptrn == LED_OFF || led_ptrn == LED_ON) { 
-    digitalWrite(led_pin, led_ptrn == LED_OFF ? LOW : HIGH); 
-    return; 
-  } 
    
   switch (led_ptrn) {   switch (led_ptrn) {
 +    case LED_OFF:
 +      digitalWrite(led_pin, LOW);
 +      return;
 +    case LED_ON:
 +      digitalWrite(led_pin, HIGH);
 +      return;
     case BLINK_SLOW:     case BLINK_SLOW:
       blink_interval = 1000;       blink_interval = 1000;
Line 302: Line 376:
   }   }
    
-  /* debounce + rotate 90 degrees if button pressed */+  /* debounce + rotate certain degrees if button pressed */
   if (millis() - btnPrevMillis > min_debounce_ms) {   if (millis() - btnPrevMillis > min_debounce_ms) {
     if (!digitalRead(rot_pin)) {     if (!digitalRead(rot_pin)) {
-      handle_angular_rotation(90, &avg, &avg_prev);+      handle_angular_rotation(&avg, &avg_prev);
       while (!digitalRead(rot_pin)); // wait for button release       while (!digitalRead(rot_pin)); // wait for button release
       btnPrevMillis = millis();       btnPrevMillis = millis();
projects/cnc/4th_axis.1744383773.txt.gz · Last modified: 2025/04/11 17:02 by admin