janelia-arduino / TMC2209

The TMC2209 is an ultra-silent motor driver IC for two phase stepper motors with both UART serial and step and direction interfaces.
Other
175 stars 27 forks source link

Working Exemple of TMC2209 + AccelStepper #52

Open MRTNPRSN opened 7 months ago

MRTNPRSN commented 7 months ago

Hello, Thanks a lot for this lib, I really appreciate the fact that every settings are so clear. I was using TMCstepper lib before with accelstepper and I'am currently trying to migrate my code to your lib. Serial communication is working great but I am struggling making it work with AccelStepper lib. My setup is: ESP32 (lolin32 lite) driving 2 TMC2209 drivers, serial communication via hardware serial2 (everything ok here). I mention here that my previous code using TMCStepper was working ok. I also tried your exemple StepAndDirection and it is also working, motor is moving as expected, but no luck with AccelStepper.

Basically, no motor movement with AccelStepper.

Do you have any hint to help me?

peterpolidoro commented 7 months ago

I have never used AccelStepper. Does it generate step and direction pulses? The TMC2209 expects either step and direction pulses or serial commands. The AccelStepper library might instead be generating signals meant to be used for H-Bridges. If it does generate step and direction pulses, can you check to make sure those pulses are working properly with an oscilloscope? If you need nice acceleration and deceleration there might another Arduino library that will generate step and direction pulses if AccelStepper does not or you could use a chip like the TMC429 to generate the step and direction pulses for you.

MRTNPRSN commented 7 months ago

Hi Peter,

Yes AccelStepper generate step and direction pulses. Here is how I implement this in my code:

#include <TMC2209.h>
#include <AccelStepper.h>

#define MICROSTEPPING_AZ 64

#define DIR_PIN_1 5    // Direction
#define STEP_PIN_1 18  // Step
#define EN_PIN_1 22
#define MS1_PIN_1 13
#define MS2_PIN_1 15

TMC2209 stepper_driver_0;
const TMC2209::SerialAddress SERIAL_ADDRESS_0 = TMC2209::SERIAL_ADDRESS_0;

#define DRIVER_SERIAL_BAUD_RATE 115200

AccelStepper stepperAz = AccelStepper(AccelStepper::DRIVER, STEP_PIN_1, DIR_PIN_1);

void setup() {
  Serial.begin(115200);
  //SET THE DRIVER_1 ADDRESS TO 0b00
  pinMode(MS1_PIN_1, OUTPUT);
  pinMode(MS2_PIN_1, OUTPUT);
  digitalWrite(MS1_PIN_1, LOW);
  digitalWrite(MS2_PIN_1, LOW);

  stepper_driver_0.setup(Serial2, DRIVER_SERIAL_BAUD_RATE, SERIAL_ADDRESS_0);
  stepper_driver_0.setMicrostepsPerStep(MICROSTEPPING_AZ);
  stepper_driver_0.setHardwareEnablePin(EN_PIN_1);
  stepper_driver_0.enable();

  stepperAz.setMaxSpeed(20000.0);
  stepperAz.setAcceleration(40000.0);
  stepperAz.setSpeed(100);

  stepperAz.move(100000);
}

void loop() {
  if(stepperAz.distanceToGo() != 0)stepperAz.run();
}

As I mention in my previous message, everything works nicely with AccelStepper + TMCStepper lib. But I really like the way TMC2209 implement the serial communication and the ease of settings things.

peterpolidoro commented 7 months ago

Do you have an oscilloscope? Can you look to see if the step and direction pulses are being output properly?

MRTNPRSN commented 7 months ago

Hi Peter, No sadly I don't have an oscilloscope, I will try to find one and check if the steps and direction pulses are alright

jacycatlin commented 1 month ago

FWIW I spent a lot of time on this myself and determined that the STEP/DIR pins work until the UART gets anything - even just software_serial.setup(), not even .begin or sending data - will make it ignore STEP/DIR until you reset the driver board. (well, I briefly remove the 12V feed, I bet you could probably reset by cycling the EN pin too)

I'm currently in the process of hacking up my own rough'n'ready accel/decel code, and will post my question in its own thread, but this topic - I spent most of a weekend on it... I really wanted to get STRONG_BRAKING working alongside of smooth start and stop!

BTW there are a few TMC-family libraries which claim to incorporate or blend with AccelStepper features, but I could not get any to work on an ESP8266 - they're very old, crashy. and/or written for the Arduino AT-MEGA platform.

If I'm wrong and there is some way to send serial commands and then still use STEP/DIR... well, at this point, don't tell me!

peterpolidoro commented 1 month ago

I always use uart commands from a microcontroller to setup the TMC2209 driver then control it with step and direction signals from a TMC429. The TMC429 handles acceleration, velocity, and deceleration, but it should work with step and direction signals from a microcontroller too.

I do not know why the step and direction signals would stop working with the TMC2209 after you send it uart commands, because it is definitely intended to work that way if it is wired up correctly.

Can you please show a schematic of how you have it wired and the code that causes it to fail?

jacycatlin commented 4 weeks ago

ARRRGH - well now it DOES work. I reflashed my test sketch and it no longer quits after the first loop. An intensely frustrating capstone to a frustrating weekend of troubleshooting...

YOU did this, somehow... I don't know how yet... but trust me, I'm shaking my fist at you with considerable vigor.

I know the data sheet claims they can be used together, which is why I spent so much time trying to make it work.

Now I'm back to trying to decide whether to keep trying with AccelStepper, or continue the way I'd been going. My application (a powered roller blind unit) takes manual input from a physical switch as well as MQTT commands, so there's a relatively complex control logic in the mix. (and I'm already well beyond what would have been a sensible amount of effort to devote to this, considering there's a working version of the project in place already with fewer, but adequate, features)

Y'know what, I'll submit my other question here instead of its own thread, out of spite: where can I find a list of functions/methods for this library? The documentation has a lot of info but I don't see much beyond the examples for what you can actually do. I could be overlooking something obvious - I'm fairly experienced at that...

jacycatlin commented 4 weeks ago

OK well I still can't get AccelStepper to work in conjunction with a UART connection. In fact my demonstration sketch seems incredibly brittle - changing almost anything makes it stop working... FWIW I'm using a TMC2008 not that that should make much difference. (I have TMC2009 units to test with if need be)

Anyhow, clearly nothing to do with this library.

peterpolidoro commented 4 weeks ago

We have all been there, no worries. One of the joys of working with embedded systems, they are a dream when they work and can be a nightmare when they do not.

I am not sure how the AccelStepper library is implemented, but it may be using interrupts or something else that is interfering with the rest of your code. If you unload that logic onto something like the TMC429 it could make your life much easier.

I do not know if there are any breakout boards for the TMC429, but if not maybe I should make one since other people have run into this issue too.

Alternatively I have also started using the TMC5130 which combines a TMC429 and TMC2209 into a single chip so all you need to do is send position or velocity commands and it handles all velocity and accelerations for you, freeing up your microcontroller to just handle your code. I am working on a library for that one too I named TMC51X0 since it also works with the TMC5160.

jacycatlin commented 4 weeks ago

Now that I'm looking into it more, I think AccelStepper was designed to offer an alternative for several features of the TMC429. I've been trying to work out how to even do my project without AccelStepper since I can't find anything in your library that shows distance/steps covered or even current speed (then again I can't find documentation for your library, as such...)

At this point hardly any version of my test sketch works unless I briefly remove the 12V feed from the TMC2208 - and I don't even know why that "resets" anything, but it does, until I reset the ESP, at which point it stops again... I've boiled down the code to almost nothing:

#include <TMC2209.h>
SoftwareSerial soft_serial(D2, D0); 
TMC2209 stepper_serial;

void setup() {
  stepper_serial.setup(soft_serial); 
}

void loop() {
  stepper_serial.moveAtVelocity(10000);
  delay(1500);
  stepper_serial.moveAtVelocity(0);
  delay(1000);
}

... and just the UART wire (I've tried various source pins for TX too) connecting the two. Power up - nothing. Cut 12V power to the 2208 temporarily - reconnect - works great.

Fortunately my actual project code still works - or it did last time I tried it \<not panicking>... but this is my 4th ground-up rewrite of what was supposed to be a straightforward project, and all it does so far is briefly spin the motor at certain points to show it's working; I'm still fleshing out the rest of the logic overall.

I've been meaning to try and skim the AccelStepper code but I'm verrry rusty at actual programming so there's a fair chance I won't understand the key bits. It definitely handles the bit-banging for you but figuring out why it (may or may not be) conflicting with anything else is another matter.

Anyhow, I'd normally stubborn my way through this but the 429 sounds like a good answer, except - yep, I don't see any handy hobbyist products around! Thanks for your time either way -

peterpolidoro commented 4 weeks ago

Is there a reason why you have to use software serial? Does your microcontroller not have any available hardware uarts? Software serial can also be very buggy and should only be used as a last resort. If it is possible for to change to hardware serial or change microcontrollers then you may have a much easier time with your project.

jacycatlin commented 4 weeks ago

Well using software serial frees up the main hardware channel to Serial.print() troubleshooting info to the Arduino IDE serial monitor! (so yeah, no good reason... I could probably link up a USB-UART board and make software serial be my troubleshooting output, or for that matter, just send MQTT messages since it's already linked up to my broker)

And yes, I bet switching from ESP8266 to ESP32 would solve some problems - or at least, shake up the problem set so that new ones are pointed at me. I haven plenty of both boards, and this is a one-off gadget (the rest of the house has vertical blinds....) I'm just being stubborn, mostly.

Thanks for the reminder about software serial, it's worth trying - I'm not even using debugging messages in this pared-down test sketch anyway, so there's no excuse!

jacycatlin commented 4 weeks ago

Hey guess what was missing from my pared-down test code...?
stepper_serial.enable();

So, the TMC chip is enabled on powerup, disabled by the driver (by default), and at some point I took the .enable() out of the test code.... D'OH

jacycatlin commented 4 weeks ago

Wait a minute - "StepAndDirection.ino" is an example from THIS library which uses both serial commands and STEP/DIR!

I changed Serial3 to "Serial", pins 2 and 3 to D2 and D1. But - it works. Or seems to... can't truly be sure the serial commands are going through unless I change something I can see visually, and my overall setup still seems pretty "brittle" - very often, making seemingly-innocent changes breaks stuff.

But still - well, put it this way, had I found this example sooner it would have made a MUCH better starting point!

jacycatlin commented 3 weeks ago

OK FWIW and in case anyone arrives here by a similar path to me, here's an example sketch which should - given a similar wiring and parts, anyway - allow you to use multiple commands for movement in the same program:

// this sketch demonstrates the use of UART communications with a TMC2208 or 2209 stepper driver
// while also remaining able to use STEP/DIR pins, either directly (bit-banging) or via AccelStepper
// tested with an ESP8266 (Wemos D1 mini clone), a TMC2208, and - wait for it! - a NEMA17 stepper
// (Adapted from StepAndDirection.ino, in TMC2209.h library by Peter Polidoro https://github.com/janelia-arduino/TMC2209/

#include <TMC2209.h>
#include <AccelStepper.h>

HardwareSerial & serial_stream = Serial;  // using the hardware serial at TX/DX pins 

const uint8_t STEP_PIN = D2;
const uint8_t DIRECTION_PIN = D1;

const uint32_t STEP_COUNT = 51200;
const uint16_t HALF_STEP_MICROSECONDS = 10;

// create an object to access the stepper library
TMC2209 stepper_driver;

// and another one for AccelStepper features
AccelStepper stepper_AS(AccelStepper::DRIVER, STEP_PIN, DIRECTION_PIN); 

void setup()
{
  stepper_driver.setup(serial_stream); 

  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIRECTION_PIN, OUTPUT);
  pinMode(D4, OUTPUT);  // built-in LED for indicating <whatever> - errors, other feedback

  stepper_driver.setRunCurrent(100);
  //stepper_driver.setMicrostepsPerStep(64);  // changing this affects different movement methods differently
  stepper_driver.enableCoolStep();
  stepper_driver.enable();

  stepper_AS.setMaxSpeed(80000);
  stepper_AS.setAcceleration(10000);
}

void loop() {

  delay(1000);  // each type of movement command is indicated by a series of 1, 2 or 3 quick blinks
  blinky(1);    // because using HardwareSerial means I can't use the Arduino IDE SerialMonitor,
  delay(200);   // and I'm too lazy to wire up something on a SoftwareSerial port anyway

  for (uint32_t i=0; i<STEP_COUNT*2; ++i)  // not sure why i needs to be 32-bit? but it was in the example
  {
    digitalWrite(STEP_PIN, !digitalRead(STEP_PIN));  // this is manipulating STEP/DIR directly via GPIO 
    delayMicroseconds(HALF_STEP_MICROSECONDS);
  }
  digitalWrite(DIRECTION_PIN, !digitalRead(DIRECTION_PIN));  // reverse direction for next loop

  delay(1000);  // OK that's it for bit-banging,
  blinky(2);   // next up we have movement via UART command - the TMC2208/9 doing the driving
  delay(200);  

  stepper_driver.moveAtVelocity(80000);
  delay(800);
  stepper_driver.moveAtVelocity(0);

  delay(1000);  // and finally - AccelStepper, which I struggled for days to get working
  blinky(3);    // This moves differently and I'm fiddling with the accel/maxspeed/microsteps a lot
  delay(200);   // but at least all 3 work within this one configuration

  stepper_AS.move(50000);
  while (stepper_AS.run()) { yield(); }
  delay(1000);
}

void blinky(int times) {
  // quick'n'dirty indicator - blocking, but I don't care in this context
  for (int i = 0; i < times; i++) {
    digitalWrite(D4, LOW);  delay(100);
    digitalWrite(D4, HIGH); delay(100);   
  }

}