Jump to content

Recommended Posts

Posted (edited)

****edited as the basic issue is resolved, just leaving the discussion for reference****

 

All, this thread https://forum.dcs.world/topic/318814-increasing-the-sensitivity-of-ir-digital-position-sensor/#comment-5290335 

shows what I have done so far, but I am being frustrated by the fact that I am not happy with the whole altimeter. The zeroing works great, as soon as you power up it will zero immediately and correctly.

However once the gauge is used via USB in game it is not so good, with despite playing around with the stepper config max steps it never really matches the pointer position correctly, exacerbated by the movement not being constant - to explain, even in a steady descent with the in game pointer rotating at a steady speed, the physical pointer will more to fast for part of the rotation, and then slow down too much for another period, then speed up etc. It seems random, so the sketch I am using isn't really keeping control of the pointer.

Things are worse still on trying to go to RS485; I managed to get it 'working' but it stutters constantly and is just not good. This is the code I'm using

//#define DCSBIOS_IRQ_SERIAL

#define DCSBIOS_RS485_SLAVE 48
#define TXENABLE_PIN 2

#include <AccelStepper.h>
#include "DcsBios.h"
#include <Wire.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 =
{
  730,  // maxSteps
  2200, // maxSpeed
  1000 // acceleration
};


// define AccelStepper instance
AccelStepper stepper(AccelStepper::DRIVER, 4, 5);
// 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
                             6,              // 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, 65535, 0, 0, stepperConfig.maxSteps - 1);
});

void setup() {

  DcsBios::setup();

}

void loop() {

  DcsBios::loop();

}

This was based on some code produced (I think by Craig) some time back.

I now want to try a clean sheet version. The IR sensor part works fine, but I would like to see if there is a revised version that works better.

So, do any of you have any alternative sketches that I could try?

Cheers

 

Les

Edited by lesthegrngo
Posted

Hi Les,

we had a long discussion on the altimeter sketch of the Bf-109. Maybe there are some useful points for your investigation.

 

Else we may again discuss details via PM.

Best regards, Vinc

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Posted

The AccelStepper version in that thread worked, once I made a patch PCB to enable me to delete the stepper driver. It is not perfect, despite playing around with the max steps in the stepper config, the position of the pointer doesn't properly match the 'real' position, but it will pass through the zero point with out a step forwards or backwards, so the rotation is smooth and doesn't detract. I also had no issues getting it functioning with RS485 either

Puzzlingly the max steps value had to be changed when I went from the USB to the RS485 version, I don't know of any logical reason why that would be. Nonetheless, compared to the old version it is a massive improvement. In case anyone wants to use it here is the final sketch, which includes the fully functioning Baro set and Alt/Elec/Pneu rotary switch

//#define DCSBIOS_IRQ_SERIAL

#define DCSBIOS_RS485_SLAVE 100
#define TXENABLE_PIN 2

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



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


class Vid60Stepper : 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:
    Vid60Stepper(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(200);
        
        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 = {
  740,  // maxSteps
  8000, // acceleration
  4000 // maxSpeed
 };


// define AccelStepper instance
AccelStepper stepper1(AccelStepper::FULL4WIRE , 5, 4, 6, 7);
// define Vid60Stepper class that uses the AccelStepper instance defined in the line above
//           v-- arbitrary name
Vid60Stepper alt100ftPointer(0x107e,          // DCS Bios address For stepper data
                             stepper1,         // 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 zero_stepper1(){
    stepper1.setMaxSpeed(4000);    //  maximum speed in steps per second. Must be > 0.
    stepper1.setAcceleration(8000);  //  desired acceleration in steps per second per second. Must be > 0.0
    stepper1.runToNewPosition(630); // go to the upper end stop
    delay(250);
    stepper1.setCurrentPosition(630); // set max steps
    stepper1.runToNewPosition(0);    // go to the lower end stop
    delay(250);
    stepper1.setCurrentPosition(0);  // set steps to zero
}


const byte altElectPneuPins[3] = {11, 10, 8};
DcsBios::SwitchMultiPos altElectPneu("ALT_ELECT_PNEU", altElectPneuPins, 3);

DcsBios::RotaryEncoder altSetPressure("ALT_SET_PRESSURE", "-1600", "+1600", 12, 13);


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

void loop() {
  PORTB |= (1<<5);
  PORTB &= ~(1<<5);
  DcsBios::loop();
}

cheers

Les

  • Like 1
Posted

A quick update on this

I increased the voltage to the IR LED after discussions with the old sketch not seeming to be sensitive enough - you can read all about it here https://forum.dcs.world/topic/318814-increasing-the-sensitivity-of-ir-digital-position-sensor/#comment-5152445  if you are feeling so inclined. 

My new setup uses a lot of that hardware, and it looks like I may have to go backwards a step on the sensitivity. The new sketch works well, right up until you put the gauge face and 'glass' on it, after which it will not zero. It looks like I have increased the IR LED output to the point where the IR light is bouncing back off the 'glass' with the result that there is no real zeroing signal. Additionally, the potentiometer that is supposed to adjust sensitivity is unable to compensate for it.

So, it looks like I'll have to go back to the 390 ohm resistor, by no means a difficult task. Maybe a potentiometer would be an idea so that I can regulate it but I would have to redo the PCB for that

 

Cheers

Les

 

  • lesthegrngo changed the title to X27 stepper constant rotation altimeter
  • Recently Browsing   0 members

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