Could not init LSM303 sensor

Hi all,

this is my first post in this forum.

I've trying to adapt an Arduino sketch from SatNOGS project to support a LSM303 magnetometer/accelerometer sensor to positioning it at zero at start.

I've a GY-511 chip (LSM303DLHC) and I'm using the Pololu library to get the values. Firstly I calibrated the sensor and I got the max and min values.

Next I write a simple function to get the heading, pitch and roll values compensated. I've tested the function and it works fine and the values I'm getting are fine.

But when I use it from the rotator sketch I always get "LSM303 could not be initialized" when I call:

lsm303.init(LSM303::device_auto, LSM303::sa0_auto) returns false when I call from the main sketch.

This is the code to get the sensor values "orientationTilt.h":

#include <LSM303.h>

LSM303 lsm303;

// Min and max values obtained from calibration for tilt compensated heading: see Calibration.ino example from LSM303 library
#define TILT_MIN_X  -530
#define TILT_MIN_Y  -539
#define TILT_MIN_Z  -475

#define TILT_MAX_X  +610
#define TILT_MAX_Y  +430
#define TILT_MAX_Z  +450

/*
  In our case note that:
  heading = azimuth
  pitch = elevation
*/
struct orientation {
  float pitch;
  float roll;
  float heading;  
};

struct orientation getOrientationTilt(){
  const float alpha = 0.10;   // Alpha
  float fXa, fYa, fZa = 0;    // Low-pass filtered accelerometer variables
  
  if (lsm303.init(LSM303::device_auto, LSM303::sa0_auto)) {
    lsm303.enableDefault();
    /*
      Calibration values: the default values of +/-32767 for each axis lead to an assumed
      magnetometer bias of 0. Use the Pololu LSM303 library Calibrate example program to
      determine appropriate values for each LSM303 sensor.
    */
    lsm303.m_min = (LSM303::vector<int16_t>) {TILT_MIN_X, TILT_MIN_Y, TILT_MIN_Z};
    lsm303.m_max = (LSM303::vector<int16_t>) {TILT_MAX_X, TILT_MAX_Y, TILT_MAX_Z};

    // Apply low-pass filter to accelerometer data
    for (byte i = 0; i < 30; i++) {
      lsm303.read();   // Read accelerometer and magnetometer data
      fXa = lsm303.a.x * alpha + (fXa * (1.0 - alpha));
      fYa = lsm303.a.y * alpha + (fYa * (1.0 - alpha));
      fZa = lsm303.a.z * alpha + (fZa * (1.0 - alpha));      
    }

    // Calculate orientation data
    float pitch = (atan2(fXa, sqrt((long)sq(fYa) + (long)sq(fZa))) * 180) / PI; // horizontal=0º -> up=+90º -> horizontal=0º -> down=-90º -> horizontal=0º
    float roll = (atan2(fYa, fZa) * 180) / PI;    
    float heading = lsm303.heading((LSM303::vector<int>) {1, 0, 0}); // PCB orientation: {1,0,0}=+X, {0,1,0}=+Y, ...

    //Return orientation
    orientation retOrientation;
    retOrientation.pitch   = pitch;
    retOrientation.roll    = roll;
    retOrientation.heading = heading;

    return retOrientation;
    
  }
  else {
    Serial.println(F("Error: Could not initialize LSM303!"));
  }

}

And next an excerpt of the main sketch:

#define SAMPLE_TIME        0.1   ///< Control loop in s
#define RATIO              4    ///< Gear ratio of rotator gear box                                 default 54
#define MICROSTEP          32     ///< Set Microstep
#define MIN_PULSE_WIDTH    1.9    ///< In microsecond for AccelStepper
#define MAX_SPEED          1000  ///< In steps/s, consider the microstep
#define MAX_ACCELERATION   800  ///< In steps/s^2, consider the microstep
#define SPR                6400 ///< Step Per Revolution, consider the microstep
#define MIN_M1_ANGLE       0     ///< Minimum angle of azimuth
#define MAX_M1_ANGLE       360   ///< Maximum angle of azimuth
#define MIN_M2_ANGLE       0     ///< Minimum angle of elevation
#define MAX_M2_ANGLE       90   ///< Maximum angle of elevation
#define DEFAULT_HOME_STATE LOW  ///< Change to LOW according to Home sensor
#define HOME_DELAY         12000 ///< Time for homing Deceleration in millisecond

#include <AccelStepper.h>
#include <Wire.h>
#include "globals.h"
#include "easycomm.h"
#include "rotator_pins.h"
//#include <rs485.h>
#include "endstop.h"
//#include <watchdog.h>
#include "orientationTilt.h"

uint32_t t_run = 0; // run time of uC
easycomm comm;
AccelStepper stepper_az(1, M1IN1, M1IN2);
AccelStepper stepper_el(1, M2IN1, M2IN2);
endstop switch_az(SW1, DEFAULT_HOME_STATE), switch_el(SW2, DEFAULT_HOME_STATE);
orientation compass;
//wdt_timer wdt;

enum _rotator_error homing(int32_t seek_az, int32_t seek_el);
int32_t deg2step(float deg);
float step2deg(int32_t step);

void setup() {
    // Homing switch
    switch_az.init();
    switch_el.init();

    // Serial Communication
    comm.easycomm_init();

    // Init sensors
    //initSensors();

    // Stepper Motor setup
    stepper_az.setEnablePin(MOTOR_EN);
    stepper_az.setPinsInverted(false, false, true);
    stepper_az.enableOutputs();
    stepper_az.setMaxSpeed(MAX_SPEED);
    stepper_az.setAcceleration(MAX_ACCELERATION);
    stepper_az.setMinPulseWidth(MIN_PULSE_WIDTH);
    stepper_el.setPinsInverted(false, false, true);
    stepper_el.enableOutputs();
    stepper_el.setMaxSpeed(MAX_SPEED);
    stepper_el.setAcceleration(MAX_ACCELERATION);
    stepper_el.setMinPulseWidth(MIN_PULSE_WIDTH);

    // Initialize WDT
    // wdt.watchdog_init();
   
    **compass = getOrientationTilt();  <-- function fails here**

    stepper_az.setCurrentPosition(deg2step(compass.heading));
    stepper_el.setCurrentPosition(deg2step(compass.pitch));

}

void loop() { ...... }

I think there's a conflict with the Serial but I don't know how to solve it.

Thanks in advance.

Please post all the code.

I think there's a conflict with the Serial

Why? Please describe the problem in detail. Explain what you think should happen, and what happens instead.

Next the main sketch (it could contain errors because I'm still trying it):

/*!
 * @file stepper_motor_controller.ino
 *
 * This is the documentation for satnogs rotator controller firmware
 * for stepper motors configuration. The board (PCB) is placed in
 * <a href="https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator-controller">
 * satnogs-rotator-controller </a> and is for releases:
 * v2.0
 * v2.1
 * v2.2
 * <a href="https://wiki.satnogs.org/SatNOGS_Rotator_Controller"> wiki page </a>
 *
 * @section dependencies Dependencies
 *
 * This firmware depends on <a href="http://www.airspayce.com/mikem/arduino/AccelStepper/index.htmlhttp://www.airspayce.com/mikem/arduino/AccelStepper/index.html">
 * AccelStepper library</a> being present on your system. Please make sure you
 * have installed the latest version before using this firmware.
 *
 * @section license License
 *
 * Licensed under the GPLv3.
 *
 */

#define SAMPLE_TIME        0.1   ///< Control loop in s
#define RATIO              4    ///< Gear ratio of rotator gear box                                 default 54
#define MICROSTEP          32     ///< Set Microstep
#define MIN_PULSE_WIDTH    1.9    ///< In microsecond for AccelStepper
#define MAX_SPEED          1000  ///< In steps/s, consider the microstep
#define MAX_ACCELERATION   800  ///< In steps/s^2, consider the microstep
#define SPR                6400 ///< Step Per Revolution, consider the microstep
#define MIN_M1_ANGLE       0     ///< Minimum angle of azimuth
#define MAX_M1_ANGLE       360   ///< Maximum angle of azimuth
#define MIN_M2_ANGLE       0     ///< Minimum angle of elevation
#define MAX_M2_ANGLE       90   ///< Maximum angle of elevation
#define DEFAULT_HOME_STATE LOW  ///< Change to LOW according to Home sensor
#define HOME_DELAY         12000 ///< Time for homing Deceleration in millisecond

#include <AccelStepper.h>
#include <Wire.h>
#include "globals.h"
#include "easycomm.h"
#include "rotator_pins.h"
//#include <rs485.h>
#include "endstop.h"
//#include <watchdog.h>
//#include "orientation.h"
//#include "orientation_v2.h"
#include "orientationTilt.h"

uint32_t t_run = 0; // run time of uC
easycomm comm;
AccelStepper stepper_az(1, M1IN1, M1IN2);
AccelStepper stepper_el(1, M2IN1, M2IN2);
endstop switch_az(SW1, DEFAULT_HOME_STATE), switch_el(SW2, DEFAULT_HOME_STATE);
orientation compass;
//wdt_timer wdt;

enum _rotator_error homing(int32_t seek_az, int32_t seek_el);
int32_t deg2step(float deg);
float step2deg(int32_t step);

void setup() {
    // Homing switch
    switch_az.init();
    switch_el.init();

    // Serial Communication
    comm.easycomm_init();

    // Init sensors
    //initSensors();

    // Stepper Motor setup
    stepper_az.setEnablePin(MOTOR_EN);
    stepper_az.setPinsInverted(false, false, true);
    stepper_az.enableOutputs();
    stepper_az.setMaxSpeed(MAX_SPEED);
    stepper_az.setAcceleration(MAX_ACCELERATION);
    stepper_az.setMinPulseWidth(MIN_PULSE_WIDTH);
    stepper_el.setPinsInverted(false, false, true);
    stepper_el.enableOutputs();
    stepper_el.setMaxSpeed(MAX_SPEED);
    stepper_el.setAcceleration(MAX_ACCELERATION);
    stepper_el.setMinPulseWidth(MIN_PULSE_WIDTH);

    // Initialize WDT
    // wdt.watchdog_init();
   
    compass = getOrientationTilt();

    // To debug LSM303
    /*
    Serial.println(compass.heading);
    Serial.println(compass.pitch);
    Serial.println();
    */
      
    stepper_az.setCurrentPosition(deg2step(compass.heading));
    stepper_el.setCurrentPosition(deg2step(compass.pitch));

}

void loop() {
    // Update WDT
    // wdt.watchdog_reset();

    // Get end stop status
    rotator.switch_az = switch_az.get_state();
    rotator.switch_el = switch_el.get_state();

    // Run easycomm implementation
    comm.easycomm_proc();

    // Get position of both axis
    control_az.input = step2deg(stepper_az.currentPosition());
    control_el.input = step2deg(stepper_el.currentPosition());

    // Check rotator status
    if (rotator.rotator_status != error) {
        if (rotator.homing_flag == false) {
            // Check home flag
            rotator.control_mode = position;
            // Homing
            // rotator.rotator_error = homing(deg2step(-MAX_M1_ANGLE), deg2step(-MAX_M2_ANGLE));
            rotator.rotator_error = homing_2(deg2step(compass.heading), deg2step(compass.pitch));
            if (rotator.rotator_error == no_error) {
                // No error
                rotator.rotator_status = idle;
                rotator.homing_flag = true;
            } else {
                // Error
                rotator.rotator_status = error;
                rotator.rotator_error = homing_error;
            }
        } else {
            // Control Loop
            stepper_az.moveTo(deg2step(control_az.setpoint));
            stepper_el.moveTo(deg2step(control_el.setpoint));
            rotator.rotator_status = pointing;
            // Move azimuth and elevation motors
            stepper_az.run();
            stepper_el.run();
            // Idle rotator
            if (stepper_az.distanceToGo() == 0 && stepper_el.distanceToGo() == 0) {
                rotator.rotator_status = idle;
            }
        }
    } else {
        // Error handler, stop motors and disable the motor driver
        stepper_az.stop();
        stepper_az.disableOutputs();
        stepper_el.stop();
        stepper_el.disableOutputs();
        if (rotator.rotator_error != homing_error) {
            // Reset error according to error value
            rotator.rotator_error = no_error;
            rotator.rotator_status = idle;
        }
    }
}

/**************************************************************************/
/*!
    @brief    Move both axis with one direction in order to find home position,
              end-stop switches
    @param    seek_az
              Steps to find home position for azimuth axis
    @param    seek_el
              Steps to find home position for elevation axis
    @return   _rotator_error
*/
/**************************************************************************/
enum _rotator_error homing(int32_t seek_az, int32_t seek_el) {
    bool isHome_az = false;
    bool isHome_el = false;

    // Move motors to "seek" position
    stepper_az.moveTo(seek_az);
    stepper_el.moveTo(seek_el);

    // Homing loop
    while (isHome_az == false || isHome_el == false) {
        // Update WDT
       // wdt.watchdog_reset();
        if (switch_az.get_state() == true && !isHome_az) {
            // Find azimuth home
            stepper_az.moveTo(stepper_az.currentPosition());
            isHome_az = true;
        }
        if (switch_el.get_state() == true && !isHome_el) {
            // Find elevation home
            stepper_el.moveTo(stepper_el.currentPosition());
            isHome_el = true;
        }
        // Check if the rotator goes out of limits or something goes wrong (in
        // mechanical)
        if ((stepper_az.distanceToGo() == 0 && !isHome_az) ||
            (stepper_el.distanceToGo() == 0 && !isHome_el)){
            return homing_error;
        }
        // Move motors to "seek" position
        stepper_az.run();
        stepper_el.run();
    }
    // Delay to Deccelerate and homing, to complete the movements
    uint32_t time = millis();
    while (millis() - time < HOME_DELAY) {
       // wdt.watchdog_reset();
        stepper_az.run();
        stepper_el.run();
    }
    // Set the home position and reset all critical control variables
    stepper_az.setCurrentPosition(0);
    stepper_el.setCurrentPosition(0);
    control_az.setpoint = 0;
    control_el.setpoint = 0;

    return no_error;
}

/**************************************************************************/
/*!
    @brief    Move azimuth and elevation motors to 0,0
              Azimuth motor moves:
               Clockwise if azimuth parameter is >= (MAX_M1_ANGLE / 2) deg
               Counterclockwise if azimuth parameter is < (MAX_M1_ANGLE / 2) deg
              Elevation motor moves:
               Clockwise if elevation parameter is between MIN_M2_ANGLE and MAX_M2_ANGLE deg
               Counterclockwise if elevation parameter is between -MAX_M2_ANGLE and -MIN_M2_ANGLE deg
    @param    az
              Azimuth in steps
    @param    el
              Elevation in steps     
    @return   _rotator_error
*/
/**************************************************************************/
enum _rotator_error homing_2(int32_t az, int32_t el) {
    
   // Azimuth homing
   /* To move the less possible angle, azimuth motor moves:
      Clockwise if azimuth parameter is >= (MAX_M1_ANGLE / 2) deg until reaches MAX_M1_ANGLE
      Counterclockwise if azimuth parameter is < (MAX_M1_ANGLE / 2) deg
   */    
    if (az >= (deg2step(MAX_M1_ANGLE) / 2)){
        stepper_az.move(deg2step(MAX_M1_ANGLE) - az);
    } else{
        stepper_az.move(deg2step(MIN_M1_ANGLE) - az);
    } 
    
    while (stepper_az.distanceToGo() != 0){
        stepper_az.run();
    }

    // Elevation homing
    /* Move elevation motor:
       Clockwise if elevation parameter is over horizon, i.e. between MIN_M2_ANGLE and MAX_M2_ANGLE deg
       Counterclockwise if elevation parameter is under horizon, i.e. between -MAX_M2_ANGLE and -MIN_M2_ANGLE deg
       This case shouldn't be frequent so it's better dispose the elevation manually over the horizon before rotor starts run
    */
    if ((el >= MIN_M2_ANGLE) && (el <= MAX_M2_ANGLE)){
        stepper_el.move(MIN_M2_ANGLE - el);
    } else {
      if ((el >= -MAX_M2_ANGLE) && (el <= -MIN_M2_ANGLE)){
          stepper_el.move(el - MIN_M2_ANGLE);
      } else {
          return homing_error;
      }
    }

    while (stepper_el.distanceToGo() != 0){
        stepper_el.run();
    }
    
    // Delay to Deccelerate and homing, to complete the movements
    uint32_t time = millis();
    while (millis() - time < HOME_DELAY) {
       // wdt.watchdog_reset();
        stepper_az.run();
        stepper_el.run();
    }
    // Set the home position and reset all critical control variables
    stepper_az.setCurrentPosition(0);
    stepper_el.setCurrentPosition(0);
    control_az.setpoint = 0;
    control_el.setpoint = 0;

    return no_error;
}

/**************************************************************************/
/*!
    @brief    Convert degrees to steps according to step/revolution, rotator
              gear box ratio and microstep
    @param    deg
              Degrees in float format
    @return   Steps for stepper motor driver, int32_t
*/
/**************************************************************************/
int32_t deg2step(float deg) {
    return (RATIO * SPR * deg / 360);
}

/**************************************************************************/
/*!
    @brief    Convert steps to degrees according to step/revolution, rotator
              gear box ratio and microstep
    @param    step
              Steps in int32_t format
    @return   Degrees in float format
*/
/**************************************************************************/
float step2deg(int32_t step) {
    return (360.00 * step / (SPR * RATIO));
}

Steppers should move to homing but when I debug the call to getOrientationTilt() the sensor it isn't initialized.
I try getOrientationTilt() in another test sketch and it works.

Thanks.

The very best approach is to make sure each part of the project is working independently and correctly before combining functions.

Get the sensor working properly alone, with no extraneous code, sensors or motors, before adding the code to a project with other functions.

As I said the sensor code is tested and works fine standalone.

Something in the added code seems to be causing the problem. Possibly, that would be in the code you forgot to post, like pin definitions, variable names or types, etc. from the includes below.

#include "globals.h"
#include "easycomm.h"
#include "rotator_pins.h"
#include "endstop.h"
#include "orientationTilt.h"

At last I've got to work properly. I've tried more sofisticated and difficult calibration methods but the LSM303's library calibration method is I've used and the best results for me (althoug I've noted the TILT_MAX_Z is a negative value compared with the other MAX values but I calibrated twice and TILT_MAX_Z got is always negative).

Heading is quite accurate for my needs but I've noted that pitch (elevation) is between 3 and 6 degrees when I homing my rotator to zero. The LSM303 sensor is well placed and I think the calibration values got are fine but for an strange reason I can't determine why it happens.

Next my Arduino sketches:

/*!
 * @file stepper_motor_controller.ino
 *
 * This is the documentation for satnogs rotator controller firmware
 * for stepper motors configuration. The board (PCB) is placed in
 * <a href="https://gitlab.com/librespacefoundation/satnogs/satnogs-rotator-controller">
 * satnogs-rotator-controller </a> and is for releases:
 * v2.0
 * v2.1
 * v2.2
 * <a href="https://wiki.satnogs.org/SatNOGS_Rotator_Controller"> wiki page </a>
 *
 * @section dependencies Dependencies
 *
 * This firmware depends on <a href="http://www.airspayce.com/mikem/arduino/AccelStepper/index.htmlhttp://www.airspayce.com/mikem/arduino/AccelStepper/index.html">
 * AccelStepper library</a> being present on your system. Please make sure you
 * have installed the latest version before using this firmware.
 *
 * @section license License
 *
 * Licensed under the GPLv3.
 *
 */

#define SAMPLE_TIME        0.1   ///< Control loop in s
#define RATIO              4    ///< Gear ratio of rotator gear box                                 default 54
#define MICROSTEP          32     ///< Set Microstep
#define MIN_PULSE_WIDTH    1.9    ///< In microsecond for AccelStepper
#define MAX_SPEED          1000  ///< In steps/s, consider the microstep
#define MAX_ACCELERATION   800  ///< In steps/s^2, consider the microstep
#define SPR                6400 ///< Step Per Revolution, consider the microstep
#define MIN_M1_ANGLE       0     ///< Minimum angle of azimuth
#define MAX_M1_ANGLE       360   ///< Maximum angle of azimuth
#define MIN_M2_ANGLE       0     ///< Minimum angle of elevation
#define MAX_M2_ANGLE       90   ///< Maximum angle of elevation
#define DEFAULT_HOME_STATE LOW  ///< Change to LOW according to Home sensor
#define HOME_DELAY         12000 ///< Time for homing Deceleration in millisecond

#include <AccelStepper.h>
//#include <Wire.h>
#include "globals.h"
#include "easycomm.h"
#include "rotator_pins.h"
//#include <rs485.h>
#include "endstop.h"
//#include <watchdog.h>
//#include "orientation.h"
//#include "orientation_v3.h"
#include "orientationTilt.h"

uint32_t t_run = 0; // run time of uC
easycomm comm;
AccelStepper stepper_az(AccelStepper::DRIVER, M1IN1, M1IN2);
AccelStepper stepper_el(AccelStepper::DRIVER, M2IN1, M2IN2);
endstop switch_az(SW1, DEFAULT_HOME_STATE), switch_el(SW2, DEFAULT_HOME_STATE);
orientation compass;
//wdt_timer wdt;

enum _rotator_error homing(int32_t seek_az, int32_t seek_el);
int32_t deg2step(float deg);
float step2deg(int32_t step);

void setup() {
    // Homing switch
    switch_az.init();
    switch_el.init();    

    // Serial Communication
    comm.easycomm_init();

    // Get the current orientation before enable the steppers to avoid any interference
    compass = getOrientationTilt();
    
    /*
    Serial.print("Heading: "); Serial.println(compass.heading);
    Serial.print("Pitch: "); Serial.println(compass.pitch);
    Serial.print("Roll: "); Serial.println(compass.roll);  
    Serial.println();  
    */

    // Stepper Motor setup
    stepper_az.setEnablePin(MOTOR_EN);
    stepper_az.setPinsInverted(false, false, true);
    stepper_az.enableOutputs();
    stepper_az.setMaxSpeed(MAX_SPEED);
    stepper_az.setAcceleration(MAX_ACCELERATION);
    stepper_az.setMinPulseWidth(MIN_PULSE_WIDTH);
    stepper_el.setEnablePin(MOTOR_EN);
    // Elevation stepper has inverted direction pin due to sensor position respect of motor
    stepper_el.setPinsInverted(true, false, true);
    stepper_el.enableOutputs();
    stepper_el.setMaxSpeed(MAX_SPEED);
    stepper_el.setAcceleration(MAX_ACCELERATION);
    stepper_el.setMinPulseWidth(MIN_PULSE_WIDTH);

    // Initialize WDT
    // wdt.watchdog_init();
         
    stepper_az.setCurrentPosition(deg2step(compass.heading));
    stepper_el.setCurrentPosition(deg2step(compass.pitch));

}

void loop() {
    // Update WDT
    // wdt.watchdog_reset();

    // Get end stop status
    rotator.switch_az = switch_az.get_state();
    rotator.switch_el = switch_el.get_state();

    // Run easycomm implementation
    comm.easycomm_proc();

    // Get position of both axis
    control_az.input = step2deg(stepper_az.currentPosition());
    control_el.input = step2deg(stepper_el.currentPosition());

    // Check rotator status
    if (rotator.rotator_status != error) {
        if (rotator.homing_flag == false) {
            // Check home flag
            rotator.control_mode = position;
            // Homing
            // rotator.rotator_error = homing(deg2step(-MAX_M1_ANGLE), deg2step(-MAX_M2_ANGLE));            
            rotator.rotator_error = homing_2(deg2step(compass.heading), deg2step(compass.pitch));
            if (rotator.rotator_error == no_error) {
                // No error
                rotator.rotator_status = idle;
                rotator.homing_flag = true;
            } else {
                // Error
                rotator.rotator_status = error;
                rotator.rotator_error = homing_error;
            }
        } else {
            // Control Loop
            stepper_az.moveTo(deg2step(control_az.setpoint));
            stepper_el.moveTo(deg2step(control_el.setpoint));
            rotator.rotator_status = pointing;
            // Move azimuth and elevation motors
            stepper_az.run();
            stepper_el.run();
            // Idle rotator
            if (stepper_az.distanceToGo() == 0 && stepper_el.distanceToGo() == 0) {
                rotator.rotator_status = idle;
            }
        }
    } else {
        // Error handler, stop motors and disable the motor driver
        stepper_az.stop();
        stepper_az.disableOutputs();
        stepper_el.stop();
        stepper_el.disableOutputs();
        if (rotator.rotator_error != homing_error) {
            // Reset error according to error value
            rotator.rotator_error = no_error;
            rotator.rotator_status = idle;
        }
    }
}

/**************************************************************************/
/*!
    @brief    Move both axis with one direction in order to find home position,
              end-stop switches
    @param    seek_az
              Steps to find home position for azimuth axis
    @param    seek_el
              Steps to find home position for elevation axis
    @return   _rotator_error
*/
/**************************************************************************/
enum _rotator_error homing(int32_t seek_az, int32_t seek_el) {
    bool isHome_az = false;
    bool isHome_el = false;

    // Move motors to "seek" position
    stepper_az.moveTo(seek_az);
    stepper_el.moveTo(seek_el);

    // Homing loop
    while (isHome_az == false || isHome_el == false) {
        // Update WDT
       // wdt.watchdog_reset();
        if (switch_az.get_state() == true && !isHome_az) {
            // Find azimuth home
            stepper_az.moveTo(stepper_az.currentPosition());
            isHome_az = true;
        }
        if (switch_el.get_state() == true && !isHome_el) {
            // Find elevation home
            stepper_el.moveTo(stepper_el.currentPosition());
            isHome_el = true;
        }
        // Check if the rotator goes out of limits or something goes wrong (in
        // mechanical)
        if ((stepper_az.distanceToGo() == 0 && !isHome_az) ||
            (stepper_el.distanceToGo() == 0 && !isHome_el)){
            return homing_error;
        }
        // Move motors to "seek" position
        stepper_az.run();
        stepper_el.run();
    }
    // Delay to Deccelerate and homing, to complete the movements
    uint32_t time = millis();
    while (millis() - time < HOME_DELAY) {
       // wdt.watchdog_reset();
        stepper_az.run();
        stepper_el.run();
    }
    // Set the home position and reset all critical control variables
    stepper_az.setCurrentPosition(0);
    stepper_el.setCurrentPosition(0);
    control_az.setpoint = 0;
    control_el.setpoint = 0;

    return no_error;
}

/**************************************************************************/
/*!
    @brief    Move azimuth and elevation motors to 0,0
              Azimuth motor moves:
               Clockwise if azimuth parameter is >= (MAX_M1_ANGLE / 2) deg
               Counterclockwise if azimuth parameter is < (MAX_M1_ANGLE / 2) deg
              Elevation motor moves:
               Clockwise if elevation parameter is between MIN_M2_ANGLE and MAX_M2_ANGLE deg
               Counterclockwise if elevation parameter is between -MAX_M2_ANGLE and -MIN_M2_ANGLE deg
    @param    az
              Azimuth in steps
    @param    el
              Elevation in steps     
    @return   _rotator_error
*/
/**************************************************************************/
enum _rotator_error homing_2(int32_t az, int32_t el) {
    
   // Azimuth homing
   /* To move the less possible angle, azimuth motor moves:
      Clockwise if azimuth parameter is >= (MAX_M1_ANGLE / 2) deg until reaches MAX_M1_ANGLE
      Counterclockwise if azimuth parameter is < (MAX_M1_ANGLE / 2) deg
   */    
    if (az >= (deg2step(MAX_M1_ANGLE) / 2)){
        stepper_az.move(deg2step(MAX_M1_ANGLE) - az);        
    } else{        
        stepper_az.move(deg2step(MIN_M1_ANGLE) - az);
    }     
    
    while (stepper_az.distanceToGo() != 0){        
        stepper_az.run();
    }

    // Elevation homing
    /* Move elevation motor:
       Clockwise if elevation parameter is over horizon, i.e. between MIN_M2_ANGLE and MAX_M2_ANGLE deg
       Counterclockwise if elevation parameter is under horizon, i.e. between -MAX_M2_ANGLE and -MIN_M2_ANGLE deg
       This case shouldn't be frequent so it's better dispose the elevation manually over the horizon before rotor starts run
    */
    if (((el >= deg2step(MIN_M2_ANGLE)) && (el <= deg2step(MAX_M2_ANGLE))) || ((el >= deg2step(-MAX_M2_ANGLE)) && (el <= deg2step(-MIN_M2_ANGLE)))){
        // If elevation stepper inverted pin is not used
        //stepper_el.move(el - deg2step(MIN_M2_ANGLE));
        // If elevation stepper inverted pin is used
        stepper_el.move(deg2step(MIN_M2_ANGLE) - el);
    } else {            
        return homing_error;
    }    

    while (stepper_el.distanceToGo() != 0){
        stepper_el.run();
    }
        
    // Delay to Deccelerate and homing, to complete the movements
    uint32_t time = millis();
    while (millis() - time < HOME_DELAY) {
       // wdt.watchdog_reset();
        stepper_az.run();
        stepper_el.run();
    }
    
    // Set the home position and reset all critical control variables
    stepper_az.setCurrentPosition(0);
    stepper_el.setCurrentPosition(0);
    control_az.setpoint = 0;
    control_el.setpoint = 0;

    return no_error;
}

/**************************************************************************/
/*!
    @brief    Convert degrees to steps according to step/revolution, rotator
              gear box ratio and microstep
    @param    deg
              Degrees in float format
    @return   Steps for stepper motor driver, int32_t
*/
/**************************************************************************/
int32_t deg2step(float deg) {
    return (RATIO * SPR * deg / 360);
}

/**************************************************************************/
/*!
    @brief    Convert steps to degrees according to step/revolution, rotator
              gear box ratio and microstep
    @param    step
              Steps in int32_t format
    @return   Degrees in float format
*/
/**************************************************************************/
float step2deg(int32_t step) {
    return (360.00 * step / (SPR * RATIO));
}

orientationTilt.h

#include <LSM303.h>
#include <Wire.h>

LSM303 lsm303;

// Min and max values obtained from calibration for tilt compensated heading: see Calibration.ino example from LSM303 library
#define TILT_MIN_X  -193
#define TILT_MIN_Y  -393
#define TILT_MIN_Z  -898

#define TILT_MAX_X  +912
#define TILT_MAX_Y  +422
#define TILT_MAX_Z  -202

/*
  In our case note that:
  heading = azimuth
  pitch = elevation
*/
struct orientation {
  float pitch;
  float roll;
  float heading;  
};

struct orientation getOrientationTilt(){
  const float alpha = 0.10;   // Alpha
  float fXa, fYa, fZa = 0;    // Low-pass filtered accelerometer variables
  
  Wire.begin();

  if (lsm303.init(LSM303::device_auto, LSM303::sa0_auto)) {        
    lsm303.enableDefault();
    /*
      Calibration values: the default values of +/-32767 for each axis lead to an assumed
      magnetometer bias of 0. Use the Pololu LSM303 library Calibrate example program to
      determine appropriate values for each LSM303 sensor.
    */
    lsm303.m_min = (LSM303::vector<int16_t>) {TILT_MIN_X, TILT_MIN_Y, TILT_MIN_Z};
    lsm303.m_max = (LSM303::vector<int16_t>) {TILT_MAX_X, TILT_MAX_Y, TILT_MAX_Z};

    // Apply low-pass filter to accelerometer data
    for (byte i = 0; i < 30; i++) {
      lsm303.read();   // Read accelerometer and magnetometer data
      fXa = lsm303.a.x * alpha + (fXa * (1.0 - alpha));
      fYa = lsm303.a.y * alpha + (fYa * (1.0 - alpha));
      fZa = lsm303.a.z * alpha + (fZa * (1.0 - alpha));      
    }

    // Calculate orientation data
    float pitch = (atan2(fXa, sqrt((fYa * fYa) + (fZa * fZa))) * 180) / PI; // horizontal=0º -> up=+90º -> horizontal=0º -> down=-90º -> horizontal=0º
    float roll = (atan2(fYa, fZa) * 180) / PI;    
    float heading = lsm303.heading((LSM303::vector<int>) {1, 0, 0}); // PCB orientation: {1,0,0}=+X, {0,1,0}=+Y, ...

    //Return orientation
    orientation retOrientation;
    retOrientation.pitch   = pitch;
    retOrientation.roll    = roll;
    retOrientation.heading = heading;

    return retOrientation;
    
  }
  else {
    Serial.println(F("Error: Could not initialize LSM303!"));
  }

}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.