Arduino as a measuring system - but how to stop the loop?

Hello,

I have been working on a project that is re-purposing a 3D printer into a measuring device. The goal right now is to make a number of measurements every 1mm along a single path. The Z axis would move down at a slow speed until the touch probe touches the surface, at this pioint the X, Y and Z axis co-ordinates are printed to serial print. The Z axis would then move up (zretract), move along X axis 1mm and repeat.

I also have 2 joysticks in the system that allow me to position the probe at the desired start point. Once in the correct position, push the button (which is incopertaed into one of the joysticks) and the sequence starts.

This all works well (so I know the wiring is correct), except the sequence does not stop after the desired number of measurement points. Currently the code is written to perform 3 measurement points. I think it is looping the sequence over and over, so making 3 measurements, followed by another 3 and so on.

I have tried using various methods to stop the sequence, using examples but with no impact.

Any advice please?

Hardware is:
Arduino Uno
CNC Shield V3 & A4988 Stepper Driver
The stepper motors are from an Artillery Genius Pro
The probe is a BL Touch Probe
Joysticks: XY Axis Joystick Module - Thumbstick - Arduino Experimentation Module - UK | eBay

Here is the code without an attempt to stop the loop.

#include <SpeedyStepper.h>
#include <ezButton.h>
#include <Servo.h>

// Stepper motor objects
 SpeedyStepper stepperX;
 SpeedyStepper stepperY;
 SpeedyStepper stepperZ;

// Servo object for BLTouch
 Servo blTouchServo;   //servo object to control a servo
 int Touch = 0;        // state of blTouch
 // BLTouch control pins
 const int blTouchPin = 12;      //  White wire output to Digital pin 12
 const int blTouchServoPin = 11; // Yellow wire for probe wire control to Digital Pin 11

// Button for starting the sequence
 ezButton startButton(13); // Button connected to pin 13 from X Y Joystick Module

// Joystick pins
 const int joyXPin = A0;
 const int joyYPin = A1;
 const int joyZPin = A2;

// Motor driver pins 
 const int stepXPin = 2, dirXPin = 5;
 const int stepYPin = 3, dirYPin = 6;
 const int stepZPin = 4, dirZPin = 7;
 const int STEPPERS_ENABLE_PIN = 8;

// Configurable Parameters
 const float xStepDistance = 1.0; // Distance to move in X-axis per step (mm). 
 const float zRetractDistance = 1.0; // Distance to retract in Z-axis (mm)
 const float xTotalDistance = 3.0; // Total X-axis distance to measure (mm)
 const int maxSpeedX = 50; // Max speed for X-axis stepper (mm/second)
 const int maxSpeedY = 10; // Max speed for Y-axis stepper (mm/second)
 const int maxSpeedZ = 10;  // Max speed for Z-axis stepper (mm/second)
 const int maxSpeedZProbe = 5; // Max speed for Z-axis stepper when probing (mm/second)
 const int maxAccelX = 500;  // Max acceleration for X-axis stepper (mm/second/second)
 const int maxAccelY = 500;  // Max acceleration for X-axis stepper (mm/second/second)
 const int maxAccelZ = 500;  // Max acceleration for X-axis stepper (mm/second/second)

// Joystick sensitivity
 const int joystickThreshold = 20; // Sensitivity threshold
 const int joystickMaxSpeed = 100;  // Max speed for joystick control (mm/second)

// Absolute position variables
 float absX = 0.0, absY = 0.0, absZ = 0.0;

 // Correction factors if needed
  const float FactorX = (5/1);  // Correction factor for X axis. 
 // const float FactorY = (5/1);  // Correction factor for Y axis. 
  const float FactorZ = (5/1); // Correction factor for Z axis. 

 // Calculating steps per mm 
 #define PI 3.1415926535897932384626433832795
 const int MotorStepsPerRev = 200; // Motor Steps per revolution for all steppers
 const int MicroStep = 16;   // Microstepping for all drivers. 
 const int ToothPitch = 2; //Tooth to Tooth pitch for X and Y in millimeters
 const int PulleyTeeth = 20; //No of Teeth for pulleys on X and Y. 
 const float PulleyPitch = (ToothPitch * PulleyTeeth)/(PI);  // Pulley pitch for X and Y in millimetres.
 const float StepsPermm = (MotorStepsPerRev * MicroStep)/(PulleyPitch * PulleyTeeth)*FactorX; // Step per mm for X and Y
 const int LeadScrewLead = 8; // Z Axis Lead screw lead (mm per revolution)
 const float StepsPermmZ = (MotorStepsPerRev * MicroStep)/(LeadScrewLead)*FactorZ; // Steps per mm for Z axis




void setup() {
  pinMode(STEPPERS_ENABLE_PIN, OUTPUT);

   // Initialize BLTouch servo
  blTouchServo.attach(blTouchServoPin); // Attaches the servo on the digital pin to the servo object
  pinMode(blTouchPin, INPUT_PULLUP); // May need resistor in circuit. Then remove PULLUP

  Serial.begin(9600);

  //De-bugging blTouch. Touch the probe, what happens?
 // while (true) {
   // int state = digitalRead(blTouchPin);
    //Serial.println(state);
    //delay(1000); // Slow down output for readability
 // }

 // connect and configure the stepper motor to there IO pins
 
 stepperX.connectToPins(stepXPin, dirXPin);
 stepperY.connectToPins(stepYPin, dirYPin);
 stepperZ.connectToPins(stepZPin, dirZPin);
 
 // enable the stepper motors
  digitalWrite(STEPPERS_ENABLE_PIN, LOW);

 // Initialize button
 startButton.setDebounceTime(50); // Debounce for button

// Show blTouch works
  deployProbe(); // Deploy probe at startup to show it works
  delay(500);
 //retractProbe(); // Retract probe at startup to show it works

  Serial.println("Setup complete. Use joysticks to position X, Y and Z.");
}

void loop() {//The measurements loop, i.e. do not finish when total X reached

 // Set max speeds for stepper motors. Can these be in setup?
 stepperX.setSpeedInMillimetersPerSecond(maxSpeedX);
 stepperY.setSpeedInMillimetersPerSecond(maxSpeedY);
 stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZ);

 // Set acceleration for stepper motors
 stepperX.setAccelerationInMillimetersPerSecondPerSecond(maxAccelX);
 stepperY.setAccelerationInMillimetersPerSecondPerSecond(maxAccelY);
 stepperZ.setAccelerationInMillimetersPerSecondPerSecond(maxAccelZ);

 // Set steps per millimetre
 stepperX.setStepsPerMillimeter(StepsPermm);    // Steps per millimetere for X axis
 stepperY.setStepsPerMillimeter(StepsPermm);    // Steps per millimetere for Y axis
 stepperZ.setStepsPerMillimeter(StepsPermmZ);    // Steps per millimetere for Z axis
 
 // Update button state
  startButton.loop();

// Joystick control for X, Y AND z axes
  int joyX = analogRead(joyXPin) - 512;
  int joyY = analogRead(joyYPin) - 512;
  int joyZ = analogRead(joyZPin) - 512;

  if (abs(joyX) > joystickThreshold) {
    int speedX = map(joyX, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperX.setSpeedInMillimetersPerSecond(speedX);
    stepperX.moveRelativeInMillimeters(speedX > 0 ? 10 : -10);
    absX += (speedX > 0 ? 10 : -10); // Update absolute position
  }

  if (abs(joyY) > joystickThreshold) {
    int speedY = map(joyY, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperY.setSpeedInMillimetersPerSecond(speedY);
    stepperY.moveRelativeInMillimeters(speedY > 0 ? 10 : -10);
    absY += (speedY > 0 ? 10 : -10); // Update absolute position
  }
  
  if (abs(joyZ) > joystickThreshold) {
    int speedZ = map(joyZ, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperZ.setSpeedInMillimetersPerSecond(speedZ);
    stepperZ.moveRelativeInMillimeters(speedZ > 0 ? 10 : -10);
    absZ += (speedZ > 0 ? 10 : -10); // Update absolute position
  }

  // Start sequence on button press
  if (startButton.isPressed()) {
    Serial.println("Sequence starting...");
    executeSequence();
  }
}

void executeSequence() {
  // Mark current position as (0, 0, 0)
   absX = 0.0;
   absY = 0.0;
   absZ = 0.0;
    Serial.print("Position: X=");
    Serial.print(absX);
    Serial.print(", Y=");
    Serial.print(absY);
    Serial.print(", Z=");
    Serial.println(absZ);


  
  int PositionsInX = xTotalDistance / xStepDistance; // Calculate total number of positions in X-axis to be measured

   for (int i = 0; i <= PositionsInX; i++) {
    // Move Z down until BLTouch is triggered
    Serial.println("Probing Z...");
    deployProbe();
    while (digitalRead(blTouchPin) == LOW) {
   
      stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZProbe); // Move Z down
      stepperZ.moveRelativeInSteps(1); //positive to get correct direction on stepper motor
      absZ -= 0.01; // Update absolute Z position
    }
  
    retractProbe();

      

    Serial.print("Position: X=");
    Serial.print(absX);
    Serial.print(", Y=");
    Serial.print(absY);
    Serial.print(", Z=");
    Serial.println(absZ);

    // Move Z up by retract distance
    stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZ); // Move Z up
    stepperZ.moveRelativeInMillimeters(-zRetractDistance); //negative to get correct direction on stepper motor
    absZ += zRetractDistance;

    // Move X by position distance for the next measurement
    stepperX.setSpeedInMillimetersPerSecond(maxSpeedX); //is it needed again here? If should I include acceleration again?
    stepperX.moveRelativeInMillimeters(xStepDistance); 
    absX += xStepDistance;

    delay(500); // Small delay for stability
  }

  Serial.println("Sequence complete.");
}

// Deploy the BLTouch probe
void deployProbe() {
  blTouchServo.write(10); // Adjust angle for deployment
  delay(500);
}

// Retract the BLTouch probe
void retractProbe() {
  blTouchServo.write(90); // Adjust angle for retraction
  delay(500);
}

//void blink() {
 // Touch = 1;

Here is a code with an attempt to stop the loop

#include <SpeedyStepper.h>
#include <ezButton.h>
#include <Servo.h>

bool sequenceInProgress = false; //Flag to indicate if sequence in progress

// Stepper motor objects
 SpeedyStepper stepperX;
 SpeedyStepper stepperY;
 SpeedyStepper stepperZ;

// Servo object for BLTouch
 Servo blTouchServo;   //servo object to control a servo
 int Touch = 0;        // state of blTouch
 // BLTouch control pins
 const int blTouchPin = 12;      //  White wire output to Digital pin 12
 const int blTouchServoPin = 11; // Yellow wire for probe wire control to Digital Pin 11

// Button for starting the sequence
 ezButton startButton(13); // Button connected to pin 13 from X Y Joystick Module

// Joystick pins
 const int joyXPin = A0;
 const int joyYPin = A1;
 const int joyZPin = A2;

// Motor driver pins 
 const int stepXPin = 2, dirXPin = 5;
 const int stepYPin = 3, dirYPin = 6;
 const int stepZPin = 4, dirZPin = 7;
 const int STEPPERS_ENABLE_PIN = 8;

// Configurable Parameters
 const float xStepDistance = 1.0; // Distance to move in X-axis per step (mm). 
 const float zRetractDistance = 10.0; // Distance to retract in Z-axis (mm)
 const float xTotalDistance = 3.0; // Total X-axis distance to cover (mm)
 const int maxSpeedX = 10; // Max speed for X-axis stepper (mm/second)
 const int maxSpeedY = 10; // Max speed for Y-axis stepper (mm/second)
 const int maxSpeedZ = 10;  // Max speed for Z-axis stepper (mm/second)
 const int maxSpeedZProbe = 5; // Max speed for Z-axis stepper when probing (mm/second)
 const int maxAccelX = 250;  // Max acceleration for X-axis stepper (mm/second/second)
 const int maxAccelY = 250;  // Max acceleration for Y-axis stepper (mm/second/second)
 const int maxAccelZ = 250;  // Max acceleration for Z-axis stepper (mm/second/second)

// Joystick sensitivity
 const int joystickThreshold = 200; // Sensitivity threshold
 const int joystickMaxSpeed = 100;  // Max speed for joystick control (mm/second)

// Absolute position variables
 float absX = 0.0, absY = 0.0, absZ = 0.0;

  // Correction factiors if needed
  const float FactorX = (5/1);  // Correction factor for X axis. This is correct
  //const float FactorY = (5/1);  // Correction factor for Y axis. This is correct
  const float FactorZ = (5/1); // Correction factor for Z axis. Might be correct

 // Calculating steps per mm 
 #define PI 3.1415926535897932384626433832795
 const int MotorStepsPerRev = 200; // Motor Steps per revolution for all steppers
 const int MicroStep = 16;   // Microstepping for all drivers. 
 const int ToothPitch = 2; //Tooth to Tooth pitch for X and Y in millimeters
 const int PulleyTeeth = 20; //No of Teeth for pulleys on X and Y. 
 const float PulleyPitch = (ToothPitch * PulleyTeeth)/(PI);  // Pulley pitch for X and Y in millimetres.
 const float StepsPermm = (MotorStepsPerRev * MicroStep)/(PulleyPitch * PulleyTeeth)*FactorX; // Step per mm for X and Y
 const int LeadScrewLead = 8; // Z Axis Lead screw lead (mm per revolution)
 const float StepsPermmZ = (MotorStepsPerRev * MicroStep)/(LeadScrewLead)*FactorZ; // Steps per mm for Z axis


void setup() {
  pinMode(STEPPERS_ENABLE_PIN, OUTPUT);

   // Initialize BLTouch servo
  blTouchServo.attach(blTouchServoPin); // Attaches the servo on the digital pin to the servo object
  pinMode(blTouchPin, INPUT_PULLUP); // May need resistor in circuit. Then remove PULLUP

  Serial.begin(9600);

  //De-bugging blTouch. Touch the probe, what happens?
 // while (true) {
   // int state = digitalRead(blTouchPin);
    //Serial.println(state);
    //delay(1000); // Slow down output for readability
 // }

 // connect and configure the stepper motor to there IO pins
 
 stepperX.connectToPins(stepXPin, dirXPin);
 stepperY.connectToPins(stepYPin, dirYPin);
 stepperZ.connectToPins(stepZPin, dirZPin);
 
 // enable the stepper motors
  digitalWrite(STEPPERS_ENABLE_PIN, LOW);

 // Initialize button
 startButton.setDebounceTime(50); // Debounce for button

// Show blTouch works
  deployProbe(); // Deploy probe at startup to show it works
  delay(500);
 //retractProbe(); // Retract probe at startup to show it works

  Serial.println("Setup complete. Use joysticks to position X, Y and Z.");
}

void loop() {//The measurements loop, i.e. do not finish when total X reached


 // Set max speeds for stepper motors. Can these be in setup?
 stepperX.setSpeedInMillimetersPerSecond(maxSpeedX);
 stepperY.setSpeedInMillimetersPerSecond(maxSpeedY);
 stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZ);

 // Set acceleration for stepper motors
 stepperX.setAccelerationInMillimetersPerSecondPerSecond(maxAccelX);
 stepperY.setAccelerationInMillimetersPerSecondPerSecond(maxAccelY);
 stepperZ.setAccelerationInMillimetersPerSecondPerSecond(maxAccelZ);

 // Set steps per millimetre
 stepperX.setStepsPerMillimeter(StepsPermm);    // Steps per millimetere for X axis
 stepperY.setStepsPerMillimeter(StepsPermm);    // Steps per millimetere for Y axis
 stepperZ.setStepsPerMillimeter(StepsPermmZ);    // Steps per millimetere for Z axis
 
 // Update button state
  startButton.loop();

// Joystick control for X, Y AND z axes
  int joyX = analogRead(joyXPin) - 512;
  int joyY = analogRead(joyYPin) - 512;
  int joyZ = analogRead(joyZPin) - 512;

  if (abs(joyX) > joystickThreshold) {
    int speedX = map(joyX, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperX.setSpeedInMillimetersPerSecond(speedX);
    stepperX.moveRelativeInMillimeters(speedX > 0 ? 5 : -5);
    absX += (speedX > 0 ? 5 : -5); // Update absolute position
  }

  if (abs(joyY) > joystickThreshold) {
    int speedY = map(joyY, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperY.setSpeedInMillimetersPerSecond(speedY);
    stepperY.moveRelativeInMillimeters(speedY > 0 ? 5 : -5);
    absY += (speedY > 0 ? 5 : -5); // Update absolute position
  }
  
  if (abs(joyZ) > joystickThreshold) {
    int speedZ = map(joyZ, 512, -512, -joystickMaxSpeed, joystickMaxSpeed);
    stepperZ.setSpeedInMillimetersPerSecond(speedZ);
    stepperZ.moveRelativeInMillimeters(speedZ > 0 ? 5 : -5);
    absZ += (speedZ > 0 ? 5 : -5); // Update absolute position
  }

  // Start sequence on button press
  if (startButton.isPressed() && !sequenceInProgress) {
        Serial.println("Sequence starting...");
        sequenceInProgress = true; // Mark the sequence as in progress
        executeSequence();
        sequenceInProgress = false; // Reset the flag after completiion
    
  }
}

void executeSequence() {

  // Mark current position as (0, 0, 0)
   absX = 0.0;
   absY = 0.0;
   absZ = 0.0;
  
  int PositionsInX = xTotalDistance / xStepDistance; // Calculate total number of positions in X-axis to be measured

   for (int i = 0; i <= PositionsInX; i++) {
    // Move Z down until BLTouch is triggered
    Serial.println("Probing Z...");
    deployProbe();
    while (digitalRead(blTouchPin) == LOW) {
   
      stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZProbe); // Move Z down
      stepperZ.moveRelativeInSteps(1); //positive tp get correct motor direction
      absZ -= 0.01; // Update absolute Z position
    }
  
    retractProbe();

      

    Serial.print("Position: X=");
    Serial.print(absX);
    Serial.print(", Y=");
    Serial.print(absY);
    Serial.print(", Z=");
    Serial.println(absZ);

    // Move Z up by retract distance
    stepperZ.setSpeedInMillimetersPerSecond(maxSpeedZ); // Move Z up
    stepperZ.moveRelativeInMillimeters(-zRetractDistance); //negative to get correct motor direction
    absZ += zRetractDistance;

    // Move X by position distance for the next measurement
    stepperX.setSpeedInMillimetersPerSecond(maxSpeedX); //is it needed again here? If should I include acceleration again?
    stepperX.moveRelativeInMillimeters(xStepDistance); 
    absX += xStepDistance;

    delay(500); // Small delay for stability
  }

  Serial.println("Sequence complete.");
}

// Deploy the BLTouch probe
void deployProbe() {
  blTouchServo.write(10); // Adjust angle for deployment
  delay(500);
}

// Retract the BLTouch probe
void retractProbe() {
  blTouchServo.write(90); // Adjust angle for retraction
  delay(500);
}

//void blink() {
 // Touch = 1;

Suggestions and tips welcome please!

Many thanks
Matt

Exactly where in your second sketch is the attempt to stop the loop ?

The code is too long and complicated to easily analyze, given that you have provided no guidance as to the actual cause of the problem.

So, two bits of advice:

Start by getting rid of all the delays. The computer can't do anything else while it is stuck in a delay().

I think it is looping the sequence over and over

That is easy for you to verify. Put in Serial.print() statements to examine the values of key variables. Are they what you expect them to be? Put in loop counters and print them.

3 Likes

Hi @matthorn95 Two things I would try 1. using a different pin for the joystick button 2. Try .isReleased() instead in case wires are crossed (unless it's starting on button press and just not stopping)

Hi,

I was looking for help to identify the cause of the issue - had I known the issue I expect I could resolve it by myself!

That said, the loop counters idea is a goof one

and just after the joystick mapping:

 // Start sequence on button press
  if (startButton.isPressed() && !sequenceInProgress) {
        Serial.println("Sequence starting...");
        sequenceInProgress = true; // Mark the sequence as in progress
        executeSequence();
        sequenceInProgress = false; // Reset the flag after completiion
    
  }

Hi Steve9,

Yes it is starting on button press (as intended) and just not stopping.

What makes you think trying a different pin for joystick button?

That was obvious. However, for people to help, you need to provide more information about the problem, which means putting some effort into your own investigation of it.

Post #3 suggests specific things you could do in order to provide that information.

1 Like

Not that familiar with your board, but pin 13 is usually LED pin and I'd just eliminate that as a possible cause

Hi,

I have put effort in, 3 months on and off I have been working on this. I was very wary of posting on here, as reading other threads from my searches does seem to show a rather unhelpful attitude from a minority of people on this forum.

I would thik there is a command / set of commands that can be used to limit a sequence to a requested amount. Perhaps even an example sketch? With such a specific question, perhaps you can off er constructive comments?

Regards

This kind of board loops forever. If you want to PAUSE the loop, use a button to either pause or start. Make sure you debounce the button and do the pause at the end or the start at the start.

Try a different button library or do your own handling. ezButton doesn't suck, but needs its service method to be called very frequently.

This one

works, and works better. Follow the example, it shouldn't take but a minute to get it swapped in.

Note: it has no service or update method. One button press results in one true return from the button for pressed method.

Note: it does have a begin() method.

Also notable is the long default debounce of 100, but there is a constructor where you can set that to something less ridiculous:

Button::Button(uint8_t pin, uint16_t debounce_ms)

HTH

a7

Sure. Choose the variables labeled X (to be incremented in the code at an appropriate place) and N (the upper limit) appropriately. Program action effectively terminates with an infinite loop that does nothing.

if  (X >= N) while(1);

or exit the loop function prematurely:

if  (X >= N) return;

Naturally, that is not as wise or as useful as studying the code, understanding what each line of code does, and installing a sensible limit or escape clause at a logical place in the code.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.