Jump to content

How To: mod vid 29 for 360° movement


draken152

Recommended Posts

Hi Guys,

Like some others also I have problems to obtain vid60 motors, than in one thread fbfan64 mentioned it is possible to mod vid29 to 360° movement. I made some investigation and pop up with this solution, for sure there are more solutions...

So what we need (see pic1):

Vid29 motor -link

2 Channel Speed Detection Sensor - link

Detection disk - home made

Easy driver (you don’t need it for mod but for testing) - link

 

1. Disassembly the 4 screw on vid 29 (pic2) and take out the arrow shaft with gear

 

2. From bottom side of the gear you can see a movement restriction pin. Cut it away with sharp knife (pic3).

 

3. Assembly vid29 back

 

4. Now you have motor with 360° movement but you need zero positioning. There are again more solutions but I prefer this because it is easy adjustable, precise and invisible from gauge front side. So glue on the shaft detection disc (pic4)

 

5. Now you just need to assembly your vid29 to gauge and assembly one of the sensors above it (pic5). Detection disk must be after assembly positioned between the two legs/light gate of sensor (pic6), and only the pin of the disk must be positioned in active part of sensor. So zero position is triggered by pin of the disk, sensitivity of sensor is easily adjustable by trimmer on the main pcb of sensors (when is pin detected the corresponding led on main board switch off)

 

6. Now just connect arduino, load Warhogs code....:music_whistling:

 

P.S. Guys I think DCS pit building community is really missing more guides, more or less we have lot of threads with same questions because there are no guides... There are lot of skilled guys here on forum so let’s try to change this in next year... As idea for guides artificial horizon construction, gauge calibration procedure using dcs bios....

pic1.thumb.JPG.73e994b4c2f6600e259e5148106ca7bd.JPG

pic2.thumb.JPG.944eda8e3e36689b096ce90edeb7689f.JPG

pic3.thumb.jpg.21d25d755781b7a21fa3e532686b4e00.jpg

pic4.thumb.JPG.29a82371e923044d056406b665d474aa.JPG

pic5.thumb.JPG.31c1d5f34dc36db4484198ad58086a13.JPG

pic6.thumb.JPG.137d0fdcf0581c379d6042beeedd568a.JPG


Edited by draken152

[sIGPIC][/sIGPIC]

Building FW190D pit ,,To Dora with love" http://forums.eagle.ru/showthread.php?t=132743

Link to comment
Share on other sites

Hi Guys,

Like some others also I have problems to obtain vid60 motors, than in one thread fbfan64 mentioned it is possible to mod vid29 to 360° movement. I made some investigation and pop up with this solution, for sure there are more solutions...

So what we need (see pic1):

Vid29 motor -link

2 Channel Speed Detection Sensor - link

Detection disk - home made

Easy driver (you don’t need it for mod but for testing) - link

 

1. Disassembly the 4 screw on vid 29 (pic2) and take out the arrow shaft with gear

 

2. From bottom side of the gear you can see a movement restriction pin. Cut it away with sharp knife (pic3).

 

3. Assembly vid29 back

 

4. Now you have motor with 360° movement but you need zero positioning. There are again more solutions but I prefer this because it is easy adjustable, precise and invisible from gauge front side. So glue on the shaft detection disc (pic4)

 

5. Now you just need to assembly your vid29 to gauge and assembly one of the sensors above it (pic5). Detection disk must be after assembly positioned between the two legs/light gate of sensor (pic6), and only the pin of the disk must be positioned in active part of sensor. So zero position is triggered by pin of the disk, sensitivity of sensor is easily adjustable by trimmer on the main pcb of sensors (when is pin detected the corresponding led on main board switch off)

 

6. Now just connect arduino, load Warhogs code....:music_whistling:

 

P.S. Guys I think DCS pit building community is really missing more guides, more or less we have lot of threads with same questions because there are no guides... There are lot of skilled guys here on forum so let’s try to change this in next year... As idea for guides artificial horizon construction, gauge calibration procedure using dcs bios....

 

I am so impressed by the level of creativity on this forum. Draken, that is a marvelous little systerm you developed to zero that stepper motor. Well done. I must say, necessity is very much the mother of invention.

 

And I love those little IR detection boards. I have several of them for zeroing my ADI, HSI and my standby ADI. I originally made a couple of them from scratch but when I saw them on eBay... well its no longer worth my while to make my own. I must have purchased around 10 of them in various forms/formats.

 

I'm also playing with another zero detection system that uses a Hall sensors. It uses the switch type hall sensor. The detector itself is extremely tiny and the magnets that are available come in a variety of sizes depending on your requirements. If the IR system doesn't fit the available space I am sure the Hall sensors system could be adapted to fit.

Regards

John W

aka WarHog.

 

My Cockpit Build Pictures...



John Wall

 

My Arduino Sketches ... https://drive.google.com/drive/folders/1-Dc0Wd9C5l3uY-cPj1iQD3iAEHY6EuHg?usp=sharing

 

 

WIN 10 Pro, i8-8700k @ 5.0ghz, ASUS Maximus x Code, 16GB Corsair Dominator Platinum Ram,



AIO Water Cooler, M.2 512GB NVMe,

500gb SSD, EVGA GTX 1080 ti (11gb), Sony 65” 4K Display

VPC MongoosT-50, TM Warthog Throttle, TRK IR 5.0, Slaw Viper Pedals

Link to comment
Share on other sites

Thx to all.

 

WhoMadeWho as I wrote in my guide it is well known Warhogs code for vid60.

 

#define DCSBIOS_IRQ_SERIAL

#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(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, 9, 8);
// define Vid60Stepper class that uses the AccelStepper instance defined in the line above
//           v-- arbitrary name
Vid60Stepper alt100ftPointer(0x107e,          // address of stepper data
                            stepper,         // name of AccelStepper instance
                            stepperConfig,   // StepperConfig struct instance
                            11,              // 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();
 pinMode(13, OUTPUT);
}

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

[sIGPIC][/sIGPIC]

Building FW190D pit ,,To Dora with love" http://forums.eagle.ru/showthread.php?t=132743

Link to comment
Share on other sites

Thx to all.

 

WhoMadeWho as I wrote in my guide it is well known Warhogs code for vid60.

 

#define DCSBIOS_IRQ_SERIAL

#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(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, 9, 8);
// define Vid60Stepper class that uses the AccelStepper instance defined in the line above
//           v-- arbitrary name
Vid60Stepper alt100ftPointer(0x107e,          // address of stepper data
                            stepper,         // name of AccelStepper instance
                            stepperConfig,   // StepperConfig struct instance
                            11,              // 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();
 pinMode(13, OUTPUT);
}

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

 

I would just like to clarify that I am not the author of the code shown above. Ian wrote this code to help me and teach me how to control stepper motors. I passed copies to others who apparently assumed that I wrote it. That, of course, is incorrect. I expect one day to be able to write code at this level but I still have a lot to learn before I am that skilled. Kudos go to Ian for some great code. :thumbup:

Regards

John W

aka WarHog.

 

My Cockpit Build Pictures...



John Wall

 

My Arduino Sketches ... https://drive.google.com/drive/folders/1-Dc0Wd9C5l3uY-cPj1iQD3iAEHY6EuHg?usp=sharing

 

 

WIN 10 Pro, i8-8700k @ 5.0ghz, ASUS Maximus x Code, 16GB Corsair Dominator Platinum Ram,



AIO Water Cooler, M.2 512GB NVMe,

500gb SSD, EVGA GTX 1080 ti (11gb), Sony 65” 4K Display

VPC MongoosT-50, TM Warthog Throttle, TRK IR 5.0, Slaw Viper Pedals

Link to comment
Share on other sites

Thank you very much for the post,

 

I'm using a NORM 8 from Pololu to make my ADI_Bank and my ADI_Pich. I'm using Ian's code too but without using an IR detector. My detail is that reached the maximum position 65535 the stepper "restarts" returns to the initial position marked and then record again the position past the 360. Is it possible for the engine to run a full turn as many times as an IR detector can not be placed?

 

I use this code:

 

#define DCSBIOS_IRQ_SERIAL

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

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

/////////////////////////////////////////////////////////////////////////////////////////////////////////////  
   class NEMA_ocho  : public DcsBios::Int16Buffer {
 
     private:
       AccelStepper& stepper;
         StepperConfig& stepperConfig;
           unsigned int (*map_function)(unsigned int);
            
            unsigned char initState;
 
     public:
        NEMA_ocho 
        
        (unsigned int address, 
         AccelStepper& stepper, 
          StepperConfig& stepperConfig, 
           unsigned int (*map_function)(unsigned int))
               : 
             Int16Buffer(address),
              stepper(stepper), 
               stepperConfig(stepperConfig), 
                map_function(map_function), 
                       
                       initState(0) {
   }

   virtual void loop() {
     
     if (initState == 0) // not initialized yet 
       { 
       stepper.setMaxSpeed(stepperConfig.maxSpeed);
       stepper.setAcceleration(stepperConfig.acceleration);
       stepper.moveTo(-((long)stepperConfig.maxSteps));
       initState = 1;
       }
     
     if (initState == 1) // zeroing
     { 
       stepper.run();
       if (stepper.currentPosition() <= -((long)stepperConfig.maxSteps)) 
         stepper.setCurrentPosition(0);
         initState = 2;
         stepper.moveTo(stepperConfig.maxSteps/2);
         }
     }
     
     if (initState == 2) // running normally
     { 
       if (hasUpdatedData()) 
         {
         unsigned int newPosition = map_function(getData());
         newPosition = constrain(newPosition, 0, stepperConfig.maxSteps);
         stepper.moveTo(newPosition);
         }
       stepper.run();
     }

  
   
   }
};

/* modify below this line */

/* define stepper parameters
  multiple NEMA_ocho instances can share the same StepperConfig object */
struct StepperConfig stepperConfig = {
 6400,  // maxSteps
 10000, // maxSpeed
 10000, // acceleration
 };


// define AccelStepper instance
AccelStepper stepper(AccelStepper::DRIVER);
// define NEMA_ocho class that uses the AccelStepper instance defined in the line above
//           +-- arbitrary name
//           |   +-- Address of stepper data (from control reference)
//           |   |       +-- name of AccelStepper instance
//           v   v       v       v--- StepperConfig struct instance
NEMA_ocho  ADI_Bank(0x1034, stepper, stepperConfig, [](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);
 }
); 


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

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

Link to comment
Share on other sites

If I am understanding you correctly, you want the rotation to be continuous through 360 degrees. Look carefully at the code that was posted and compare it to yours. It appears you not only omitted the IR section which was an error correction routine which does a reset to zero every 360 degrees to correct for stepping errors but you also removed the section that causes the continuous rotation.

 

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;
           
           [b]// if we would move more than 180 degree counterclockwise, move clockwise instead[/b]
           if (delta < -((long)(stepperConfig.maxSteps/2))) delta += stepperConfig.maxSteps;
         [b]  // if we would move more than 180 degree clockwise, move counterclockwise instead[/b]
           if (delta > (stepperConfig.maxSteps/2)) delta -= (long)stepperConfig.maxSteps;

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

 

I am be wrong here but my interpretation of the code posted above is that it causes the pointer (for a gauge) or sphere (for an ADI) to rotate continuously through 360 degrees instead of running backwards to the zero point and then starting over.

 

On the other hand I may be totally out to lunch as I am still learning how to write code and understand the logic that drives it.

Regards

John W

aka WarHog.

 

My Cockpit Build Pictures...



John Wall

 

My Arduino Sketches ... https://drive.google.com/drive/folders/1-Dc0Wd9C5l3uY-cPj1iQD3iAEHY6EuHg?usp=sharing

 

 

WIN 10 Pro, i8-8700k @ 5.0ghz, ASUS Maximus x Code, 16GB Corsair Dominator Platinum Ram,



AIO Water Cooler, M.2 512GB NVMe,

500gb SSD, EVGA GTX 1080 ti (11gb), Sony 65” 4K Display

VPC MongoosT-50, TM Warthog Throttle, TRK IR 5.0, Slaw Viper Pedals

Link to comment
Share on other sites

  • 2 weeks later...
  • Recently Browsing   0 members

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