Jump to content

shreddersa

Members
  • Posts

    49
  • Joined

  • Last visited

Personal Information

  • Flight Simulators
    DCS World, Il2 Series, X-Plane 11
  • Location
    South Africa
  • Interests
    Aviation and Flight Simulation
  • Occupation
    Mechanical Engineer, Full time Heritage Flight Simulation designer
  1. Indeed Stevo! You are most welcome. :) More on the force feedback system I have implemented here: Heritage Flight Simulation Spitfire Mk.IX
  2. :thumbup: Thanks BoboBear, I got it to work and it’s really a fantastic tool!
  3. Thought these videos of the Heritage Flight Simulation Spitfire cockpit might be of interest to the forum members: ${1} Build your own! You can check out the website here: https://heritageflightsim.com/ Roel
  4. :smilewink:That said, I prefer to rely on muscle memory when flying my real aircraft as well as the simulator. You know what they say, a fighter pilot with his head in the cockpit is a dead fighter pilot...:smilewink:
  5. This too is possible. The technology just isn’t quite up to it yet. LeapMotion is actually a very nice reasonably priced solution but not supported by DCS World. I have the VR gloves by VRfree but they are buggy and unreliable in their tracking. My best hope is the work being done by Oculus using their existing built in cameras for hand tracking. Good progress being made there. So yes, that will be good and yes, it’s coming soon! :D
  6. Aha! Great question and I am glad you asked :thumbup: I suspect that part of the reason you asked is that you have not flown DCS World in VR yet? I may be wrong but if you have this should be easier to appreciate. The technical explanation: We are using Augmented Virtuality (AV) to merge the virtual world DCS Mk.IX Spitfire simulator with an accurate real world working cockpit. AV is a subcategory of mixed reality which refers to the merging of real world objects into virtual worlds. As an intermediate case in the virtuality continuum, it refers to predominantly virtual spaces, where physical elements, e.g. physical objects or people, are dynamically integrated into, and can interact with, the virtual world in real time. :smartass: What I want is that you can enter an accurate replica of the Spitfire cockpit, look around you and and interact with the controls. Then when you don the VR headset, the scene washes over you, the cockpit you stepped in to is still there, you can reach out and touch everything you see but you are now in a very real 3D environment, throwing you into a different era or place. The feeling of immersion is incredible. You can look all around and behind you and see the world as if it's really there. Granted, the technology is still young and most (not all!) VR HMD's are still a little grainy, but this is only getting better with time. What inspired me to tackle this project in the first place was the experience of first seeing the Spitfire in VR and the incredibly well made flight model and detail in DCS World. I flew it today for the first time with all the effects (force feedback and Buttkicker) operating (except for the G-seat which I am still developing). The quality of immersion was mind blowing! You are really there.. Of course you could easily go the route of a full dome, you would simply add working gauges which is not a huge additional task. In fact, this is what you will experience when you fly the Boultbee Spitfire Simulator (for mucho Sterling!). But this is all in 2 D and in pretty washed out intensity..and you cannot look behind you...where is the immersion in that? Not to mention the cost of such a setup of course. No, give me VR with a real world cockpit combination anyday! :joystick:
  7. The design has since been simplified somewhat but this will give you an overview. https://heritageflightsim.com/2018/10/25/aileron-force-feedback-design/ https://heritageflightsim.com/2018/09/27/rudders-a-new-take-on-force-feedback/ I will also post a video on my channel showing the detail and operation in due course. https://www.youtube.com/channel/UCpcPJ5Gpc4vvbUc53l-X9Kg
  8. Solution! No1sonuk and Longuich, (also Ian in a different post, see link below) Many thanks for pointing me in the right direction. I have used advice from both of you and after much experimentation, headscratching, research and long hours finally came up with the right combination of elements in the code. The actuator now works beautifully, pulling the bungee cords tight to tension the action of the controls. It uses the airspeed reading to move the full range. This is the code snippet employed: (I have posted the full sketch in this post: https://forums.eagle.ru/showthread.php?p=4322727#post4322727 // constants won't change: const long interval = 100; // interval at which to move the actuator (milliseconds) void setup() { DcsBios::setup(); pinMode(inApin, OUTPUT); pinMode(inBpin, OUTPUT); pinMode(pwmpin, OUTPUT); pinMode(cspin, INPUT); pinMode(actuatorPin, INPUT); } void onAirspeedgaugeChange(unsigned int newValue) { AirSpeedConvert = newValue; //Read the airspeed value } void AirspeedChange() { int actuatorPosNow = analogRead(actuatorPin);// read the Actuator potentiometer (this will be a value between 132 and 1020 see above) int AIRSPEED = static_cast<int>((AirSpeedConvert/46.17)+132); //see explanation for this factor above, will change for different actuators if (AIRSPEED > actuatorPosNow+10){ //if AIRSPEED is higher, start forward motion digitalWrite(inApin, HIGH); //Direction Forward analogWrite(pwmpin, 255); //set PWM speed to max. delay(200); motorOff(); } else if (AIRSPEED < actuatorPosNow-10) { //if AIRSPEED is lower, start Reverse motion digitalWrite(inBpin, HIGH); //Direction Reverse analogWrite(pwmpin, 255); //set PWM speed to max. delay(200); motorOff(); } else { //if AIRSPEED is same as actuator position, switch motor off motorOff(); } if((analogRead(cspin)>CS_THRESHOLD)); { motorOff(); } } DcsBios::IntegerBuffer airspeedgaugeBuffer(0x5436, 0xffff, 0, onAirspeedgaugeChange); void motorOff() { digitalWrite(inApin, LOW); digitalWrite(inBpin, LOW); analogWrite(pwmpin, 0); } void loop() { DcsBios::loop(); // we will check the satus of airspeed every second unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { //check if more than 1/10th second has passed previousMillis = currentMillis; // if yes, save the last time you moved the actuator AirspeedChange(); // and run the Airspeedchange function } // else nothing, just carry on.. }
  9. Solution! Ian, many thanks for pointing me in the right direction. I have used advice from you, others on the forum and external tutorials and guidance. After much experimentation, headscratching, research and long hours I finally managed to come up with the right combination of elements in the code. The actuator now works beautifully, pulling the bungee cords tight to tension the action of the controls. It uses the airspeed reading to move the full range. My publishing it the sketch here is a small token of appreciation for all the help received. Hopefully it will help others too. This is the full sketch::music_whistling: /* Tell DCS-BIOS to use a serial connection and use interrupt-driven communication. The main program will be interrupted to prioritize processing incoming data. This should work on any Arduino that has an ATMega328 controller (Uno, Pro Mini, many others). */ #define DCSBIOS_IRQ_SERIAL #include "DcsBios.h" DcsBios::PotentiometerEWMA<5, 128, 5> trimWheel("TRIM_WHEEL", A1); DcsBios::PotentiometerEWMA<5, 128, 5> rtrimWheel("RTRIM_WHEEL", A2); DcsBios::Switch2Pos fuelPump("FUEL_PUMP", 2); DcsBios::Switch2Pos diluter("DILUTER", 3); DcsBios::Switch2Pos diluterCover("DILUTER_COVER", 4, true); DcsBios::Switch2Pos radTest("RAD_TEST", 5); DcsBios::Switch2Pos radTestCover("RAD_TEST_COVER", 6, true); DcsBios::Switch2Pos msTest("MS_TEST", 7); DcsBios::Switch2Pos msTestCover("MS_TEST_COVER", 33, true); DcsBios::Switch2Pos hatch("HATCH", 34); DcsBios::Switch2Pos sideDoor("SIDE_DOOR", 35); DcsBios::Switch2Pos pitot("PITOT", 36); DcsBios::Switch2Pos radiator("RADIATOR", 37); DcsBios::Switch2Pos wobblePump("WOBBLE_PUMP", 38); DcsBios::RotaryEncoder uc("UC", "DEC", "INC", 14, 15); DcsBios::Switch3Pos morseDnMode("MORSE_DN_MODE", 17, 16); DcsBios::Switch2Pos morseKey("MORSE_KEY", 18); DcsBios::RotaryEncoder morseUpMode("MORSE_UP_MODE", "DEC", "INC", 19, 20); DcsBios::Switch2Pos iffB("IFF_B", 21); DcsBios::Switch2Pos iffD("IFF_D", 22); DcsBios::Switch2Pos iffCover("IFF_COVER", 23); DcsBios::Switch2Pos iff0("IFF_0", 24); DcsBios::Switch2Pos iff1("IFF_1", 25); DcsBios::Switch2Pos droptankCock("DROPTANK_COCK", 26); DcsBios::Switch2Pos droptankJett("DROPTANK_JETT", 27); DcsBios::Switch2Pos ucEmer("UC_EMER", 28); DcsBios::Switch2Pos deicer("DEICER", 29); /* Arduino Airspeed Force Feedback Control Rev6 code by: Roel Stausebach, building on work by various before me The code addresses the following elements: MiniMonsterMoto control (VNH2SP30 Monster Motor Module, single channel) Indicated airspeed from Airspeedgauge value of DCS-BIOS Actuator Potentiometer - to provide current position. 1. OPERATION - READ THE "AIRSPEEDGAUGE" value, ADJUST THE ACTUATOR TO THAT POSITION The range can be between 0 and 65535. For the Spitfire the full gauge reading is 480mph We want full effect of the Force Feedback to be at 480mph Arduino has an analogRead range from 0 to 1023, and the actuator potentiometer is usually less than this. (see below, in our case it is 132 to 1020)We assign the AirSpeedConvert value to this. In the Prototype the potentiometer range runs from 132 retracted to 1020 extended. This was established using the Actuator_Range_Test sketch and is something that will need to be done for each different actuator. To calculate the values to be used: full range of movement: 1020-132=888 AirSpeedConvert runs from 0 to 65535=480mph So a speed range of 65535 is represented by 888 on the potentiometer range Thus a factor of 65535/888=73.8+132 to convert to AIRSPEED (the 132 is added as it is the miniumum reading on the actuator potentiometer) Lets say airspeed is 280mph then: AirSpeedConvert=280/480x65535=38228.75 and AIRSPEED=(38228.75/73.8)+132=650 and lets assume the current actuator position actuatorPosNow reads 381, so now we need to move the actuator to a position where the readout is 650 */ // Variables that remain the same: const int CS_THRESHOLD = 0.65; //this is the overload value for 5A at approx 0.13V per amp of output current const int inApin = 39; // INA: Clockwise input const int inBpin =40; // INB: Counter-clockwise input const int pwmpin = 8; // PWM OUTput const int actuatorPin = A3; // the pin that the actuator potentiometer is attached to const int cspin = A9; // Connect to the CS (current sense) pin on the MiniMonsterMoto // Generally, you should use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0; // will store last time LED was updated unsigned int AirSpeedConvert; // constants won't change: const long interval = 100; // interval at which to move the actuator (milliseconds) void setup() { DcsBios::setup(); pinMode(inApin, OUTPUT); pinMode(inBpin, OUTPUT); pinMode(pwmpin, OUTPUT); pinMode(cspin, INPUT); pinMode(actuatorPin, INPUT); } void onAirspeedgaugeChange(unsigned int newValue) { AirSpeedConvert = newValue; //Read the airspeed value } void AirspeedChange() { int actuatorPosNow = analogRead(actuatorPin);// read the Actuator potentiometer (this will be a value between 132 and 1020 see above) int AIRSPEED = static_cast<int>((AirSpeedConvert/46.17)+132); //see explanation for this factor above, will change for different actuators if (AIRSPEED > actuatorPosNow+10){ //if AIRSPEED is higher, start forward motion digitalWrite(inApin, HIGH); //Direction Forward analogWrite(pwmpin, 255); //set PWM speed to max. delay(200); motorOff(); } else if (AIRSPEED < actuatorPosNow-10) { //if AIRSPEED is lower, start Reverse motion digitalWrite(inBpin, HIGH); //Direction Reverse analogWrite(pwmpin, 255); //set PWM speed to max. delay(200); motorOff(); } else { //if AIRSPEED is same as actuator position, switch motor off motorOff(); } if((analogRead(cspin)>CS_THRESHOLD)); { motorOff(); } } DcsBios::IntegerBuffer airspeedgaugeBuffer(0x5436, 0xffff, 0, onAirspeedgaugeChange); void motorOff() { digitalWrite(inApin, LOW); digitalWrite(inBpin, LOW); analogWrite(pwmpin, 0); } void loop() { DcsBios::loop(); // we will check the satus of airspeed every second unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { //check if more than 1/10th second has passed previousMillis = currentMillis; // if yes, save the last time you moved the actuator AirspeedChange(); // and run the Airspeedchange function } // else nothing, just carry on.. }
  10. Thank you! Will give it a try and provide feedback on the result :)
  11. Thanks, I’m really hoping someone can post a code snippet example of how to call this within the loop() function.
  12. Thanks and a question Hi Bear, many thanks for this tool, its a heaven sent! I would like to check with you though, I cannot find any json files in the DCS_BIOS folder, except for MetadataEnd/Start in the control-reference-json folder? I am looking for my Spitfire json, I can use it through the DCS-BIOS interface so I dont know where its calling that from? Thanks again, Roel
  13. The DCS-BIOS documentation says the following about IntegerBuffer: "Sometimes it is more convenient to get rid of the callback function and check the current value yourself from code in the loop() function." This is the code snippet given which provides guidance on the callback: void onAltMslFtChange(unsigned int newValue) { /* your code here */ } DcsBios::IntegerBuffer altMslFtBuffer(0x0408, 0xffff, 0, onAltMslFtChange); So in this case the callback "onAltMslFtChange" is given and provided a function. How would I call the altMslFtBuffer value in the loop function? As background I would like to run my code in the loop function as I require to use the timer function millis() in the loop to ensure that my force feedback actuator can run a while before re-assessing where it is. (I use the airspeed gauge value for that) Any help appreciated!
×
×
  • Create New...