Can anyone help me understanding the code to controlling a stepper motor by Arduino interfacing with micromanager

I found this code for this on this website https://sites.google.com/site/openspinmicroscopy/home/sub-systems/sample-rotation
but I don't know how this works. Here is the Code

/*
 * This goal of the application is to set the digital output on pins 8-13 
 * This can be accomplished in three ways.  First, a serial command can directly set
 * the digital output pattern.  Second, a series of patterns can be stored in the 
 * Arduino and TTLs coming in on pin 2 will then trigger to the consecutive pattern (trigger mode).
 * Third, intervals between consecutive patterns can be specified and paterns will be 
 * generated at these specified time points (timed trigger mode).
 *
 * Interface specifications:
 * digital pattern specification: single byte, bit 0 corresponds to pin 8, 
 *   bit 1 to pin 9, etc..  Bits 7 and 8 will not be used (and should stay 0).
 *
 * Set digital output command: 1p
 *   Where p is the desired digital pattern.  Controller will return 1 to 
 *   indicate succesfull execution.
 *
 * Get digital output command: 2
 *   Controller will return 2p.  Where p is the current digital output pattern
 *
 * Set Analogue output command: 3xvv
 *   Where x is the output channel (either 1 or 2), and vv is the output in a 
 *   12-bit significant number.
 *   Controller will return 3xvv:
 *
 * Get Analogue output:  4
 *
 *
 * Set digital patten for triggered mode: 5xd 
 *   Where x is the number of the pattern (currently, 12 patterns can be stored).
 *   and d is the digital pattern to be stored at that position.  Note that x should
 *   be the real number (i.e., not  ASCI encoded)
 *   Controller will return 5xd 
 *
 * Set the Number of digital patterns to be used: 6x
 *   Where x indicates how many digital patterns will be used (currently, up to 12
 *   patterns maximum).  In triggered mode, after reaching this many triggers, 
 *   the controller will re-start the sequence with the first pattern.
 *   Controller will return 6x
 *
 * Skip trigger: 7x
 *   Where x indicates how many digital change events on the trigger input pin
 *   will be ignored.
 *   Controller will respond with 7x
 *
 * Start trigger mode: 8
 *   Controller will return 8 to indicate start of triggered mode
 *   Stop triggered mode by sending any key (including new commands, that will be 
 *   processed).  Trigger mode will  stop blanking mode (if it was active)
 * 
 * Get result of Trigger mode: 9
 *   Controller will return 9x where x is the number of triggers received during the last
 *   trigger mode run
 *
 * Set time interval for timed trigger mode: 10xtt
 *   Where x is the number of the interval (currently, 12 intervals can be stored)
 *   and tt is the interval (in ms) in Arduino unsigned int format.  
 *   Controller will return 10x
 *
  * Sets how often the timed pattern will be repeated: 11x
 *   This value will be used in timed-trigger mode and sets how often the output
 *   pattern will be repeated. 
 *   Controller will return 11x
 *  
 * Starts timed trigger mode: 12
 *   In timed trigger mode, digital patterns as set with function 5 will appear on the 
 *   output pins with intervals (in ms) as set with function 10.  After the number of 
 *   patterns set with function 6, the pattern will be repeated for the number of times
 *   set with function 11.  Any input character (which will be processed) will stop 
 *   the pattern generation.
 *   Controller will retun 12.
 * 
 * Start blanking Mode: 20
 *   In blanking mode, zeroes will be written on the output pins when the trigger pin
 *   is low, when the trigger pin is high, the pattern set with command #1 will be 
 *   applied to the output pins. 
 *   Controller will return 20
 *
 * Stop blanking Mode: 21
 *   Stops blanking mode.  Controller returns 21
 *
 * Blanking mode trigger direction: 22x
 *   Sets whether to blank on trigger high or trigger low.  x=0: blank on trigger high,
 *   x=1: blank on trigger low.  x=0 is the default
 *   Controller returns 22
 *
 * 
 * Get Identification: 30
 *   Returns (asci!) MM-Ard\r\n
 *
 * Get Version: 31
 *   Returns: version number (as ASCI string) \r\n
 *
 * Read digital state of analogue input pins 0-5: 40
 *   Returns raw value of PINC (two high bits are not used)
 *
 * Read analogue state of pint pins 0-5: 41x
 *   x=0-5.  Returns analogue value as a 10-bit number (0-1023)
 *
 *
 * 
 * Possible extensions:
 *   Set and Get Mode (low, change, rising, falling) for trigger mode
 *   Get digital patterm
 *   Get Number of digital patterns
 */
#define DIR_PIN 2
#define STEP_PIN 3
 
   unsigned int version_ = 2;
   

   // pin on which to receive the trigger (either 2 or 3, changed attachInterrupt accordingly)
   int inPin_ = 7;  
   // pin connected to DIN of TLV5618
   int dataPin = 3;
   // pin connected to SCLK of TLV5618
   int clockPin = 4;
   // pin connected to CS of TLV5618
   int latchPin = 5;
   // pin connected to LDAC
   int LDACPin = 6;

  const int SEQUENCELENGTH = 12;  // this should be good enough for everybody;)
   byte triggerPattern_[SEQUENCELENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0};
   unsigned int triggerDelay_[SEQUENCELENGTH] = {0,0,0,0,0,0,0,0,0,0,0,0};
   int patternLength_ = 0;
   byte repeatPattern_ = 0;
   volatile int triggerNr_; // total # of triggers in this run (0-based)
   volatile int sequenceNr_; // # of trigger in sequence (0-based)
   int skipTriggers_ = 0;  // # of triggers to skip before starting to generate patterns
   byte currentPattern_ = 0;
   const unsigned long timeOut_ = 1000;
   bool blanking_ = false;
   bool blankOnHigh_ = true;
 
 void setup() {
   // Higher speeds do not appear to be reliable
   Serial.begin(57600);
  

   pinMode(inPin_, INPUT);
   pinMode(dataPin, OUTPUT);
   pinMode(clockPin, OUTPUT);
   pinMode(latchPin, OUTPUT);
   pinMode(LDACPin, OUTPUT);
   
   pinMode(DIR_PIN, OUTPUT);
   pinMode(STEP_PIN, OUTPUT);
    
   pinMode(8, OUTPUT);
   pinMode(9, OUTPUT);
   pinMode(10, OUTPUT);
   pinMode(11, OUTPUT);
   pinMode(12, OUTPUT);
   pinMode(13, OUTPUT);

   // Set analogue pins as input:
   DDRC = DDRC & B11000000;
   // Turn on build-in pull-up resistors
   PORTC = PORTC | B00111111;
 }
 
 void loop() {
   if (Serial.available() > 0) {
     int inByte = Serial.read();
     switch (inByte) {
       
       // Set digital output
     case 1 :
          if (waitForSerial(timeOut_)) {
            currentPattern_ = Serial.read();
            // Do not set bits 6 and 7 (not sure if this is needed..)
            currentPattern_ = currentPattern_ & B00111111;
            
            float vel=0.25;  ///velocity
            int mov=0;       //steps to move
           
            if (!blanking_){
              if(currentPattern_ == 2)       {mov=100*8; rotate(mov,vel); delay(500);}    // 180º             
              else if(currentPattern_ == 4)  {mov=50*8; rotate(mov,vel); delay(500);}     //  90º 
              else if(currentPattern_ == 6)  {mov=25*8;  rotate(mov,vel); delay(500);}    //  45º
              else if(currentPattern_ == 8)  {mov=10*8;  rotate(mov,vel); delay(500);}    //  18º
              else if(currentPattern_ == 10) {mov=5*8; rotate(mov,vel); delay(500);}      //   9º
              else if(currentPattern_ == 12) {mov=1*8; rotate(mov,vel); delay(500);}      //   1.8º
              else if(currentPattern_ == 40) {mov=1*4; rotate(mov,vel); delay(500);}      //   0.9º
              else if(currentPattern_ == 42) {mov=1*2; rotate(mov,vel); delay(500);}      //   0.45º
              else if(currentPattern_ == 44) {mov=1; rotate(mov,vel); delay(500);}        //   0.225º
              else if(currentPattern_ == 46) {mov=200*8; rotate(mov,vel); delay(500);}    // 360º
              
              else if(currentPattern_ == 3)   {mov=-100*8; rotate(mov,vel); delay(500);}    // 180º             
              else if(currentPattern_ == 5)  {mov=-50*8; rotate(mov,vel); delay(500);}     //  90º 
              else if(currentPattern_ == 7)  {mov=-25*8;  rotate(mov,vel); delay(500);}    //  45º
              else if(currentPattern_ == 9)  {mov=-10*8;  rotate(mov,vel); delay(500);}    //  18º
              else if(currentPattern_ == 11) {mov=-5*8; rotate(mov,vel); delay(500);}      //   9º
              else if(currentPattern_ == 13) {mov=-1*8; rotate(mov,vel); delay(500);}      //   1.8º
              else if(currentPattern_ == 41) {mov=-1*4; rotate(mov,vel); delay(500);}      //   0.9º
              else if(currentPattern_ == 43) {mov=-1*2; rotate(mov,vel); delay(500);}      //   0.45º
              else if(currentPattern_ == 45) {mov=-1; rotate(mov,vel); delay(500);}        //   0.225º
              else if(currentPattern_ == 47) {mov=-200*8; rotate(mov,vel); delay(500);}    // 360º
 
              
/*  //rotate a specific number of degrees 
  rotateDeg(360, 1);
  delay(1000);
  rotateDeg(-360, .1);  //reverse
  delay(1000); 
  //rotate a specific number of microsteps (8 microsteps per step)
  //a 200 step stepper would take 1600 micro steps for one full revolution
  rotate(1600, .5);
  delay(1000); 
  rotate(-1600, .25); //reverse
  delay(1000);  */

                        
              else {PORTB = currentPattern_;}
            }
            Serial.write( byte(1));
          }
          break;
       // Get digital output
       case 2:
          Serial.write( byte(2));
          Serial.write( PORTB);
          break;
          
       // Set Analogue output (TODO: save for 'Get Analogue output')
       case 3:
         if (waitForSerial(timeOut_)) {
         }
         break;
         
       // Sets the specified digital pattern
       case 5:
          if (waitForSerial(timeOut_)) {
            int patternNumber = Serial.read();
            if ( (patternNumber >= 0) && (patternNumber < SEQUENCELENGTH) ) {
              if (waitForSerial(timeOut_)) {
                triggerPattern_[patternNumber] = Serial.read();
                triggerPattern_[patternNumber] = triggerPattern_[patternNumber] & B00111111;
                Serial.write( byte(5));
                Serial.write( patternNumber);
                Serial.write( triggerPattern_[patternNumber]);
                break;
              }
            }
          }
          Serial.write( "n:");//Serial.print("n:");
          break;
          
       // Sets the number of digital patterns that will be used
       case 6:
         if (waitForSerial(timeOut_)) {
           int pL = Serial.read();
           if ( (pL >= 0) && (pL <= 12) ) {
             patternLength_ = pL;
             Serial.write( byte(6));
             Serial.write( patternLength_);
           }
         }
         break;
         
       // Skip triggers
       case 7:
         if (waitForSerial(timeOut_)) {
           skipTriggers_ = Serial.read();
           Serial.write( byte(7));
           Serial.write( skipTriggers_);
         }
         break;
         
       //  starts trigger mode
       case 8: 
         if (patternLength_ > 0) {
           sequenceNr_ = 0;
           triggerNr_ = -skipTriggers_;
           int state = digitalRead(inPin_);
           PORTB = B00000000;
           Serial.write( byte(8));
           while (Serial.available() == 0) {
             int tmp = digitalRead(inPin_);
             if (tmp != state) {
               if (triggerNr_ >=0) {
                 PORTB = triggerPattern_[sequenceNr_];
                 sequenceNr_++;
                 if (sequenceNr_ >= patternLength_)
                   sequenceNr_ = 0;
               }
               triggerNr_++;
             }
             state = tmp;
           }
           PORTB = B00000000;
         }
         break;
         
         // return result from last triggermode
       case 9:
          Serial.write( byte(9));
          Serial.write( triggerNr_);
          break;
          
       // Sets time interval for timed trigger mode
       // Tricky part is that we are getting an unsigned int as two bytes
       case 10:
          if (waitForSerial(timeOut_)) {
            int patternNumber = Serial.read();
            if ( (patternNumber >= 0) && (patternNumber < SEQUENCELENGTH) ) {
              if (waitForSerial(timeOut_)) {
                unsigned int highByte = 0;
                unsigned int lowByte = 0;
                highByte = Serial.read();
                if (waitForSerial(timeOut_))
                  lowByte = Serial.read();
                highByte = highByte << 8;
                triggerDelay_[patternNumber] = highByte | lowByte;
                Serial.write( byte(10));
                Serial.write(patternNumber);
                break;
              }
            }
          }
          break;

       // Sets the number of times the patterns is repeated in timed trigger mode
       case 11:
         if (waitForSerial(timeOut_)) {
           repeatPattern_ = Serial.read();
           Serial.write( byte(11));
           Serial.write( repeatPattern_);
         }
         break;

       //  starts timed trigger mode
       case 12: 
         if (patternLength_ > 0) {
           PORTB = B00000000;
           Serial.write( byte(12));
           for (byte i = 0; i < repeatPattern_ && (Serial.available() == 0); i++) {
             for (int j = 0; j < patternLength_ && (Serial.available() == 0); j++) {
               PORTB = triggerPattern_[j];
               delay(triggerDelay_[j]);
             }
           }
           PORTB = B00000000;
         }
         break;

       // Blanks output based on TTL input
       case 20:
         blanking_ = true;
         Serial.write( byte(20));
         break;
         
       // Stops blanking mode
       case 21:
         blanking_ = false;
         Serial.write( byte(21));
         break;
         
       // Sets 'polarity' of input TTL for blanking mode
       case 22: 
         if (waitForSerial(timeOut_)) {
           int mode = Serial.read();
           if (mode==0)
             blankOnHigh_= true;
           else
             blankOnHigh_= false;
         }
         Serial.write( byte(22));
         break;
         
       // Gives identification of the device
       case 30:
         Serial.println("MM-Ard");
         break;
         
       // Returns version string
       case 31:
         Serial.println(version_);
         break;

       case 40:
         Serial.write( byte(40));
         Serial.write( PINC);
         break;
         
       case 41:
         if (waitForSerial(timeOut_)) {
           int pin = Serial.read();  
           if (pin >= 0 && pin <=5) {
              int val = analogRead(pin);
              Serial.write( byte(41));
              Serial.write( pin);
              Serial.write( highByte(val));
              Serial.write( lowByte(val));
           }
         }
         break;
         
       case 42:
         if (waitForSerial(timeOut_)) {
           int pin = Serial.read();
           if (waitForSerial(timeOut_)) {
             int state = Serial.read();
             Serial.write( byte(42));
             Serial.write( pin);
             if (state == 0) {
                digitalWrite(14+pin, LOW);
                Serial.write( byte(0));
             }
             if (state == 1) {
                digitalWrite(14+pin, HIGH);
                Serial.write( byte(1));
             }
           }
         }
         break;

       }
    }
    if (blanking_) {
      if (blankOnHigh_) {
        if (digitalRead(inPin_) == LOW)
          PORTB = currentPattern_;
        else
          PORTB = 0;
      } else {
        if (digitalRead(inPin_) == LOW)
          PORTB = 0;
        else     
          PORTB = currentPattern_; 
      }
    }
}

 
bool waitForSerial(unsigned long timeOut)
{
    unsigned long startTime = millis();
    while (Serial.available() == 0 && (millis() - startTime < timeOut) ) {}
    if (Serial.available() > 0)
       return true;
    return false;
 }

// Sets analogue output in the TLV5618
// channel is either 0 ('A') or 1 ('B')
// value should be between 0 and 4095 (12 bit max)
// pins should be connected as described above






/* 
 // This function is called through an interrupt   
void triggerMode() 
{
  if (triggerNr_ >=0) {
    PORTB = triggerPattern_[sequenceNr_];
    sequenceNr_++;
    if (sequenceNr_ >= patternLength_)
      sequenceNr_ = 0;
  }
  triggerNr_++;
}
void blankNormal() 
{
    if (DDRD & B00000100) {
      PORTB = currentPattern_;
    } else
      PORTB = 0;
}
void blankInverted()
{
   if (DDRD & B00000100) {
     PORTB = 0;
   } else {     
     PORTB = currentPattern_;  
   }
}   
*/

void rotate(int steps, float speed){
  //rotate a specific number of microsteps (8 microsteps per step) - (negitive for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  int dir = (steps > 0)? HIGH:LOW;
  steps = abs(steps);

  digitalWrite(DIR_PIN,dir); 

  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay); 

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);
  }
} 

void rotateDeg(float deg, float speed){
  //rotate a specific number of degrees (negitive for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  int dir = (deg > 0)? HIGH:LOW;
  digitalWrite(DIR_PIN,dir); 

  int steps = abs(deg)*(1/0.225);
  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay); 

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);
  }
}

I have to make the code as it will take input of wavelength or steps and move to that position The monochromator i am going to use is Horiba / Spex 1681B ( Horiba / Spex 1681B 0.22m Spectrometer - Price, Specs) it has the maximum step of 500 steps/sec.

Please post the code here, using code tags as adviced in the topic How to get the best from this forum.

1 Like

I have posted the code. My aim of the project is to control a Grating movement of a monochromator using stepper motor interfacing to the Micromanager. For testing, I am using an Arduino Uno, drv8825 motor driver and Nema 17 (42mm) motor.

Didn't read the instructions though. :roll_eyes:

Much better. :grin:

1 Like

Thanks!
Most helpers dislike, or refuse, downloading data. Sometimes dirty instructions can be hidden, Anyway, downloading fills up helpers computers needing cleaning some day....

1 Like

Here is the code( i don't need a Screen so I can remove that part) (Nema 17(42mm) stepper motor)

// An arduino firmware that can be used with the Micro-Manager LStep Z-Stage device adaptor.
// Allows building simple 1-axis stage devices.
// version 0.1
// JM 2016-2018

// References
// https://micro-manager.org/wiki/MarzhauserLStep
// MM device adaptor code /DeviceAdapters/Marzhauser-LStep/LStep.cpp
// LStep documentation from www.marzhauser.com/nc/en/service/downloads.html

// in HCW, use serial port settings:
// AnswerTimeout,3000.0000
// BaudRate,9600
// DelayBetweenCharsMs,0.0000
// Handshaking,Off
// Parity,None
// StopBits,1

#include <Servo.h>
Servo myservo; 
int servoPin = 3;
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String cmd = "" ;
float z = 0.0;

void setup() {
  Serial.begin( 9600 );
  myservo.attach(servoPin);
  lcd.begin(16, 2);
  lcd.print("MiFoBio 2018");
  lcd.setCursor(0, 1);
  lcd.print("vLStep-Z ready");
  delay(1000);
  reply ("Vers:LS");
}
char c = '*';

void loop()
{
  if (Serial.available()) {
    cmd = Serial.readStringUntil('\r');
    processCommand(cmd);
    cmd = "";
  }
}

void processCommand(String s) {
  if (s.startsWith("?ver")) {
    reply ("Vers:LS");
  } else if (s.startsWith("!autostatus 0")) {
    delay(5);
  } else if (s.startsWith("?det")) {
    reply ("60");
  } else if (s.startsWith("?pitch z")) {
    reply ("50.0");
  } else if (s.startsWith("?vel z")) {
    reply ("100.0");
  } else if (s.startsWith("?accel z")) {
    reply ("1.0");
  } else if (s.startsWith("!dim z 1")) {
    delay(5);
  } else if (s.startsWith("!dim z 2")) {
    delay(5);
  } else if (s.startsWith("?statusaxis")) {
    reply ("@");
  } else if (s.startsWith("!vel z")) {
    delay(5);
  } else if (s.startsWith("!accel z")) {
    delay(5);
  } else if (s.startsWith("?pos z")) {
    String zs = String(z, 1);
    reply (zs);
    lcd.clear();
    lcd.print("MiFoBio 2018");
    lcd.setCursor(0, 1);
    lcd.print("Z:");
    lcd.print(zs);
  } else if (s.startsWith("?lim z")) {
    reply ("0.0 100.0");
  } else if (s.startsWith("!pos z")) {
    delay(5);
  } else if (s.startsWith("?status")) {
    reply ("OK...");
  } else if (s.startsWith("!dim z 0")) {
    delay(5);
  } else if (s.startsWith("!speed z")) {
    delay(5);
  } else if (s.startsWith("!mor z")) {
    String delta = s.substring(s.indexOf("z") + 1);
    z = z + delta.toFloat();
    turnServo();
  } else if (s.startsWith("!moa z")) {
    String apos = s.substring(s.indexOf("z") + 1);
    z = apos.toFloat();
    turnServo();
  } else if (s.startsWith("?err")) {
    reply ("0");
  }
}

void reply(String s) {
  Serial.print(s);
  Serial.print("\r");
}

void turnServo() {
    myservo.write(map(z,-100,100,0,180));
  }
/*
  // "?ver"   ->   Vers:LS
  // "?det"   ->   11F31  seul le 2nd least significant byte (le 3) est important = 3 axes
  // "?statusaxis" -> @ si dispo et M si busy
  // "!autostatus 0"
  // "?pitch z" -> 50.0
  // "!dim z 2" mettre en microns
  // "!dim z 1"
  // "?vel z"  -> 100.0
  // "!vel z 100"
  // "?accel z" -> 1.0
  // "!accel z 1"
  "a" -> abort ??
  "!moa z 10"  move z to absolute 10
  // "?err"  retourner 0
  // "!mor z " move z by relative 10
  // "?pos z" query current z pos -> return z pos
  // "?lim z" query limits, -> 0.0 100.0
  // "!pos z 0" set origin
  // "!pos z 20 fixe cette origine pour le controlle
  // "?status"  -> OK...
  "!dim z 0" set as steps.
  "MOA Z " move to abs step pos
  "?pos z" get position as steps
  //"!speed z 10" lance le mouvement en mm/sec
*/

A stepper motor is NOT programmed. You program for the controller board that does control the stepper. What do you have?

I have a Nema 17 42 mm stepper motor , Drv8825 Driver and Arduino Uno and i want to interface it with micromanager so that i can control the steps.

A servo will go to an absolute position on command. A stepper won't. You will likely need to home the stepper on startup so you know where it is. Often this is done with a microswitch.

Can I do the homing using any code? And I don't know anything about coding in Arduino I am completely new to this so what changes i need to make in the code for the library it should be <AccelStepper.h> and any other library?

A servo knows where the home or ZERO position is located. A stepper motor does not know this and your first thing to do is strictly mechanical. Your stepper needs something attached to the rotating axle that can be used to indicate where your ZERO position is located. That can be a micro switch, any other sensor or could be a mechanical stop of some kind to stop the motor rotation at that position.

All the code to do this MUST be added to your program in the setup() part.

Have you looked at any of the available programs that use a stepper motor? You will almost always find a part of the program that senses a starting position.

Thank you. I have found many programs for the Driver and stepper motor like this

// Include the AccelStepper Library
#include <AccelStepper.h>

// Define pin connections
const int dirPin = 2;
const int stepPin = 3;

// Define motor interface type
#define motorInterfaceType 1

// Creates an instance
AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
	// set the maximum speed, acceleration factor,
	// initial speed and the target position
	myStepper.setMaxSpeed(1000);
	myStepper.setAcceleration(50);
	myStepper.setSpeed(200);
	myStepper.moveTo(200);
}

void loop() {
	// Change direction once the motor reaches target position
	if (myStepper.distanceToGo() == 0) 
		myStepper.moveTo(-myStepper.currentPosition());

	// Move the motor one step
	myStepper.run();
}

But i don't know how can i use this to interface it with micromanager.

Get it working first and then worry about the interfacing when the program is working properly.

Okay so I tested these codes and it worked for the stepper motor. Here is another programme that i found for 5 revolutions clockwise and counterclockwise.

/*Example sketch to control a stepper motor with A4988/DRV8825 stepper motor driver and Arduino without a library. More info: https://www.makerguides.com */

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define stepsPerRevolution 200

void setup() {
  // Declare pins as output:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop() {
  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 1 revolution slowly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(2000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(2000);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  // Spin the stepper motor 1 revolution quickly:
  for (int i = 0; i < stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }

  delay(1000);

  // Set the spinning direction clockwise:
  digitalWrite(dirPin, HIGH);

  // Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);

  // Set the spinning direction counterclockwise:
  digitalWrite(dirPin, LOW);

  //Spin the stepper motor 5 revolutions fast:
  for (int i = 0; i < 5 * stepsPerRevolution; i++) {
    // These four lines result in 1 step:
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
  }

  delay(1000);
}

Good!
Now what does the servo do that you can duplicate with this program you have tested?

For the original code above the servo one in that thing after I interface it with micromanager it moves according to the Z stage movement like I can move it 10um or 1um
stage control
Using this stage control.
So I need to do the same for the stepper motor.

But you need to determine the amount of movement from the servo viewpoint, so you can duplicate it in the stepper.
Can we presume you have already determined the minimum amount to turning the servo does and have matched that with your stepper?

My aim is to control a Grating in a monochromator ( like wavelength 550nm to 700 )
So if my stepper motor is 500 step/s then it should take 10nm or 1nm steps.
I found someone who worked on the monochromator he control it using buttons on a controller(Arduino Uno and A screen and Three buttons) but I need to control it using the micromanager( And I don't know much about it) here is the Code

#include <TFT.h>
#include <SPI.h>

//define pins for screen
#define LCD_RESET 8
#define CS   10
#define DC   9

//define pins for grating control
#define DIRECTION 3
#define STEP  5
#define LSWL 6//Limit switch low
#define LSWH 7//Limit switch high

//define pins for inputs
#define UP 0
#define DOWN 1
#define GO 2

TFT myScreen = TFT(CS, DC, LCD_RESET);
int wl_now = 666;
int wl_set = 666;
char print_now[4];
char print_set[4];
String str;



const int wl_max = 750;//?????????????
const int wl_min = 550;//?????????????
const int wl_step = 49;//0.1;// steps needed to move 1nm according to the rotary display

int calibModeLow = 0;
int calibModeHigh = 0;
int calibratedLow = 0;
int calibratedHigh = 0;

void updateNowVal() {
  str = String(wl_now);
  str.toCharArray(print_now,4);
  myScreen.stroke(255,255,255);
  myScreen.fill(255,255,255); //white
  myScreen.rect(5,72,40,15); // draw white box to clear text
  myScreen.stroke(0,0,0);
  myScreen.text(print_now,5,72); 
}

void updateSetVal() {
  str = String(wl_set);
  str.toCharArray(print_set,4);
  myScreen.stroke(255,255,255);
  myScreen.fill(255,255,255); //white
  myScreen.rect(5,109,40,15); // draw white box to clear text
  myScreen.stroke(0,0,0);
  myScreen.text(print_set,5,109); 
}

void checkButtons() {
  int upState = digitalRead(UP);
  int downState = digitalRead(DOWN);
  int goState = digitalRead(GO);
  myScreen.fill(255,255,255); // white
  myScreen.stroke(255,255,255);
  
  if(!upState && !downState && !goState){
    calibrationDecider();//enter calibration mode low, press 3 buttons a gain to go to calibration mode high, and again to exit calibration mode
  }
  
  if(upState==0){
    wl_set++;
    //myScreen.text("UP!",80,109);
    delay(100);
    //myScreen.stroke(255,255,255);
    //myScreen.rect(80,109,30,15);
    //myScreen.stroke(0,0,0);
    updateSetVal();
  }
  if(downState==0){
    wl_set--;
    //myScreen.text("DOWN!",80,109);
    delay(100);
    //myScreen.stroke(255,255,255);
    //myScreen.rect(80,109,30,15);
    //myScreen.stroke(0,0,0);
    updateSetVal();

  }
  if(goState==0){
    int higherLower = 0;
    if(wl_set>wl_now){
      higherLower = 1;
    }
    moveGrating(higherLower);
  }
}

void moveGrating(int upDown)  {
  //make the circle red to say it's moving
  myScreen.fill(255,0,0); // red
  myScreen.circle(135,100,20);
  // activate the grating movement then turn off the red circle
  digitalWrite(DIRECTION,upDown);//set direction pin (1 is up, 0 is down)
  // move up
  if(upDown){
   for(int i=wl_now; i<=wl_set; i++){
    for(int j=0; j <=wl_step; j++){
       // if (checkLimitsOK()){
          digitalWrite(STEP,1);
          //delay(50);
          digitalWrite(STEP,0);
          //delay(50);
           //wl_now = (i/wl_step);
          //updateNowVal();
          //Serial.print(i);
         //Serial.print('/n');
       }
       wl_now = i;
       updateNowVal();
    }
  }
    if(!upDown){
    for(int i=wl_now; i>=wl_set; i--){
      for(int j=0;j <=wl_step; j++){
    // if (checkLimitsOK()){
        digitalWrite(STEP,1);
        //delay(50);
        digitalWrite(STEP,0);
        //delay(50); 
        //wl_now = i/wl_step;
        //updateNowVal();
        //Serial.print(i);
        //Serial.print('/n');
      }
     wl_now = i;
     updateNowVal();
    }
  }
  //delay(50);
  //make the circle green to say it's OK
  myScreen.fill(0,255,0); // green
  myScreen.circle(135,100,20);
}

int checkLimitsOK(){
  int high = digitalRead(LSWH);
  int low = digitalRead(LSWL);  
  if(high || low){
    return(0);//return 0 if not ok
    if(high){
      wl_set = wl_max;
      wl_now = wl_max;
      myScreen.text("LS high",10,25);
      updateSetVal();
      updateNowVal();
      delay(1000);
  }
    if(low){
      wl_set = wl_min;
      wl_now = wl_min;
      myScreen.text("LS low",10,35);
      updateSetVal();
      updateNowVal();
      delay(1000);
    }
    
  }
  else{
    //myScreen.text("LS OK",10,45);
    return(1);//return 1 if ok
  }
}


void homing(){
  myScreen.text("Homing to min",20,15);
  digitalWrite(DIRECTION,0);
  while(checkLimitsOK()){
    digitalWrite(STEP,1);
    delay(10);
    digitalWrite(STEP,0);
    delay(10);
  }
 /* while(checkLimitsOK()){
    moveGrating(0);
  }*/
  wl_set = wl_min;
  wl_now = wl_min;
  delay(1000);
  myScreen.text("Homing to max",20,15);
    while(checkLimitsOK()){
    moveGrating(1);
  }
  wl_set = wl_max;
  wl_now = wl_max;
  myScreen.text("Homing complete",20,15);
  }

void calibrationDecider(){ // activate this by holding all three buttons
  /* these are my flags
  int calibModeLow = 0;
  int calibModeHigh = 0;
  int calibratedLow = 0;
  int calibratedHigh = 0;*/
  if (!calibModeLow && !calibModeHigh){ // if neither flag set, go to calibModeLow
    calibModeLow=1;
    calibScreen(0);
    return;
  } 
  if (calibModeLow && !calibModeHigh){ // if in low mode go to high mode & set that low calib has been done
    wl_set = wl_min;//set to 550 nm or whatever it is
    wl_now = wl_min;
    calibScreen(1);
    calibModeLow=0;
    calibratedLow=1;
    calibModeHigh=1;
    return;
  }
  if (!calibModeLow && calibModeHigh){ // if in high mode set that high calib has been done and go back to normal mode
    normalScreen();
    wl_set = wl_max;//set to 750 nm or whatever it is
    wl_now = wl_max;
    calibModeHigh=0;
    calibratedLow=1;
    calibratedHigh=1;
    return;
  }
  
}

void calibScreen(int mode){
  if(!mode){ // calib mode low
  myScreen.fill(255,255,255); 
  myScreen.rect(0,0,150,20); // clear the top with white
  myScreen.stroke(0,0,0);
  myScreen.setTextSize(2);
  myScreen.text("Calibration mode!",5,1);
  myScreen.stroke(255,255,255);
  myScreen.rect(0,55,150,20);
  myScreen.stroke(0,0,0);
  myScreen.text("find 550 nm",5,55);
  }
  if(mode){ // calib mode high
    myScreen.fill(255,255,255); 
  myScreen.rect(0,0,150,20); // clear the top with white
  myScreen.stroke(0,0,0);
  myScreen.setTextSize(2);
  myScreen.text("Calibration mode!",5,1);
  myScreen.stroke(255,255,255);
  myScreen.rect(0,55,150,20);
  myScreen.stroke(0,0,0);
  myScreen.text("find 750 nm",5,55);
  }
  return;
}

void normalScreen(){
  myScreen.background(255,255,255);  // clear the screen with white
  myScreen.stroke(0,0,0);
  myScreen.setTextSize(2);
  delay(500);  // pause for dramatic effect
 
  myScreen.text("MONOCHROMATOR!!!",5,1);
  myScreen.fill(200,0,200); // violet
  myScreen.rect(0,20,22,22);
  myScreen.fill(100,0,200); // indigo
  myScreen.rect(23,20,22,22);
  myScreen.fill(0,0,255); // blue
  myScreen.rect(46,20,22,22);
  myScreen.fill(0,255,0); // green
  myScreen.rect(69,20,22,22);
  myScreen.fill(255,255,0); // yellow
  myScreen.rect(92,20,22,22);
  myScreen.fill(255,66,0); // orange
  myScreen.rect(115,20,22,22);
  myScreen.fill(255,0,0); // red
  myScreen.rect(138,20,22,22);
}

void dramaticIntro(){
  myScreen.background(255,255,255);  // clear the screen with black
  myScreen.stroke(0,0,0);
  myScreen.setTextSize(2);
  delay(1000);  // pause for dramatic effect
 
  myScreen.text("MONOCHROMATOR!!!",5,1);
  delay(1000);
  myScreen.fill(200,0,200); // violet
  myScreen.rect(0,20,22,22);
  delay(100);
  myScreen.fill(100,0,200); // indigo
  myScreen.rect(23,20,22,22);
  delay(100);
  myScreen.fill(0,0,255); // blue
  myScreen.rect(46,20,22,22);
  delay(100);
  myScreen.fill(0,255,0); // green
  myScreen.rect(69,20,22,22);
  delay(100);
  myScreen.fill(255,255,0); // yellow
  myScreen.rect(92,20,22,22);
  delay(100);
  myScreen.fill(255,66,0); // orange
  myScreen.rect(115,20,22,22);
  delay(100);
  myScreen.fill(255,0,0); // red
  myScreen.rect(138,20,22,22);
  delay(1000);

  myScreen.text("WAVELENGTH:",5,55);
  myScreen.text("SET TO:",5,92);
  
  myScreen.text("nm",50,72);
  myScreen.text("nm",50,109);  
}

void setup() {
  pinMode(DIRECTION, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(LSWL, INPUT);
  pinMode(LSWH, INPUT);
  pinMode(UP, INPUT_PULLUP);
  pinMode(DOWN, INPUT_PULLUP);
  pinMode(GO, INPUT_PULLUP);
  
  Serial.begin(9600);
  Serial.print("hello");
  
  myScreen.begin();  
  dramaticIntro();

 // myScreen.stroke(255,255,255);
 // myScreen.fill(255,255,255); // white

  updateNowVal();
  
  // homing();
  delay(1000);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  check button();
  
}

In this code, only the 1nm UP button is working. I don't want to use buttons to control it.
The aim is to move UP or Down or either to a specific wavelength.

We know even less. Please tell.