Jump to content

Using IR optocoupler to set zero position for altimeter


lesthegrngo

Recommended Posts

Hi guys, I'm still moving this all forward slowly, now that I have a substantial amount of the cockpit if not finished, then working in need of tidy up.

 

one of the items on the list was the altimeter, which is one of the very few (physical) gauges I am making that requires unlimited rotation.

 

Middlefart has kindly provided us all with his rather nice scrolling OLED display sketch, so now all that remains on that particular gauge is to be able to set the zero position using either an IR optocoupler or a hall effect sensor. My preference for the IR optocoupler route is simply because I have one supplied as part of an arduino starter set.

 

I found this sketch on this forum thread https://forums.eagle.ru/showthread.php?t=145193

 

// include AccelStepper library
#include <AccelStepper.h>

// include DcsBios library
#include <DcsBios.h>
#include <Servo.h>

// DcsBios-related declarations
DcsBios:ProtocolParser parser;

#define STEPS_PER_REVOLUTION 240
#define ZERO_OFFSET 0

AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
int currentStepperPosition = 0; // current stepper position (in steps, from 0 to STEPS_PER_REVOLUTION-1)
signed long lastAccelStepperPosition;

void setup()
{
Serial.begin(250000);

pinMode (12,INPUT); // LOW when in zero position, HIGH otherwise


// set up stepper motor for zeroing
stepper.setMaxSpeed(1000);
stepper.setSpeed(500);
// run clockwise until we detect the zero position
while (digitalRead (12)==1) {
stepper.runSpeed();
}

// add zero offset
stepper.runToNewPosition(stepper.currentPosition() + ZERO_OFFSET);

// tell the AccelStepper library that we are at position zero
stepper.setCurrentPosition(0);
lastAccelStepperPosition = 0;
// set stepper acceleration in steps per second per second
// (default is zero)
stepper.setAcceleration(1000);

}

void loop()
{
// handle DcsBios communication
while (Serial.available()) {
parser.processChar(Serial.read());
}
DcsBios:PollingInput::pollInputs();

// move stepper motor
stepper.run();
}

void onDcsBiosWrite(unsigned int address, unsigned int value) {
if (address == 0x107e) {
digitalWrite (13,1);
unsigned int alt100ftValue = (value & 0xffff) >> 0;

// convert data from DCS to a target position expressed as a number of steps
int targetPosition = map(alt100ftValue, 0, 65535, 0, STEPS_PER_REVOLUTION-1);

// adjust currentStepperPosition to include the distance our stepper motor
// was moved since we last updated it
int movementSinceLastUpdate = stepper.currentPosition() - lastAccelStepperPosition;
currentStepperPosition += movementSinceLastUpdate;
lastAccelStepperPosition = stepper.currentPosition();

if (currentStepperPosition < 0) currentStepperPosition += STEPS_PER_REVOLUTION;
if (currentStepperPosition > STEPS_PER_REVOLUTION) currentStepperPosition -= STEPS_PER_REVOLUTION;

int delta = targetPosition - currentStepperPosition;

// if we would move more than 180 degree counterclockwise, move clockwise instead
if (delta < -(STEPS_PER_REVOLUTION/2)) delta += STEPS_PER_REVOLUTION;
// if we would move more than 180 degree clockwise, move counterclockwise instead
if (delta > (STEPS_PER_REVOLUTION/2)) delta -= STEPS_PER_REVOLUTION;

// tell AccelStepper to move relative to the current position
stepper.move(delta);

 

I'm using an X27 type stepper motor, which has already been modified to remove the limiting pin inside. The sketch has to be changed for use with a stepper driver (an A4988 module) as this sketch seems to drive the stepper directly. The optocoupler module is one of these

 

https://www.ebay.com/itm/TCRT5000-IR-Infrared-Line-Track-Follower-Sensor-Obstacle-Avoidance-Module/202058803237?hash=item2f0ba4a825:g:z-8AAOSwSZFZwAJD

 

So I am going to put a test together, then see if I can successfully get the sketch working correctly with the hardware. If anyone has experience of this and can advise as ever I would be grateful for the input

 

Wish me luck!

 

Cheers

 

Les


Edited by lesthegrngo
Link to comment
Share on other sites

  • 2 weeks later...

The unfortunate situation with Coronavirus has had the collateral effect of giving me chance to work on some bits and pieces for my sim pit.

 

I knocked together the sketch below, which with my optocoupler is working to zero the gauge. However once it has zeroed, the gauge never moves again!

 

Is there anything obvious wrong with it?

 

 

#define DCSBIOS_IRQ_SERIAL

#include <AccelStepper.h>
#include "DcsBios.h"

struct StepperConfig {
 unsigned int maxSteps;
 unsigned int acceleration;
 unsigned int maxSpeed;
};


class Vid29Stepper : public DcsBios::Int16Buffer {
 private:
   AccelStepper& stepper;
   StepperConfig& stepperConfig;
   inline bool zeroDetected() { return digitalRead(irDetectorPin) == 1; }
   unsigned int (*map_function)(unsigned int);
   unsigned char initState;
   long currentStepperPosition;
   long lastAccelStepperPosition;
   unsigned char irDetectorPin;
   long zeroOffset;
   bool movingForward;
   bool lastZeroDetectState;

   long normalizeStepperPosition(long pos) {
     if (pos < 0) return pos + stepperConfig.maxSteps;
     if (pos >= stepperConfig.maxSteps) return pos - stepperConfig.maxSteps;
     return pos;
   }

   void updateCurrentStepperPosition() {
     // adjust currentStepperPosition to include the distance our stepper motor
     // was moved since we last updated it
     long movementSinceLastUpdate = stepper.currentPosition() - lastAccelStepperPosition;
     currentStepperPosition = normalizeStepperPosition(currentStepperPosition + movementSinceLastUpdate);
     lastAccelStepperPosition = stepper.currentPosition();
   }
 public:
   Vid29Stepper(unsigned int address, 
   AccelStepper& stepper, 
   StepperConfig& stepperConfig, 
   unsigned char irDetectorPin, 
   long zeroOffset, unsigned int (*map_function)(unsigned int)): Int16Buffer(address), 
   stepper(stepper), 
   stepperConfig(stepperConfig), 
   irDetectorPin(irDetectorPin), 
   zeroOffset(zeroOffset), 
   map_function(map_function), 
   initState(0), 
   currentStepperPosition(0), 
   lastAccelStepperPosition(0) 
   {
   }

   virtual void loop() {
     
     if (initState == 0) { // not initialized yet
       pinMode(irDetectorPin, INPUT);
       stepper.setMaxSpeed(stepperConfig.maxSpeed);
       stepper.setSpeed(1000);
       
       initState = 1;
     }
     if (initState == 1) {
       // move off zero if already there so we always get movement on reset
       // (to verify that the stepper is working)
       if (zeroDetected()) {
         stepper.runSpeed();
       } else {
           initState = 2;
       }
     }
     if (initState == 2) { // zeroing
       if (!zeroDetected()) {
         stepper.runSpeed();
       } else {
           stepper.setAcceleration(stepperConfig.acceleration);
           stepper.runToNewPosition(stepper.currentPosition() + zeroOffset);
           // tell the AccelStepper library that we are at position zero
           stepper.setCurrentPosition(0);
           lastAccelStepperPosition = 0;
           // set stepper acceleration in steps per second per second
           // (default is zero)
           stepper.setAcceleration(stepperConfig.acceleration);
           
           lastZeroDetectState = true;
           initState = 3;
       }
     }
     if (initState == 3) { // running normally
       
       // recalibrate when passing through zero position
       bool currentZeroDetectState = zeroDetected();
       if (!lastZeroDetectState && currentZeroDetectState && movingForward) {
         // we have moved from left to right into the 'zero detect window'
         // and are now at position 0
         lastAccelStepperPosition = stepper.currentPosition();
         currentStepperPosition = normalizeStepperPosition(zeroOffset);
       } else if (lastZeroDetectState && !currentZeroDetectState && !movingForward) {
         // we have moved from right to left out of the 'zero detect window'
         // and are now at position (maxSteps-1)
         lastAccelStepperPosition = stepper.currentPosition();
         currentStepperPosition = normalizeStepperPosition(stepperConfig.maxSteps + zeroOffset);
       }
       lastZeroDetectState = currentZeroDetectState;
       
       
       if (hasUpdatedData()) {
           // convert data from DCS to a target position expressed as a number of steps
           long targetPosition = (long)map_function(getData());

           updateCurrentStepperPosition();
           
           long delta = targetPosition - currentStepperPosition;
           
           // if we would move more than 180 degree counterclockwise, move clockwise instead
           if (delta < -((long)(stepperConfig.maxSteps/2))) delta += stepperConfig.maxSteps;
           // if we would move more than 180 degree clockwise, move counterclockwise instead
           if (delta > (stepperConfig.maxSteps/2)) delta -= (long)stepperConfig.maxSteps;

           movingForward = (delta >= 0);
           
           // tell AccelStepper to move relative to the current position
           stepper.move(delta);
           
       }
       stepper.run();
     }
   }
};

/* modify below this line */

/* define stepper parameters
  multiple Vid60Stepper instances can share the same StepperConfig object */
struct StepperConfig stepperConfig = 
 {
 400,  // maxSteps
 2200, // maxSpeed
 1000 // acceleration
 };


// define AccelStepper instance
AccelStepper stepper(AccelStepper::DRIVER, 11, 10);
// define Vid29Stepper class that uses the AccelStepper instance defined in the line above
//           v-- arbitrary name
Vid29Stepper alt100ftPointer(0x107e,          // address of stepper data
                            stepper,         // name of AccelStepper instance
                            stepperConfig,   // StepperConfig struct instance
                            9,              // IR Detector Pin (must be HIGH in zero position)
                            0,               // zero offset
                            [](unsigned int newValue) -> unsigned int {
 /* this function needs to map newValue to the correct number of steps */
 return map(newValue, 0, 65535, 0, stepperConfig.maxSteps-1);
                                                          });


void setup() {
 DcsBios::setup();
 
}

void loop() {
 
 DcsBios::loop();
}

 

Cheers

 

Les

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...