AccellStepper Documentation

I am a simple programmer, and I just use brute force and lots of examples to make my proof of cocept sketches work, but I am doing a bit more homework on this one.

I have a RC-servo heavy project that needs ONE stepper, as it needs to move a belt-sled about 6" pretty fast, and then move it back. This moves the "stage" forwords & back. I want to limit acceleration so I don't strip/slip the belt.

I was HOPING to find some documentation to all the different calls and conditions rather than trying to sus out the details from the examples.

I would like to use an arduino UNO and a TMC2209 with a Nema17 pancake stepper to move my stage (that has all the servos on it)

My questions:

  1. for very very simple applications (and a beginner programmer), am I better running standalone or UART
  2. Does AccellStepper support UART?
  3. Is there a Non-Blocking command for "Moveto [location]" that doesn't require repetative calls to "run" as I am already running a tight loop to controll all the servos?

My Pre-Sketch workflow looks like... I write out this BEFORE I start coding....

//Initilize
Set pins, modes, base speed and acceleration.
Move sled "back" until End-sesnor, Move off a touch, set "Home Position"
Set "Present" position

//Present
Moveto [present]

//Retract
SetSpeed to 1/2
Moveto [Home]
reset speed

Luckily, these moves can be blocking (brute force) or Non-Blocking as most of the real work is being done by servo's before and after these moves

AccellStepper is a bit of overkill, but I may need this in the future, so might as well learn it now.

Mobatools is a newer stepper library recommended by experieced helpers.
Accelstepper has a number of different ways to handle steppers, and several ways to have trouble.
Your needs are clear. If UART operation is the answer, other helpers should tell.
Posting the code is recommended!

Of which library? On the right-hand side of the link below, all the function calls are shown... AccelStepper/AccelStepper.h at master · adafruit/AccelStepper · GitHub

The loop() function is meant to be repetitive. Maybe you want some low-level timer/timeout that you can set in the code and let it run? Reefwing Robotics: Programming the ATmega328P Registers and Interrupts

First, configure the driver for microstepping.

Second, slowly increase speed (accelerate) from zero to your desired maximum by slowly decreasing the time between creating a single-step pulse. To slow (negative acceleration), increase the time between creating a single-step pulse.

"time between steps"

void checkElapsedTime() { // for the stepper motor
  unsigned long currentMillis = millis(); // store the time
  if (currentMillis - previousMillis >= interval) { // compare elapsed time to interval
    previousMillis = currentMillis; // store last step time
    stepNow = 1; // flag to indicate it is time to step the motor
  }
}

"single-step pulse"

void singlepulse() { // minimum requirement to step a stepper
  digitalWrite(stepPin, HIGH);
  delay(10); // let the motor arrive at the next step
  digitalWrite(stepPin, LOW);
}

Are you sure they are electrically compatable.
You only gave us the size of the mounting plate (1.7 inch).
What is the driver voltage?
Is it related to this post. You refused to disclose the hardware there too.
Leo..

The hardware is still in the abstract stage, trying to work out what is doable before buying (or digging in the junk drawer) anything. The Tmc2209 is a generic stepper driver with lots of support. I am trying to find a non-blocking solution as I already have full loop of other tasks that is getting messy.The Nema is also a generic stepper that works well with 2209s.

Everything is still in the exploration stage… I have already gone down several paths only to find out they weren’t fast enough due to the attached gearbox, or max steps/second.

That's due to the code You have not posted.

Nema is a standarised size of the mounting plate. Nema 17 meaning 1.7 inch.
It has nothing to do with the electrical specs or brand.
Leo..

The option that was put aside said that the assembly (controller, stepper,gearbox) maxed out at about 800 steps/second which would give me a travel time way outside my design parameters.

I need to move a platform/sled with the rest of the diorama on it about 6” in less than 2 seconds. Think 3D printer head. I could do it with a really big RC servo and lots of linkages, or a nema17 two pulleys and a belt with a driver or a driver/controller.

The smarts driving this started as an Arduino nano, but people have added more “options” that are making the main timing loops unstable so I am trying to find “smart” controllers that I can just tell “go to point xx, at speed zz, with accell yy” and not have to keep polling it.

I have working code for the proof of concept. It works, but is not stable and occasionally runs things into each other before resetting. I don’t want to use any part of the concept code other than the flow as it is a mess. Same for the hardware,its a mess.

... tend to "have tricks they saw on youtube."

"Does not work"

Post your code and a working wiring diagram. After one or both are torn to shreds and reassembled, you will have a working program.

Ok, here is the WORKING prototype.
IMG_5450.zip (5.4 MB)
This is as long a video as it will let me post.

From a trigger
You hear someone dropping something
Iris Opens
Eyeball comes forward (sorry video ends here)
It talks while the eyeball scans, blinks, and continues.
Another comment and the Eyeball retreats
The Iris closes
One last curse word
(resets after delay)

It works, the mechanics are UGLY, but they work.
The Eyeball SLED is the problem, I want to make that at STEPPER, so I can move it faster. This is a string on a pulley with a Hair tie.

I am looking for CONCEPTS to make the Sled work easier. I already have a loop that runs the servos that gives me speed and acceleration control that I hand wrote.
I really don't want to do the same thing for the Servo.

Go for another gearbox or drop it.
Please reply to the requests. Posting more words, repeating old words doesn't bring the solution closer. Good luck. I'm out.

What are the devices used in the project?

  • Nano with ?ATmega328p?
  • stepper, ?200-step/rev, 12vdc, 1.5A?
  • servo ?SG90?, 5vdc, 1.5A?
  • Power supply?

What is missing?
Post a wiring diagram.
Post the full sketch.

I will post more in a bit. Have some housework to do.

Currently it is all servos… driven directly off the nano.

Will post the sketch in a bit.

Hopefully not powered by/through the Nano.
Leo..

No, not POWERED by the Nano, they have their own V+ Rail.
Like I wrote earlier, this was a proof of Concept HACK.

I am now rebuilding it so it can run in a showcase and be triggered hundreds of times a week without busting something...

4x Servos are 9g lightweights, they do the light work like eye-lids.
1x Servo is a 20Kg HD servo that runs the slide through a block/tackle and a Hair-tie as a return spring.

There are references to the SOUND Board, it is a generic module that plays sounds from an SD card when triggers are pulled low.

All of the Pins usage are described in the header.

The Sketch Follows.

//This is the Control Software for the Motion Controlled Door-Eye
//Designed by Bob Sisson 2022 modeled, sort-of, on the Star Wars Jabba Hut Door scene
//Programmed in Arduino for the Uno/Nano
// The Device is designed to:
//
//  1: Start everything retracted/closed (Recommend starting with SLED OFF)
//  2; Upon triggering
//  3: Open the IRIS (and wait for it to get all the way open)
//  4: Slid the SLED forward (and wait...)
//  5: Open the EyeLIDs
//  6: Move the Eye pseudorandomly U/D & R/L
//  7: BLINK
//  8: Move the Eye pseudorandomly U/D & R/L
//  9: Close Eyelids
// 10: Retract SLED
// 11: Close IRIS
// 12: Delay to prevent retriggering too soon
// 13: Goto 1:
//
// Arduino Pin Assignments


#include <Servo.h>

Servo IRIS;     // create servo object to control a servo     (IRIS)
Servo EyeLids;  // create servo object to control a servo     (EyeLids)
Servo EyeRL;    // create servo object to control a servo      (EyeRL)
Servo EyeUD;    // create servo object to control a servo      (EyeUD)
Servo SLED;     // create servo object to control a servo       (SLED)


//
int DEBUG = 1;
int pos = 20;
int eyeXpos = 90;
int eyeYpos = 90;         // variables to store the Eye position
int ClosedPosition = 47;  // only for Eyelids as they are BACKWARDS
int OpenPosition = 0;
int OpenSpeed = 1;
int CloseSpeed = 10;
int state = LOW;          // by default, no motion detected
int value = LOW;          // variable to store the sensor status (value)
int IrisMaxClosed = 350;  //
int IrisMaxOpen = 2500;   // these two setup values allow tuning of the iris

// Pin Assignments

int IrisPin = 2;  //Pins are logical not Physical
int SledPin = 3;
int LidsPin = 4;
int RLPin = 5;
int UDPin = 6;
int wav00001 = 7;
int sensor = 8;  // the pin that the sensor is atteched to
int wav00002 = 9;
int wav00003 = 10;
int wav00004 = 11;
int wav00005 = 12;
int LED = 13;  // the pin that the Status LED is atteched to
int wav00006 = 14;
// BLANK Pin 15



void setup() {
  Serial.begin(9600);  // initialize serial for debugging via TERMINAL
  if (DEBUG == 1) {
    Serial.println("Begin of Setup");  //debug
  }
  // All the Declarations and Such

  if (DEBUG == 1) {
    Serial.print(" Iris is on pin ");
    Serial.println(IrisPin);
    Serial.print(" Sled is on pin ");
    Serial.println(SledPin);
    Serial.print(" Lids are on pin ");
    Serial.println(LidsPin);
    Serial.print(" R/L is on pin ");
    Serial.println(RLPin);
    Serial.print(" U/D is on pin ");
    Serial.println(UDPin);
  }

  pinMode(wav00001, OUTPUT);
  digitalWrite(wav00001, HIGH);
  pinMode(wav00002, OUTPUT);
  digitalWrite(wav00002, HIGH);
  pinMode(wav00003, OUTPUT);
  digitalWrite(wav00003, HIGH);
  pinMode(wav00004, OUTPUT);
  digitalWrite(wav00004, HIGH);
  pinMode(wav00005, OUTPUT);
  digitalWrite(wav00005, HIGH);

  pinMode(LED, OUTPUT);

  pinMode(sensor, INPUT);                            // Motion Sensor Pin
  IRIS.attach(IrisPin, IrisMaxClosed, IrisMaxOpen);  // attaches the Iris
  EyeLids.attach(LidsPin);                           // attaches the Eyelid Servo
  EyeRL.attach(RLPin);                               // attaches the Right-Left Servo
  EyeUD.attach(UDPin);                               // attaches the Up-Down Servo
  SLED.attach(SledPin);                              // attaches the Sled

  // Setup Start Condition outside LOOP

  SLED.write(0);  // Make sure SKLED is fully retracted before closing Iris
  delay(1000);
  IRIS.write(0);                  // tell servo to go to ClosedPosition
  EyeLids.write(ClosedPosition);  // tell servo to go to Middle
  EyeRL.write(90);                // tell servo to go to Middle
  EyeUD.write(90);                // Basically center the Eye
  digitalWrite(LED, LOW);         // turn LED OFF

  if (DEBUG == 1) {
    Serial.println("End of Setup, pausing 5 seconds");
  }  //debug
  delay(5000);
}
// End Setup -----------------------------------------------------------------------
// main section-------------------------------------------------------------------
void loop() {
  if (DEBUG == 1) {
    Serial.println("Top of Main Section");  //debug
  }

  // Start of main loop--------------
  // The first Section is the MOTION DETECTION followed by the Main routine
  value = digitalRead(sensor);  // read sensor value
  if (value == HIGH)            // check if the sensor is HIGH/Motion
  {                             //run main routine

    //Main Routine ------------------
    if (DEBUG == 1) {
      Serial.println("Motion detected!");  //debug
    }
    digitalWrite(LED, HIGH);      // turn LED ON
    digitalWrite(wav00001, LOW);  // start first sound byte
    delay(50);
    digitalWrite(wav00001, HIGH);
    // delay to let wav00001 play
    delay(4000);
    //Open IRIS
    //THEN Move Sled
    if (DEBUG == 1) {
      Serial.println("Starting Open Iris section");  //debug
    }

    IRIS.write(180);
    delay(750);  // wait for iris to open
    SLED.write(270);
    delay(1500);  // wait for sled to finish moving
    if (DEBUG == 1) {
      Serial.println("Starting Open Eye section");  //debug
    }

    OpenEyeSlow();
    //Eye Should be OPEN, this is after Iris Open and Sled Forword
    // Total Eye Open/forward time should be around 10 seconds
    // With an Eye-BLINK around the middle of the time

    digitalWrite(wav00003, LOW);  // start second sound byte
    delay(50);
    digitalWrite(wav00003, HIGH);
    delay(1000);

    //Swing Right
    for (eyeXpos = 90; eyeXpos <= 130; eyeXpos += 1) {  // goes from 0 degrees to 180 degrees
      // in steps of 1 degree
      EyeRL.write(eyeXpos);  // tell servo to go to position in variable 'pos'
      delay(30);             // waits 15 ms for the servo to reach the position
    }
    // Swing Left past center
    for (eyeXpos = 130; eyeXpos >= 45; eyeXpos -= 1) {  // goes from 180 degrees to 0 degrees
      if (eyeXpos == 90) {
        BlinkEye();
      }

      EyeRL.write(eyeXpos);  // tell servo to go to position in variable 'pos'
      delay(30);             // waits 15 ms for the servo to reach the position
    }
    delay(500);
    //Swing back to center FAST
    for (eyeXpos = 45; eyeXpos <= 90; eyeXpos += 1) {  // goes from 0 degrees to 180 degrees
      // in steps of 1 degree
      EyeRL.write(eyeXpos);  // tell servo to go to position in variable 'pos'
      delay(10);             // waits 15 ms for the servo to reach the position
    }
    delay(3500);


    // Close Eye pull back sled and close Iris
    if (DEBUG == 1) {
      Serial.println("Starting Close Eye section");  //debug
    }
    CloseEyeSlow();
    SLED.write(0);
    delay(1100);  // wait for sled to finish moving
    IRIS.write(0);
    EyeRL.write(90);              // tell servo to go to position in variable 'pos'
    EyeUD.write(90);              // Basically center the Eye
    digitalWrite(wav00004, LOW);  // start forth sound byte
    delay(50);
    digitalWrite(wav00004, HIGH);

  }

  // End MOTION Sensed Routine

  else

  // Motion stopped routine
  {
    digitalWrite(LED, LOW);  // turn LED OFF
    delay(200);              // delay 200 milliseconds

    if (state == HIGH) {
      Serial.println("Motion stopped!");
      state = LOW;  // update variable state to LOW
    }
  }
  delay(5000);  //Delay so it won't immediatly re-trigger
}



//End of main loop, indivicual functions follow ----------------------------------------------------------------------------------------------------------------------------------------------------



void OpenEye() {
  EyeLids.write(OpenPosition);  // tell servo to go to position in variable 'pos'
}

void CloseEye() {
  EyeLids.write(ClosedPosition);  // tell servo to go to position in variable 'pos'                     // waits 15ms for the servo to reach the position
}


void BlinkEye() {
  ClosedPosition = ClosedPosition - 7;  // so the lids to crash TOO HARD
  CloseEye();
  delay(300);
  ClosedPosition = ClosedPosition + 7;  // and back so they close propperly at the end
  OpenEye();
}

void OpenEyeSlow()  // goes from ClosedPosition to OpenPosition at Speed OpenSpeed
{
  for (pos = ClosedPosition; pos >= OpenPosition; pos -= 1) {
    // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    EyeLids.write(pos);  // tell servo to go to position in variable 'pos'
    delay(OpenSpeed);    // waits for the servo to reach the position
  }
  digitalWrite(LED, HIGH);  // Show EyeLids OPEN/ON
}
// end OpenEyeSlow


void CloseEyeSlow()  // goes from OpenPosition to ClosedPosition at Speed OpenSpeed
{
  for (pos = OpenPosition; pos <= ClosedPosition; pos += 1) {  // goes from 180 degrees to 0 degrees
    // in steps of 1 degree
    EyeLids.write(pos);  // tell servo to go to position in variable 'pos'
    delay(CloseSpeed);   // waits for the servo to reach the position
  }
  digitalWrite(LED, LOW);  // Show EyeLids CLOSED/OFF
}
// end CloseEyeSlow

Some Pictures....

There is no "Schematic" as it was built as a flow diagram, a basic sketch was built to run -A- servo, and then code, then servo, then code, then 3D printing, then code...


The Small board next to the 20Kg servo is the Audio Board.

This is a view with the Iris Open and the eyelids open.

The FINAL version with have a Micro-Camera in the Middle of the Eyeball feeding a Pi running face recognition, but that's someone else's add-on project.

Yes, the Servo PWM pins go directly to the Nano.
Yes, those are unbent paperclips as rods.

There should be. Your thousand words do not paint a clear picture.

You do not need a drafting license to create a wiring diagram. Draw a bunch of boxes. Label the boxes. Label the I/O pins. Connect the pins. You will find this creation of a "big picture" invaluable when problems AND improvements arise. Do the right thing. Draw.

Here is where it is now....

(neat tool, does auto routing as well)

Nice! A real-life tomagotchi... Wokwi - Online ESP32, STM32, Arduino Simulator

Your input sensor (pin 8) seems to be floating when not pressed. This can cause false "button presses." Configure the sensor pin as INPUT_PULLUP, then make a couple changes to the program to read an unpressed button is HIGH and a pressed button is LOW.

Your use of delay() does not let the sensor detect movement unless the sensor stays "pressed" for many seconds.

Are your servos 180 or 360 degree? You are writing "270" to SLED... which is out of bounds for a 180 servo. It is far beyond "max CW" for a 360 servo... so I do not know what should happen with it.

This shows degrees for a servo 180...