Hello all, i am working on a project. It entails a AMIS-30543 motor driver, driving a Nema17 1.5A 17hs16 stepper motor with a threaded rod attached to a linear glass scale (5um resolution). These are being ran by a pololu SV board. It is meant to extend a probe, then when a stall is detected (hits a hard surface) or after 12mm, it will return to a 0 position (bottom out until I cannot get any closer and reset the scale to 0). Currently, even when I grab the threaded rod and stop it from spinning, the driver is not detecting the stall. I am lost as for what to try next. Any help would be greatly appreciated.
Hello all, i am working on a project. It entails a AMIS-30543 motor driver, driving a Nema17 1.5A 17hs16 stepper motor with a threaded rod attached to a linear glass scale (5um resolution). These are being ran by a pololu SV board. It is meant to extend a probe, then when a stall is detected (hits a hard surface) or after 12mm, it will return to a 0 position (bottom out until I cannot get any closer and reset the scale to 0). Currently, even when I grab the threaded rod and stop it from spinning, the driver is not detecting the stall. I am lost as for what to try next. Any help would be greatly appreciated.
#include <SPI.h>
#include <AMIS30543.h>
// ----- Motor Driver (AMIS-30543) Setup -----
const uint8_t amisDirPin = 2; // DIR pin
const uint8_t amisStepPin = 3; // STEP pin
const uint8_t amisSlaveSelect = 4; // CS pin
// Delay between steps (microseconds)
const unsigned int STEP_DELAY_US = 500; // Adjust for speed/timing
// ----- Probe Routine Parameters -----
const unsigned long FORWARD_TIME_MS = 10000; // Maximum time allowed for downward movement
const unsigned long RESET_TIME_MS = 10000; // Maximum time allowed for upward (reset) movement
// Maximum allowed travel in free air (if no stall occurs), in millimeters
const double MAX_TRAVEL_MM = 20.0;
// Minimum displacement (in mm) required before a stall is accepted
const double MIN_DISPLACEMENT_MM = 2.0;
// Conversion factor: if resolution is 5 µm/count, then each count = 0.005 mm.
const double CONVERSION_FACTOR = 0.005;
AMIS30543 stepper;
// ----- Glass Scale (TTL Quadrature) Setup -----
// Wiring assumption:
// Red = +5V, Black = GND, Green = Signal A, Yellow = Signal B.
// Signal A is connected to digital pin 0 and Signal B to digital pin 1.
const int SCALE_A_PIN = 0;
const int SCALE_B_PIN = 1;
volatile long encoderPosition = 0;
volatile int lastEncoded = 0;
// Forward declarations:
uint8_t readSR0Manual();
void runProbeSequence();
void step();
void setDirection(bool dir);
void updateEncoder();
void setup() {
Serial.begin(9600);
// Initialize SPI and the motor driver:
SPI.begin();
pinMode(amisSlaveSelect, OUTPUT);
digitalWrite(amisSlaveSelect, HIGH);
stepper.init(amisSlaveSelect);
pinMode(amisStepPin, OUTPUT);
pinMode(amisDirPin, OUTPUT);
digitalWrite(amisStepPin, LOW);
digitalWrite(amisDirPin, LOW);
delay(1);
stepper.resetSettings();
stepper.setCurrentMilliamps(350); // Adjust current limit to match your force (27ā31 N) calibration
stepper.setStepMode(4); // 1/4 stepping for smoother motion
stepper.enableDriver();
// Set up glass scale pins with pull-ups:
pinMode(SCALE_A_PIN, INPUT_PULLUP);
pinMode(SCALE_B_PIN, INPUT_PULLUP);
int aVal = digitalRead(SCALE_A_PIN);
int bVal = digitalRead(SCALE_B_PIN);
lastEncoded = (aVal << 1) | bVal;
attachInterrupt(digitalPinToInterrupt(SCALE_A_PIN), updateEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(SCALE_B_PIN), updateEncoder, CHANGE);
delay(1000);
Serial.println("A-Star ready.");
}
void loop() {
// Wait for a "PROBE" command from the host (e.g., Raspberry Pi)
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.equalsIgnoreCase("PROBE")) {
// Send an immediate preliminary value to avoid host timeout
Serial.println("0");
runProbeSequence();
}
}
}
void runProbeSequence() {
// --- Downward (Probe) Phase ---
setDirection(false); // Set motor direction downward
unsigned long startTime = millis();
long measuredCounts = 0;
double probeDepth_mm = 0.0;
while (millis() - startTime < FORWARD_TIME_MS) {
step();
delay(1); // Small delay to allow stall flag to update
measuredCounts = encoderPosition;
probeDepth_mm = measuredCounts * CONVERSION_FACTOR;
// Debug: Print current counts and calculated depth
Serial.print("Counts: ");
Serial.print(measuredCounts);
Serial.print(" Depth (mm): ");
Serial.println(probeDepth_mm);
uint8_t status = readSR0Manual();
Serial.print("Stall status: ");
Serial.println(status, BIN);
// Only accept a stall if at least the minimum displacement has been reached
if (probeDepth_mm > MIN_DISPLACEMENT_MM && (status & 0x80)) {
Serial.println("Stall detected after valid displacement.");
break;
}
// Stop if maximum travel (20 mm) is reached
if (probeDepth_mm >= MAX_TRAVEL_MM) {
Serial.println("Maximum travel reached.");
break;
}
}
double calcinationDepth = probeDepth_mm; // Save the measured depth
// --- Upward (Reset) Phase ---
// Reverse motor until the probe mount bottoms out (stall detected) or timeout
// Upward (reset) phase: reverse until stall (i.e. mount bottoms out) or timeout
setDirection(true); // Set motor direction upward
unsigned long resetStartTime = millis();
bool printedStatus = false;
while (millis() - resetStartTime < RESET_TIME_MS) {
step();
delay(1);
uint8_t status = readSR0Manual();
if (status & 0x80) { // Stall detected during reset
if (!printedStatus) {
Serial.print("Reset stall status: ");
Serial.println(status, BIN);
Serial.println("Reset stall detected. Home reached.");
printedStatus = true;
}
break;
}
}
if (!printedStatus) {
Serial.println("Reset phase completed without stall detection.");
}
// Debug: Print final calcination depth before encoder reset
Serial.print("Final calcination depth (mm): ");
Serial.println(calcinationDepth);
// Reset encoder to 0 (home position) after a short delay
delay(100);
noInterrupts();
encoderPosition = 0;
interrupts();
// Print final depth for the host (GUI)
Serial.println(calcinationDepth);
}
void step() {
digitalWrite(amisStepPin, HIGH);
delayMicroseconds(3);
digitalWrite(amisStepPin, LOW);
delayMicroseconds(3);
delayMicroseconds(STEP_DELAY_US);
}
void setDirection(bool dir) {
delayMicroseconds(1);
digitalWrite(amisDirPin, dir);
delayMicroseconds(1);
}
uint8_t readSR0Manual() {
digitalWrite(amisSlaveSelect, LOW);
SPI.transfer(0x40 | (0x0C & 0x3F)); // Command for reading SR0 (0x4C)
uint8_t status = SPI.transfer(0x00);
digitalWrite(amisSlaveSelect, HIGH);
return status;
}
void updateEncoder() {
int aVal = digitalRead(SCALE_A_PIN);
int bVal = digitalRead(SCALE_B_PIN);
int encoded = (aVal << 1) | bVal;
int sum = (lastEncoded << 2) | encoded;
lastEncoded = encoded;
switch (sum) {
case 0b0011:
case 0b0100:
case 0b1011:
case 0b1100:
encoderPosition++;
break;
case 0b0001:
case 0b0110:
case 0b1001:
case 0b1110:
encoderPosition--;
break;
// Transitional states (0b0000, 0b1111) are ignored.
}
}
