I'm building an antenna rotator based on SatNOGS v2 and I need programming help

Hi, before anything please consider that I'm a complete noob. And I have a few doubts and questions that may seem ridiculous to you so please go easy on me :smiley:

So I'm building an antenna rotator based on SatNOGS v2 which is the one that looks easiest to build for me, they are using an Arduino Pro Mini connected to their own controller board, I intend using stronger steppers controlled with TB6600 controllers, by looking at their code I'm having some questions. First one there's this:

#define DIR_AZ 18 //PIN for Azimuth Direction

but looking at the arduino pro mini pinout I find no pin 18

Then there's this:

#define MS1 9 //PIN for step size

but the stepper controllers (TB6600) don't have a step size connection, it's done using dip switches.

Also another thing I would like to do it control it via WIFI, someone told me that the code could be changed to work directly using an ESP32 or leave the code unchanged and use a separate ESP32 connected to a regular arduino to act as a WIFI to Serial converter, how would I do that and how would I interconnect both boards?

I know these are noob questions but the only experience with arduinos was bulding a 3d printed clock which was basically just write the code to the arduino nano and connecting like the diagram and it just worked, but this is a bit more complex for me.

The only thing different in terms of hardware is I'm using 50:1 gear ratio instead of 60:1 and I'm using larger steppers with different controllers, I'll be also using to optical homing sensors.

I can't upload files because I'm new so I hope I don't break any rules by pasting it here:

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <AccelStepper.h>

#define DIR_AZ 18 //PIN for Azimuth Direction
#define STEP_AZ 10 //PIN for Azimuth Steps
#define DIR_EL 6 //PIN for Elevation Direction
#define STEP_EL 7 //PIN for Elevation Steps

#define MS1 9 //PIN for step size
#define EN 8 //PIN for Enable or Disable Stepper Motors

#define SPR 200 //Step Per Revolution
#define RATIO 60 //Gear ratio
#define T_DELAY 60000 //Time to disable the motors in millisecond

#define HOME_AZ 4 //Homing switch for Azimuth
#define HOME_EL 5 //Homing switch for Elevation
/*The MAX_ANGLE depends of ANGLE_SCANNING_MULT and maybe misbehave for large values*/
#define ANGLE_SCANNING_MULT 180 //Angle scanning multiplier
#define MAX_AZ_ANGLE 360 //Maximum Angle of Azimuth for homing scanning
#define MAX_EL_ANGLE 360 //Maximum Angle of Elevation for homing scanning

#define HOME_DELAY 6000 //Time for homing Decceleration in millisecond

/*Global Variables*/
unsigned long t_DIS = 0; //time to disable the Motors
/*Define a stepper and the pins it will use*/
AccelStepper AZstepper(1, STEP_AZ, DIR_AZ);
AccelStepper ELstepper(1, STEP_EL, DIR_EL);

void setup()
{  
  /*Change these to suit your stepper if you want*/
  AZstepper.setMaxSpeed(150);
  AZstepper.setAcceleration(50);
  
  /*Change these to suit your stepper if you want*/
  ELstepper.setMaxSpeed(150);
  ELstepper.setAcceleration(50);
  
  /*Enable Motors*/
  pinMode(EN, OUTPUT);
  digitalWrite(EN, LOW);
  /*Step size*/
  pinMode(MS1, OUTPUT);
  digitalWrite(MS1, LOW); //Full step
  /*Homing switch*/
  pinMode(HOME_AZ, INPUT);
  pinMode(HOME_EL, INPUT);
  /*Serial Communication*/
  Serial.begin(19200);
  /*Initial Homing*/
  Homing(deg2step(-ANGLE_SCANNING_MULT), deg2step(-ANGLE_SCANNING_MULT));
}

void loop()
{ 
  /*Define the steps*/
  static int AZstep = 0;
  static int ELstep = 0;
  /*Time Check*/
  if (t_DIS == 0)
    t_DIS = millis();

  /*Disable Motors*/
  if (AZstep == AZstepper.currentPosition() && ELstep == ELstepper.currentPosition() && millis()-t_DIS > T_DELAY)
  {
    digitalWrite(EN, HIGH);
  }
  /*Enable Motors*/
  else
    digitalWrite(EN, LOW);
    
  /*Read the steps from serial*/
  cmd_proc(AZstep, ELstep);
  /*Move the Azimuth & Elevation Motor*/
  stepper_move(AZstep, ELstep);
}

/*Homing Function*/
void Homing(int AZsteps, int ELsteps)
{
  int value_Home_AZ = HIGH;
  int value_Home_EL = HIGH;
  int n_AZ = 1; //Times that AZ angle has changed
  int n_EL = 1; //Times that EL angle has changed
  boolean isHome_AZ = false;
  boolean isHome_EL = false;
  
  AZstepper.moveTo(AZsteps);
  ELstepper.moveTo(ELsteps);
  
  while(isHome_AZ == false || isHome_EL == false)
  {
    value_Home_AZ = digitalRead(HOME_AZ);
    value_Home_EL = digitalRead(HOME_EL);
    /* Change to LOW according to Home sensor */
    if (value_Home_AZ == HIGH)
    {
      AZstepper.moveTo(AZstepper.currentPosition());
      isHome_AZ = true;
    }   
    /* Change to LOW according to Home sensor */
    if (value_Home_EL == HIGH)
    {
      ELstepper.moveTo(ELstepper.currentPosition());
      isHome_EL = true;
    }
    if (AZstepper.distanceToGo() == 0 && !isHome_AZ)
    {
      n_AZ++;
      AZsteps = deg2step(pow(-1,n_AZ)*n_AZ*ANGLE_SCANNING_MULT);
      if (abs(n_AZ*ANGLE_SCANNING_MULT) > MAX_AZ_ANGLE)
      {
        error(0);
        break;
      }
      AZstepper.moveTo(AZsteps);
    } 
    if (ELstepper.distanceToGo() == 0 && !isHome_EL)
    { 
      n_EL++;
      ELsteps = deg2step(pow(-1,n_EL)*n_EL*ANGLE_SCANNING_MULT);
      if (abs(n_EL*ANGLE_SCANNING_MULT) > MAX_EL_ANGLE)
      {
        error(1);
        break;
      }
      ELstepper.moveTo(ELsteps);
    }
    
    AZstepper.run();
    ELstepper.run();
  }
  /*Delay to Deccelerate*/
  long time = millis();  
  while(millis() - time < HOME_DELAY)
  {  
    AZstepper.run();
    ELstepper.run();
  }
  /*Reset the steps*/
  AZstepper.setCurrentPosition(0);
  ELstepper.setCurrentPosition(0); 
}
 
/*EasyComm 2 Protocol & Calculate the steps*/
void cmd_proc(int &stepAz, int &stepEl)
{
  /*Serial*/
  char buffer[256];
  char incomingByte;
  char *p=buffer;
  char *str;
  static int counter=0;
  char data[100];
  
  double angleAz,angleEl;
  
  /*Read from serial*/
  while (Serial.available() > 0)
  {
    incomingByte = Serial.read();
    /* XXX: Get position using custom and test code */
    if (incomingByte == '!')
    {
      /* Get position */
      Serial.print("TM");
      Serial.print(1);
      Serial.print(" ");
      Serial.print("AZ");
      Serial.print(10*step2deg(AZstepper.currentPosition()), 1);
      Serial.print(" ");
      Serial.print("EL");
      Serial.println(10*step2deg(ELstepper.currentPosition()), 1);
    }
    /*new data*/
    else if (incomingByte == '\n')
    {
      p = buffer;
      buffer[counter] = 0;
      if (buffer[0] == 'A' && buffer[1] == 'Z')
      {
        if (buffer[2] == ' ' && buffer[3] == 'E' && buffer[4] == 'L')
        {
          /* Get position */
          Serial.print("AZ");
          Serial.print(step2deg(AZstepper.currentPosition()), 1);
          Serial.print(" ");
          Serial.print("EL");
          Serial.print(step2deg(ELstepper.currentPosition()), 1);
          Serial.println(" ");
        }
        else
        {
          /*Get the absolute value of angle*/
          str = strtok_r(p, " " , &p);
          strncpy(data, str+2, 10);
          angleAz = atof(data);
          /*Calculate the steps*/
          stepAz = deg2step(angleAz);

          /*Get the absolute value of angle*/
          str = strtok_r(p, " " , &p);
          if (str[0] == 'E' && str[1] == 'L')
          {
            strncpy(data, str+2, 10);
            angleEl = atof(data);
            /*Calculate the steps*/
            stepEl = deg2step(angleEl);
          }
        }
      }
      /* Stop Moving */
      else if (buffer[0] == 'S' && buffer[1] == 'A' && buffer[2] == ' ' && buffer[3] == 'S' && buffer[4] == 'E')
      {
        /* Get position */
        Serial.print("AZ");
        Serial.print(step2deg(AZstepper.currentPosition()), 1);
        Serial.print(" ");
        Serial.print("EL");
        Serial.println(step2deg(ELstepper.currentPosition()), 1);
        stepAz = AZstepper.currentPosition();
        stepEl = ELstepper.currentPosition();
      }
      /* Reset the rotator */
      else if (buffer[0] == 'R' && buffer[1] == 'E' && buffer[2] == 'S' && buffer[3] == 'E' && buffer[4] == 'T')
      {
        /* Get position */
        Serial.print("AZ");
        Serial.print(step2deg(AZstepper.currentPosition()), 1);
        Serial.print(" ");
        Serial.print("EL");
        Serial.println(step2deg(ELstepper.currentPosition()), 1);
        /*Move the steppers to initial position*/
        Homing(0,0);
        /*Zero the steps*/
        stepAz = 0;
        stepEl = 0;
      }      
      counter = 0;
      /*Reset the disable motor time*/
      t_DIS = 0;
    }
    /*Fill the buffer with incoming data*/
    else {
      buffer[counter] = incomingByte;
      counter++;
    }
  }
}

/*Error Handling*/
void error(int num_error)
{
  switch (num_error)
  {
    /*Azimuth error*/
    case (0):
      while(1)
      {
        Serial.println("AL001");
        delay(100);
      }
    /*Elevation error*/
    case (1):
      while(1)
      {
        Serial.println("AL002");
        delay(100);
      }
    default:
      while(1)
      {
        Serial.println("AL000");
        delay(100);
      }
  }
}

/*Send pulses to stepper motor drivers*/
void stepper_move(int stepAz, int stepEl)
{
  AZstepper.moveTo(stepAz);
  ELstepper.moveTo(stepEl);
    
  AZstepper.run();
  ELstepper.run();
}

/*Convert degrees to steps*/
int deg2step(double deg)
{
  return(RATIO*SPR*deg/360);
}

/*Convert steps to degrees*/
double step2deg(int Step)
{
  return(360.00*Step/(SPR*RATIO));
}

We can tell that because you are trying to modify something without ever building and testing it. Build the exact duplicate of the system you are going to emulate. Get it to work properly, then begin to substitute, one at a time, the components for your end design.

I just want to build a more robust rotator, metal worm gears, etc. If I could write the program from scratch I would but unfortunately I need help for that so rather than taking a degree in programming, I chose the satNOGS v2 because it's the one that seems more similar to what I would like to conceive. At first I thought it would be just as simple as just changing the gear ratio. But then I look at the code and see pin assignments that doesn't seem right.

I could leave the wifi aspect of it for last, but as for the pin assignment is it as easy as just setting to any other GPIO I want?

It is, all things being equal. That is what you have to determine from the specifications for each of the pins. Will your new pin be able to do the same functions are the original pin?

Well assuming that pin 18 is the direction signal it either needs to be high or low.

Well, if I use an Arduino Pro Mini which is the same they use, can you tell me which is pin 18? Because looking at the pinouts I can't find any. I don't mind using the same Arduino, but they use the Arduino as a daughter board connected to their own custom built board and their schematic also doesn't reference any pin 18 connection, it's all really confusing.

So, they lied. Either not using a pro-mini or the code is not their final version. Have you asked the site where you found the project?

On any of the mega328 based boards (Uno, Nano, Pro Mini) pin 18 is the same as A4 (analog input). The analog pins are really digital pins with analog input as a special function. Thty are pins 14 (A0) - 19 (A5).

Thank you so much! So as for the MS1 (step size pin) I see it referencing in the code to set it to full step and that's all. I assume that using the TB6600 controllers, I would set the controller to full step and I could just ignore that pin connection. Is this correct?

Yes, I suppose so since, as far as I know, there is no way to control micro-stepping programmatically with the TB6600 driver.

But I would recommend that you use some level of micro-stepping (x4 or more) to mitigate potential resonance problems. Especially if your mechanical setup is mechanically stiff (lead screw, metal gear train).
See here for information on stepper motor resonance. >> What is stepper motor resonance and how can it be avoided?

If step size relates to steps per degree of rotation, micro-stepping will have to be taken into account. Without micro-stepping and a 200 step/rev motor your granularity is 1.8 degrees per step. Micro-stepping will reduce granularity in proportion to the micro-step ratio. Micro_stepping x4reduces granularity to 0.45 degrees.

1 Like

Suppose I decide to use 1/4 stepping, all I would have to do is multiply the steps per rotation by 4? In this case 200x4=800?

Is there also any downside to micro stepping?

Yes. But only when you first power the stepper motor. They only start on a full step. There is a second down side in that it will take longer for your code to find the homing position for your stepper motor.

That is correct.

With a 60:1 gear reduction, 200 * 4 * 60 = 48000 steps per output shaft revolution, or 0.0075 degrees per step.

1 Like

So I built the rotator and I think all connections are OK as it's doing the homing sequence and all, but how do I interact with it? The Arduino is showing on my PC as COM3, I'm trying Gpredict but it sends data by a TCP connection, I tried the program "Serial-TCP" to act as a bridge to convert TCP to serial data through COM3, someone on Facebook asked if I installed the Hamlib library, how do I do that?

I managed to get the rotator working, but it's way to noisy! I tried using 4x micro-stepping, I set controllers and the Arduino to 800 steps per revolution and I also multiplied the max speed and acceleration by 4, it made it quieter but now the angles are off, for instance if I set the rotator to 90ΒΊ it turns to around 45ΒΊ, any idea why?

For informed help, please read and follow the directions in the "How to get the best out of this forum" post.

Post the code, using code tags, and links to the motors and drivers, etc.

any idea why?

Incorrect assumptions and/or code.

There is no include for that library in the originally posted code. Are you running different code than what is posted? If so, we need to see the latest code to be able to comment on it.

How to install an Arduino library (IDE 2+).

How to install an Arduino library (IDE 1+).

It does not look like that particular library is available via the library manager. You will probably need to do a manual install.

Is this the library? >> GitHub - Hamlib/Hamlib: Ham radio control library for rigs, rotators, tuners, and amplifiers

I was able to get that sorted out, hamlib was supposed to be installed on the PC not the Arduino, that was my confusion. Now the issue I'm having is with attempting to use microstepping to make the motors less noisy and vibrating less, but when I set the SPR to 800 and multiplies the speed and acceleration the angles don't match up anymore.

The code is on my first post. I'm using two TB6600 drivers and two 57HS56-3004 motors.

Shouldn't changing the TB6600 setting to 800 steps and changing the code to 800 SPR and chaniging the max speed and acceleration to 4x be sufficient? I don't understand why the angles aren't matching the same as when set to 200 SPR