teemuatlut / TMCStepper

MIT License
500 stars 195 forks source link

TMC2300, Stallguard, coolstep and more... #203

Open HomelessBee opened 3 years ago

HomelessBee commented 3 years ago

Hi,

I'm having an issue with my setup. I want to use a TMC2300 to detect a stall using StallGuard, and then use Coolstep to adapt the current when in use in order to save power since my setup is running on batteries. But I have reached a standstill in my progress.

I have configured a stall, and when I compare it to SG_RESULT, and when SG_VALUE ≤ SGTHRS*2, the motor does not stop, and the DIAG pin does not react. I have tried different configurations, microsteps, speed, Stall values, ect, but no matter the config the driver will not detect a stall. I can read values on the driver with no issue.

Another issue; The motor will not run before I have disconnected and reconnected power from the power supply

I am using an Arduino uno, PM35S-048 motor, TMC2300, 12V battery-power supply.

My test code is:

#include <Arduino.h>
#include <TMCStepper.h>

#define STALL_VALUE       60// [0... 255]
#define TOFF_VALUE        4 // [1... 15]

//#define STEP_PIN          10
//#define DIR_PIN            11
#define EN_PIN                8 // Enable pin
#define SW_RX                 2 // SoftwareSerial receive pin
#define SW_TX                 3 // SoftwareSerial transmit pin
//#define SERIAL_PORT       0 // HardwareSerial port
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
#define DIAG_PIN           6 // diag input

#define R_SENSE 0.11f // Match to your driver
// SilentStepStick series use 0.11
// UltiMachine Einsy and Archim2 boards use 0.2
// Panucatt BSD2660 uses 0.1
// Watterott TMC5160 uses 0.075

// Select your stepper driver type
//TMC2209Stepper driver(SERIAL_PORT, R_SENSE, DRIVER_ADDRESS);
TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);

using namespace TMC2209_n;

void setup() {
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
  digitalWrite(EN_PIN, HIGH);
  delay(500);
  Serial.begin(115200);         // Init serial port and set baudrate
  while (!Serial);              // Wait for serial port to connect
  Serial.println("\nStart...");

  //SERIAL_PORT.begin(115200);
  driver.beginSerial(115200);
  driver.begin();
  //  driver.pdn_uart(true);
  //driver.en_spreadCycle(true);
  //stepper.setCurrentPositionInSteps(0);

  // Sets the slow decay time (off time) [1... 15]. This setting also limits
  // the maximum chopper frequency. For operation with StealthChop,
  // this parameter is not used, but it is required to enable the motor.
  // In case of operation with StealthChop only, any setting is OK.
  driver.toff(TOFF_VALUE);

  // VACTUAL allows moving the motor by UART control.
  // It gives the motor velocity in +-(2^23)-1 [μsteps / t]
  // 0: Normal operation. Driver reacts to STEP input.
  // /=0: Motor moves with the velocity given by VACTUAL.
  // Step pulses can be monitored via INDEX output.
  // The motor direction is controlled by the sign of VACTUAL.
  //driver.VACTUAL(10000);

  // Comparator blank time. This time needs to safely cover the switching
  // event and the duration of the ringing on the sense resistor. For most
  // applications, a setting of 16 or 24 is good. For highly capacitive
  // loads, a setting of 32 or 40 will be required.
  driver.blank_time(24);

  driver.rms_current(750); // mA
  driver.microsteps(128); //microsteps 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 1/256
  // Lower threshold velocity for switching on smart energy CoolStep and StallGuard to DIAG output
  driver.TCOOLTHRS(0xFFFFF); // 20bit max

  // CoolStep lower threshold [0... 15].
  // If SG_RESULT goes below this threshold, CoolStep increases the current to both coils.
  // 0: disable CoolStep
  driver.semin(5);

  // CoolStep upper threshold [0... 15].
  // If SG is sampled equal to or above this threshold enough times,
  // CoolStep decreases the current to both coils.
  driver.semax(2);

  // Sets the number of StallGuard2 readings above the upper threshold necessary
  // for each current decrement of the motor current.
  driver.sedn(0b01);

  // StallGuard4 threshold [0... 255] level for stall detection. It compensates for
  // motor specific characteristics and controls sensitivity. A higher value gives a higher
  // sensitivity. A higher value makes StallGuard4 more sensitive and requires less torque to
  // indicate a stall. The double of this value is compared to SG_RESULT.
  // The stall output becomes active if SG_RESULT fall below this value.
  driver.SGTHRS(STALL_VALUE); //stallvalue

  Serial.print("\nTesting connection...");
  uint8_t result = driver.test_connection();

  if (result) {
    Serial.println("failed!");
    Serial.print("Likely cause: ");

    switch (result) {
      case 1: Serial.println("loose connection"); break;
      case 2: Serial.println("no power"); break;
    }

    Serial.println("Fix the problem and reset board.");

    // We need this delay or messages above don't get fully printed out
    delay(100);
    abort();
  }

  Serial.println("OK");

}

void loop() {
  driver.VACTUAL(5120); // motor speed
  Serial.print(driver.SG_RESULT() < STALL_VALUE, DEC); //check for stall
  Serial.print("\n ");
  Serial.print(driver.SG_RESULT()); // Motor load

}

my test setup: Note: DIAG is NOT on 20210617_141815

teemuatlut commented 3 years ago

image

But I would highly suggest you do not try to use driver definitions that do not match your hardware. You were setting all kinds of bits unintentionally. The code below works but is not how you should do it. The Release v1 branch supports the TMC2300 so I would suggest using that instead. I'll try to port this over to that branch when I have the time.

#include <Arduino.h>
#include <TMCStepper.h>

#define STALL_VALUE       60// [0... 255]

#define EN_PIN                8 // Enable pin
#define VIO_PIN              19 // Driver VIO pin used for resetting the driver
#define SW_RX                 2 // SoftwareSerial receive pin
#define SW_TX                 3 // SoftwareSerial transmit pin
//#define SERIAL_PORT       0 // HardwareSerial port
#define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2
#define DIAG_PIN           6 // diag input

#define R_SENSE 0.11f // Match to your driver

TMC2209Stepper driver(SW_RX, SW_TX, R_SENSE, DRIVER_ADDRESS);

using namespace TMC2209_n;

void setup() {
  pinMode(EN_PIN, OUTPUT);
  pinMode(DIAG_PIN, INPUT);
  pinMode(VIO_PIN, OUTPUT);
  digitalWrite(EN_PIN, LOW);
  digitalWrite(EN_PIN, HIGH);
  digitalWrite(VIO_PIN, LOW);
  delay(500);
  digitalWrite(VIO_PIN, HIGH);
  Serial.begin(115200);         // Init serial port and set baudrate
  while (!Serial);              // Wait for serial port to connect
  Serial.println("\nStart...");

  driver.beginSerial(19200);
  driver.toff(1);

  driver.irun(20);
  driver.microsteps(128); //microsteps 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 1/256
  driver.TCOOLTHRS(0xFFFFF); // 20bit max

  driver.SGTHRS(50);

  Serial.print("\nTesting connection...");
  uint8_t result = driver.test_connection();

  if (result) {
    Serial.println("failed!");
    Serial.print("Likely cause: ");

    switch (result) {
      case 1: Serial.println("loose connection"); break;
      case 2: Serial.println("no power"); break;
    }

    Serial.println("Fix the problem and reset board.");

    // We need this delay or messages above don't get fully printed out
    delay(100);
    abort();
  }

  Serial.println("OK");

  driver.VACTUAL(15120); // motor speed
}

void loop() {
  Serial.print(100 * digitalRead(DIAG_PIN)); //check for stall
  Serial.print("\t");
  Serial.print(driver.SG_RESULT()); // Motor load
  Serial.print("\n ");

}
teemuatlut commented 3 years ago

#include <Arduino.h>
#include <TMCStepper.h> // Branch: Release_v1

constexpr uint8_t EN_PIN   = 8;
constexpr uint8_t VIO_PIN  = 19;
constexpr uint8_t SW_RX    = 2;
constexpr uint8_t SW_TX    = 3;
constexpr uint8_t DIAG_PIN = 6;

constexpr uint8_t sgthrs = 130;
constexpr uint8_t semin = 6;
constexpr uint8_t semax = 2;

TMC_HAL::SWSerial ser(SW_RX, SW_TX); // Provides half-duplex mode
TMC2300Stepper driver(ser, 0.11, 0);

void setup() {
  pinMode(EN_PIN, OUTPUT);
  pinMode(DIAG_PIN, INPUT);
  pinMode(VIO_PIN, OUTPUT);

  Serial.begin(115200); // Init serial port and set baudrate
  while (!Serial);      // Wait for serial port to initialize

  digitalWrite(VIO_PIN, LOW);  // Reset driver memory
  delay(50);
  digitalWrite(VIO_PIN, HIGH);

  driver.beginSerial(19200); // Set SW UART baudrate

  auto version = driver.version();
  while (version == 0) {
    delay(10000);
    Serial.print("Communication error ");
  }

  driver.GSTAT(0b111); // Reset error flags

  driver.enable_drv(true); // Unnecessary as 1 is default
  driver.rms_current(800);
  driver.microsteps(128);
  driver.TCOOLTHRS(0x3FF); // 10bit max

  driver.semin(semin);   // If SG value is below this * 32, the current will be increased
  driver.semax(semax);   // If SG value is over (this + semin + 1) * 32, the current will be decreased
  driver.sedn(0b00);     // Set current reduction rate
  driver.seup(0b01);     // Set current increase rate
  driver.SGTHRS(sgthrs); // If SG value falls below this * 2 then the diag output will become active

  digitalWrite(EN_PIN, HIGH);
  driver.VACTUAL(50000);

  Serial.println("StallGuard_value Actual_current Diag_pin semin semax sgthrs");
}

void loop() {
  delay(100);

  char buffer[128];
  snprintf(buffer, sizeof(buffer), "%u %u %u %u %u %u",
    driver.SG_VALUE(),
    driver.cs2rms(driver.cs_actual()),
    100 * digitalRead(DIAG_PIN),
    semin*32, (semin+semax+1)*32, sgthrs*2
  );
  Serial.println(buffer);
}

image

HomelessBee commented 3 years ago

Great, but when does v1 release so I can try this out? I'm currently running v0.71

teemuatlut commented 3 years ago

You can try it out whenever you want. You just need to pull or download a different branch.

HomelessBee commented 3 years ago

It's working.. kinda. My StallGuard value is consistantly very low, 200 max. without load. And actual current is unaffected. Any idea what could be causing this?

teemuatlut commented 3 years ago

The value can depend on current, speed, motor characteristics and more. What more important is you get a response to applied load.

cranefist commented 3 years ago

Is there any benefit in using the DIAG pin, instead of monitoring the stallguard value in software?

If i'm doing a simple homing, something like this where i'm waiting for the SG to hit 0.

driver.VACTUAL(-3000); 
while (driver.SG_RESULT()!=0) {};
driver.VACTUAL(0);

Also, sorry if this interferes.. did not want to open a separate issue for this.

HomelessBee commented 3 years ago

Hi cranefist.

In my experience monitoring in software is too unreliable and slow for my usage. Beside that I'm using DIAG as an interrupt in my program.