{"id":151,"date":"2024-05-25T15:34:21","date_gmt":"2024-05-25T15:34:21","guid":{"rendered":"https:\/\/manueldobusch.eu\/blog\/?p=151"},"modified":"2024-06-01T22:37:02","modified_gmt":"2024-06-01T22:37:02","slug":"dcs-g-suite","status":"publish","type":"post","link":"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/","title":{"rendered":"DCS G-Suit"},"content":{"rendered":"\n<p>As a live-long aviation enthusiast I&#8217;ve been playing flight simulators since childhood. For about as long as that I had a fascination for associated computer peripheries, joysticks, pedals and such. Anything to improve the illusion of sitting in an actual cockpit.<\/p>\n\n\n\n<p>So anyways, here is my attempt at inflating my pants.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"DCS G Suit Demo\" width=\"525\" height=\"295\" src=\"https:\/\/www.youtube.com\/embed\/ySS8RbgyLog?list=PL5l3saOZz1AWyk0SceIl3rBGm8SRCjycH\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_66_1 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69ec0ac7f1440\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #161616;color:#161616\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #161616;color:#161616\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69ec0ac7f1440\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Motivation\" title=\"Motivation\">Motivation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Project_Overview\" title=\"Project Overview\">Project Overview<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Hardware\" title=\"Hardware\">Hardware<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Wiring\" title=\"Wiring\">Wiring<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Code\" title=\"Code\">Code<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Arduino_Code\" title=\"Arduino Code\">Arduino Code<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#G-Suit_Server\" title=\"G-Suit Server\">G-Suit Server<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#DCS_Plugin\" title=\"DCS Plugin\">DCS Plugin<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Known_Issues_and_further_Development\" title=\"Known Issues and further Development\">Known Issues and further Development<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Acknowledgement\" title=\"Acknowledgement\">Acknowledgement<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/#Resources\" title=\"Resources\">Resources<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Motivation\"><\/span>Motivation<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>If you are in the know about military aviation you will already have guessed that my pants-inflation endavours have <s>very little<\/s> no <a href=\"https:\/\/en.wikipedia.org\/wiki\/Body_inflation\" target=\"_blank\" rel=\"noreferrer noopener\">sexual<\/a> motivation. Instead this is an attempt at creating haptic feedback for <a href=\"https:\/\/en.wikipedia.org\/wiki\/G-force\" target=\"_blank\" rel=\"noreferrer noopener\">G-Forces<\/a> experienced in flight (-simulation).<\/p>\n\n\n\n<p>Actual G-Forces have a number of effects on the human body. For starters, there is that stomach-drop sensation that most people will know from either flying commercially or maybe from riding a roller coaster. With increasing severity, there is the onset of tunnel-vision, culminating in loss of consciousness.<\/p>\n\n\n\n<p>I am over-simplyfing for brevity, but in any case I don&#8217;t know enough about the human body to (safely) simulate any of those effects (within budget&#8230;). So instead I decided to create a little desktop version of a pilot&#8217;s <a href=\"https:\/\/en.wikipedia.org\/wiki\/G-suit\" target=\"_blank\" rel=\"noreferrer noopener\">g suit<\/a>.<\/p>\n\n\n\n<p>Simplyfied, to combat the effects of G-Forces fighter pilots wear inflatable pants to help pushing blood up from the legs. The approach of recreating this equipment provides both usefull haptic feedback and is at least related to what a real fighter pilot would feel during flight.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"overview\"><span class=\"ez-toc-section\" id=\"Project_Overview\"><\/span>Project Overview<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium-1024x768.jpg\" alt=\"\" class=\"wp-image-291\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium-1024x768.jpg 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium-300x225.jpg 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium-768x576.jpg 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium-1536x1152.jpg 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/overview0_medium.jpg 1920w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Pump Box with connected Leg-Wraps<\/figcaption><\/figure>\n\n\n\n<p>This project is an attempt at creating a <a href=\"https:\/\/en.wikipedia.org\/wiki\/G-suit\" target=\"_blank\" rel=\"noreferrer noopener\">g suit<\/a> like computer periphery for use with flight simulators. Leg-wraps with internal air chambers inflate proportionally to increased g loads experienced by the player to create pressure on the legs. This pressure sensation provides feedback to the player about ingame forces without having to read on-screen dials.<\/p>\n\n\n\n<p>Other than real g suits it covers only the upper thighs. This reduces the internal volume and makes it easier and quicker to in- and deflate them. It also makes it easier and quicker to set the whole thing up and put it on.<\/p>\n\n\n\n<p>The <a href=\"#hardware\">hardware<\/a> for this project consists of two components<\/p>\n\n\n\n<ul>\n<li>A box providing air supply<\/li>\n\n\n\n<li>Leg-wraps with inflatable air-chambers<\/li>\n<\/ul>\n\n\n\n<p>The box houses six <a href=\"https:\/\/www.adafruit.com\/product\/4699\" target=\"_blank\" rel=\"noreferrer noopener\">small air pumps<\/a> and an <a href=\"https:\/\/store.arduino.cc\/products\/arduino-leonardo-without-headers\" data-type=\"link\" data-id=\"https:\/\/store.arduino.cc\/products\/arduino-leonardo-without-headers\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino Leonardo<\/a>. I just happen to have a few Leonardos lying around, most other models will do just as fine. The pump motors are controlled with <a href=\"https:\/\/www.sparkfun.com\/products\/retired\/13911\" target=\"_blank\" rel=\"noreferrer noopener\">Serial Controlled Motor Drivers<\/a> from SparkFun. At time of writing those are unfortunately discontinued.<br>The box also has <a href=\"https:\/\/www.berrybase.at\/luefter-30x30x10mm-5v-dc-mit-dupont-steckverbinder\" data-type=\"link\" data-id=\"https:\/\/www.berrybase.at\/luefter-30x30x10mm-5v-dc-mit-dupont-steckverbinder\" target=\"_blank\" rel=\"noreferrer noopener\">two little fans<\/a> to keep the motor drivers and the motors cool, two LEDs to indicated power supply to the Arduino and the motor drivers and an <a href=\"https:\/\/www.conrad.com\/en\/p\/apem-637nh-2-637nh-2-toggle-switch-250-v-ac-10-a-1-x-on-off-on-momentary-0-momentary-1-pc-s-700753.html\" target=\"_blank\" rel=\"noreferrer noopener\">(on)-off-(on) <\/a>switch for testing.<\/p>\n\n\n\n<p>The leg-wraps are simple fabric strips that close with velcro and have pockets to hold inflatable plastic tubes. The plastic tubes are connected with <a href=\"https:\/\/www.conrad.com\/en\/p\/papurex-pu-6-1198-25-1-pu-polyurethan-6-x-3-9-25m1-black-583670.html\" target=\"_blank\" rel=\"noreferrer noopener\">silicon and plastic tubing<\/a>, and standard <a href=\"https:\/\/www.conrad.at\/de\/p\/tru-components-y-verbinder-py6-rohr-o-6-mm-1-st-2615648.html\" target=\"_blank\" rel=\"noreferrer noopener\">pneumatic connectors<\/a> with 6mm outer diameter.<br>One of the plastic tubes contains a <a href=\"https:\/\/www.berrybase.de\/bmp280-breakout-board-2in1-sensor-fuer-temperatur-und-luftdruck\" target=\"_blank\" rel=\"noreferrer noopener\">pressure sensor<\/a>. This enables mapping of G-Forces to air-pressure.<\/p>\n\n\n\n<p>The <a href=\"#code\">software<\/a> for this project has three components. The code running on the Arduino controls the pumps and provides serial communication via a simple protocol. A standalone desktop application communicates with the Arduino and receives G-Forces as floats via TCP socket. Lastly there is the DCS plugin which simply passes on the player&#8217;s current G-Force.<br>The source code is available on github (<a href=\"https:\/\/github.com\/wrongway88\/gSuitServer\" target=\"_blank\" rel=\"noreferrer noopener\">Server<\/a>, <a href=\"https:\/\/github.com\/wrongway88\/gSuitArduino\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino<\/a>, <a href=\"https:\/\/github.com\/wrongway88\/gSuitDCSPlugin\" target=\"_blank\" rel=\"noreferrer noopener\">Plugin<\/a>).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"hardware\"><span class=\"ez-toc-section\" id=\"Hardware\"><\/span>Hardware<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>As stated in <a href=\"#overview\" data-type=\"internal\" data-id=\"#overview\">Project Overview<\/a> most of the electronic components are housed in a box with air pumps.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium-1024x768.jpg\" alt=\"\" class=\"wp-image-195\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium-1024x768.jpg 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium-300x225.jpg 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium-768x576.jpg 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium-1536x1152.jpg 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/inside0_medium.jpg 1920w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Inside the case, electronics are on the left, pumps are on the right<\/figcaption><\/figure>\n\n\n\n<p>The electronics compartement is somewhat compact and difficult to photograph. The <a href=\"#wiring\">wiring <\/a>will be explained in detail below.<\/p>\n\n\n\n<p>The  six air pumps are arranged in two groups, one for inflation and one for deflation. This type of <a href=\"https:\/\/www.adafruit.com\/product\/4699\">pump<\/a> does blow the same way regardless of engine direction, therefore the two groups are needed.<\/p>\n\n\n\n<p>The tubes coming from the pumps all combine into one single outlet. The software only ever runs one of the two pump groups, therefore only one outlet is needed.<\/p>\n\n\n\n<p>The outlet connects to a silicon tube ending in a pneumatic coupling. A cable with 4 wires to connect a pressure sensor runs along the tube and ends in a 4-pin plug.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium-1024x768.jpg\" alt=\"\" class=\"wp-image-285\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium-1024x768.jpg 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium-300x225.jpg 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium-768x576.jpg 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium-1536x1152.jpg 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/connectors0_medium.jpg 1920w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Air and sensor connectors between Pump Box and Leg-Wraps<\/figcaption><\/figure>\n\n\n\n<p>The second and final part of the hardware setup is a pair of leg-wraps covering the user&#8217;s upper thighs. The wraps are constructed from cotton fabric and close with 5 cm velcro strips. Each wrap has 3 pockets for air chambers.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium-1024x768.jpg\" alt=\"\" class=\"wp-image-283\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium-1024x768.jpg 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium-300x225.jpg 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium-768x576.jpg 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium-1536x1152.jpg 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/legWraps0_medium.jpg 1920w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Leg Wraps with air chambers<\/figcaption><\/figure>\n\n\n\n<p>The air chambers are made from <a href=\"https:\/\/www.hornbach.at\/p\/gartenfolie-floraself-5x2-m-gruen\/6425333\/\" target=\"_blank\" rel=\"noreferrer noopener\">PE foil<\/a> because this material is well suited to be welded with a heat gun. Each chamber connects to a pneumatic splitter via a tube. One of the chambers contains a <a href=\"https:\/\/www.berrybase.de\/bmp280-breakout-board-2in1-sensor-fuer-temperatur-und-luftdruck\" target=\"_blank\" rel=\"noreferrer noopener\">GY-BMP280<\/a> pressure sensor. This sensor is used to control inflation of the air chambers. The idea is to map a range of G-Forces to a pressure range.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium-1024x768.jpg\" alt=\"\" class=\"wp-image-288\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium-1024x768.jpg 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium-300x225.jpg 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium-768x576.jpg 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium-1536x1152.jpg 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/airChambers0_medium.jpg 1920w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Air Chambers with Pressure Sensor in the top one<\/figcaption><\/figure>\n\n\n\n<p>A given force f<sub>n<\/sub> translates to a pressure p<sub>n<\/sub>. The pumps are used to reach and maintain p<sub>n<\/sub> within a given tolerance until the given force changes.<\/p>\n\n\n\n<p>The air tube running from the air chambers and the cable running from the pressure sensor end in the counter parts to the coupling and plug coming from the pump box.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"wiring\"><span class=\"ez-toc-section\" id=\"Wiring\"><\/span>Wiring<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The electronic components for this project consist of<\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/store.arduino.cc\/collections\/boards-modules\/products\/arduino-leonardo-without-headers?_pos=14&amp;_fid=91ab14ea3&amp;_ss=c\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino Leonardo<\/a> (without headers)<\/li>\n\n\n\n<li>3 x <a href=\"https:\/\/www.sparkfun.com\/products\/retired\/13911\" target=\"_blank\" rel=\"noreferrer noopener\">SparkFun Serial Controlled Motor Driver<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.sparkfun.com\/products\/12009\" target=\"_blank\" rel=\"noreferrer noopener\">SparkFun Logic Level Converter<\/a><\/li>\n\n\n\n<li>6 x <a href=\"https:\/\/www.adafruit.com\/product\/4699\" target=\"_blank\" rel=\"noreferrer noopener\">DC Air Pump<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.berrybase.de\/bmp280-breakout-board-2in1-sensor-fuer-temperatur-und-luftdruck\" target=\"_blank\" rel=\"noreferrer noopener\">GY-BMP280 Pressure Sensor<\/a><\/li>\n\n\n\n<li>2 x <a href=\"https:\/\/www.berrybase.at\/luefter-30x30x10mm-5v-dc-mit-dupont-steckverbinder\" target=\"_blank\" rel=\"noreferrer noopener\">30mm DC Fan<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.conrad.at\/de\/p\/apem-637h-2-637h-2-kippschalter-250-v-ac-10-a-1-x-ein-aus-ein-tastend-0-tastend-1-st-700596.html\" target=\"_blank\" rel=\"noreferrer noopener\">(on)\/off\/(on) Toggle Switch<\/a><\/li>\n\n\n\n<li>2 x LED (+ resistor)<\/li>\n<\/ul>\n\n\n\n<p>This list excludes some simple parts like power plugs and cable connectors.<\/p>\n\n\n\n<p>There is no specific reason to use the Leonardo board, other than that&#8217;s what I had lying around. If you opt for a different board note that the pinout on the Leonardo is somewhat different from most other similar ones like the Uno. The descriptions below are based on the Leonardo but I will try to point out relevant differences.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"597\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-1024x597.png\" alt=\"\" class=\"wp-image-198\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-1024x597.png 1024w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-300x175.png 300w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-768x448.png 768w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-1536x896.png 1536w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite_bb_drivers-2048x1195.png 2048w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><figcaption class=\"wp-element-caption\">Complete wiring diagram<\/figcaption><\/figure>\n\n\n\n<p>I was not able to find Fritzing files for all the components, most notably the motor driver. Therefore parts of the diagram look a bit artisanal. The 6 pumps are represented as motors in the diagram, but that&#8217;s basically what they are anyways.<\/p>\n\n\n\n<p>The specific <strong>motor drivers<\/strong> used in this project were chosen because they are chainable to control more than 2 motors without running out of pins on the Arduino. Up to 16 drivers can be chained with two motors each, for a total of up to 32 motors.<br>The <a href=\"https:\/\/learn.sparkfun.com\/tutorials\/serial-controlled-motor-driver-hookup-guide\" target=\"_blank\" rel=\"noreferrer noopener\">hookup guide<\/a> shows how to connect to an Arduino (or SparkFun board). Especially example 3 in the guide is relevant to this project.<\/p>\n\n\n\n<p><strong>NOTE <\/strong>that the Arduino Leonardo&#8217;s pinout differs from the RedBoard in the guide as well as Arduino Uno. Importantly the SCL, COPI, and CIPO pins are in a different position. They are found among the 6 ICSP pins oposite from the USB connection. Refer to the page 3 of the official <a href=\"https:\/\/docs.arduino.cc\/resources\/pinouts\/A000057-full-pinout.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">pinout diagram<\/a>. Pin 10 as chip select is the same as in the hookup guide though.<\/p>\n\n\n\n<p>To limit the load on the drivers at any given time I did connect one inflation and one deflation motor each. Therefore only ever one engine per driver will be running.<\/p>\n\n\n\n<p>The motor drivers have pins for an external power supply for the motors. I use a 9V power supply with 3000 mA, indicated by the standalone socket in the diagram. Each pump motor draws up to 500 mA according to the documentation. However, using an adjustable lab power supply I measured more than that, so I recommend some headroom.<\/p>\n\n\n\n<p>One <strong>LED <\/strong>(with resistor fitting for 9V supply) connects directly to the socket.<\/p>\n\n\n\n<p>The <strong>pressure sensor<\/strong> uses i2c communication and therefore connects to the SDA and SCL pins (as well as ground and 5V).<\/p>\n\n\n\n<p><strong>NOTE <\/strong>that the SDA and SCL pins on the Leonardo are again placed differently than on similar boards. Refer to page 2 of the <a href=\"https:\/\/docs.arduino.cc\/resources\/pinouts\/A000057-full-pinout.pdf\" target=\"_blank\" rel=\"noreferrer noopener\">pinout diagram<\/a>.<\/p>\n\n\n\n<p>The outer pins of the <strong>toggle switch<\/strong> connect to digital pins 4 and 5, the center pin on the switch connects to ground. Since the switch I use does not lock on either of the outer positions it basically behaves like two buttons.<\/p>\n\n\n\n<p>One <strong>LED <\/strong>(with a resistor fitting for 5V supply) and the two <strong>cooling fans<\/strong> connect directly to the Arduino&#8217;s 5V and ground pins.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"code\"><span class=\"ez-toc-section\" id=\"Code\"><\/span>Code<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The code for this project consists of three components<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"730\" height=\"140\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite.drawio-1.png\" alt=\"\" class=\"wp-image-299\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite.drawio-1.png 730w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuite.drawio-1-300x58.png 300w\" sizes=\"(max-width: 730px) 100vw, 730px\" \/><\/figure>\n\n\n\n<ul>\n<li><a href=\"#arduinocode\">Arduino Code<\/a> (<a href=\"https:\/\/github.com\/wrongway88\/gSuitArduino\" target=\"_blank\" rel=\"noreferrer noopener\">Repository<\/a>)<\/li>\n\n\n\n<li><a href=\"#gsuiteserver\">G-Suit Server<\/a> (<a href=\"https:\/\/github.com\/wrongway88\/gSuitServer\" target=\"_blank\" rel=\"noreferrer noopener\">Repository<\/a>)<\/li>\n\n\n\n<li><a href=\"#dcsplugin\">DCS Plugin<\/a> (<a href=\"https:\/\/github.com\/wrongway88\/gSuitDCSPlugin\" target=\"_blank\" rel=\"noreferrer noopener\">Repository<\/a>)<\/li>\n<\/ul>\n\n\n\n<p>The following discussion only covers some of the more noteworthy elements. The full code is available in the linked repositories.<\/p>\n\n\n\n<p>The <a href=\"#arduinocode\">code running on the Arduino<\/a> in the <a href=\"#hardware\">pump box<\/a> controlls the pumps (suprise&#8230;) to reach and maintain a given pressure value within the leg-wraps&#8217; air chambers.<\/p>\n\n\n\n<p>The <a href=\"#gsuiteserver\">G Suit Server<\/a> is a standalone desktop application that implements the serial communication with the Arduino and provides a simple GUI for testing and debugging. The server listens to a TCP port to receive G-Force magnitudes from external sources (typically a flight simulator&#8230;DCS perhaps&#8230;).<\/p>\n\n\n\n<p>The <a href=\"#dcsplugin\">DCS plugin<\/a> simply sends current G-Forces to the G-Suit Server.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"arduinocode\"><span class=\"ez-toc-section\" id=\"Arduino_Code\"><\/span>Arduino Code<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/wrongway88\/gSuitArduino\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino code<\/a> is mainly responsible for controlling an array of six air pumps. As mentioned in the <a href=\"#wiring\" data-type=\"internal\" data-id=\"#hardware\">Wiring <\/a>section, the pump motors are controlled by three SparkFun Serial Controlled Motor Drivers using the corresponding <a href=\"https:\/\/www.arduino.cc\/reference\/en\/libraries\/serial-controlled-motor-driver\/\" target=\"_blank\" rel=\"noreferrer noopener\">library<\/a>. A GY-BMP 280 sensor is used to messure pressure inside air chambers, using the <a href=\"https:\/\/www.arduino.cc\/reference\/en\/libraries\/adafruit-bmp280-library\/\" target=\"_blank\" rel=\"noreferrer noopener\">BMP280<\/a> library.<\/p>\n\n\n\n<p>The setup function will block until both the motor drivers and the pressure sensor are initialized to make sure everything works as intended, or better not at all. The setup code for the motor drivers is based on the <a href=\"https:\/\/learn.sparkfun.com\/tutorials\/serial-controlled-motor-driver-hookup-guide\" target=\"_blank\" rel=\"noreferrer noopener\">hookup guide<\/a> (example 3), omitting the bridging part.<\/p>\n\n\n\n<p>The pump control is programmed to inflate the connected air chambers (mentioned in the <a href=\"#hardware\">Hardware <\/a>section) to a given pressure. To do so the environment pressure is taken and stored immediatly after initialization. During runtime the reference pressure is continuously updated when the pumps were inactive for 60 seconds.<br>The idea is that, since the air system is not completely airtight the pressure inside will have normalized to environment levels after 60 seconds. This continuous updating prevents weird behaviour if the environment pressure changes significantly (e.g. significant weather changes).<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void calibrate()\n{\n  \/*\n  setDeflationSpeed(PUMP_SPEED);\n\n  delay(1000);\n\n  setDeflationSpeed(0);\n\n  delay(10000);\n  \/**\/\n\n  if(_sensorIsAvailable == true)\n  {\n    _referencePressure = _bmp.readPressure();\n\n    PrintLine(\"Calibrated Reference Pressure = \" + String(_referencePressure));\n  }\n  else\n  {\n    PrintLine(\"Pressure Sensor is not available\");\n  }\n  \n  _sensorIsCalibrated = true;\n}<\/pre>\n\n\n\n<p>Note that deflation before taking the reference value is disabled because it actually creates a slight vacuum if the chambers were empty to begin with.<\/p>\n\n\n\n<p>The main pump control logic is implemented in the <em>handleTargetPressure<\/em> function. If a target pressure is set the code will attempt to inflate or deflate the air chambers until the target is met within a slight tolerance. Note that target pressures are given as offset to the environment pressure.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void handleTargetPressure()\n{\n  float pressure = _bmp.readPressure() - _referencePressure;\n\n  if(_targetSet)\n  {\n    float diff = _targetPressure - pressure;\n    float absDiff = abs(diff);\n\n    \/\/ PrintLine(String(_targetPressure) + \" - \" + String(pressure) + \" = \" + String(diff));\n\n    if(absDiff > 20.0f) \/\/ get positive, diff > 50\n    {\n      float pf = 1.0f;\n\n      if(absDiff &lt; PUMP_REG_LIMIT)\n      {\n        pf = constrain(absDiff \/ PUMP_REG_LIMIT, 0.2f, 1.0f);\n      }\n\n      if(diff > 0.0f)\n      {\n        setDeflationSpeed(0.0f);\n        setInflationSpeed(PUMP_SPEED * pf);\n      }\n      else\n      {\n        setInflationSpeed(0.0f);\n        setDeflationSpeed(PUMP_SPEED * pf);\n      }\n    }\n    else\n    {\n      setInflationSpeed(0.0f);\n      setDeflationSpeed(0.0f);\n      if(_targetPressure &lt;= 0.0f)\n      {\n        _targetSet = false;\n      }\n    }\n  }\n}<\/pre>\n\n\n\n<p>If the pressure difference to the target is lower than PUMP_REG_LIMIT, but higher than the tolerance value the pump speed is progressively limited to compensate for measurement latency. Otherwise the pumps are run at a given maximum speed.<\/p>\n\n\n\n<p>If a target pressure of 0 was given (remember, targets are offsets from environment pressure) the target pressure will be discarded once it has been reached. This means active pressure regulation ceases until a new non-zero target is given.<\/p>\n\n\n\n<p>The <em>readSerialInput<\/em> function implements a simple serial communication protocol. The implementation is straight forward and will not be discussed in detail. The messages are<\/p>\n\n\n\n<ul>\n<li>PUMPITUP (challenge to be sent by the Server application)<\/li>\n\n\n\n<li>HITTHEJAM (response to be sent by the Arduino after the challenge message was received)<\/li>\n\n\n\n<li>INFL (run inflation pumps, to be sent by server)<\/li>\n\n\n\n<li>DEFL (run the deflation pumps, to be sent by server)<\/li>\n\n\n\n<li>STOP (stop all pumps, to be sent by server)<\/li>\n\n\n\n<li>REBOOT (experimental, send a reboot impulse to motor drivers, to be sent by server)<\/li>\n\n\n\n<li>SET_PRESSURE&lt;float> (set the target pressure, to be sent by server)<\/li>\n<\/ul>\n\n\n\n<p>All messages end with a delimiter character, &#8216;;&#8217;.<\/p>\n\n\n\n<p>The main loop make sure that the reference pressure is set, handle serial and test switch input, verify the motor drivers and pressure sensor are connected, and handle the target pressure, if given.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void loop()\n{\n  if(_sensorIsCalibrated == false)\n  {\n    calibrate();\n  }\n\n  readSerialInput();\n\n  handleTestSwitch();\n\n  updatePumps();\n\n  \/\/ delay to give serial com. some space\n  delay(UPDATE_DELAY);\n\n  \/\/ check if motor driver is still up and running, or reset if not (e.g. power supply disconnected or something...)\n  SCMDDiagnostics diagObject;\n  _motorDriver.getDiagnostics(diagObject);\n  if(diagObject.MST_E_ERR != 0x0)\n  {\n    Serial.println(\"Motor driver lost\");\n    setupMotorDriver();\n  }\n\n  \/\/ check sensor is up and running and reset\/restart until it is (e.g. unplugged...)\n  uint8_t status = _bmp.getStatus();\n\n  if(_sensorIsAvailable == false\n    || status == 0xF3)\n  {\n    resetPressureSensor();\n  }\n  else\n  {\n    \/\/ normal operations\n    handleTargetPressure();\n  }\n\n  \/\/ recalibrate periodically to handle changing environment conditions\n  if(_targetSet == false)\n  {\n    _inactiveTime += UPDATE_DELAY * 2; \/\/ x2 because we delay after reading serial input\n\n    if(_inactiveTime > RECALIBRATION_TIMEOUT)\n    {\n      _referencePressure = _bmp.readPressure();\n\n      PrintLine(\"Calibration updated to \" + String(_referencePressure));\n\n      _inactiveTime = 0.0f;\n    }\n  }\n  else\n  {\n    _inactiveTime = 0.0f;\n  }\n\n  delay(UPDATE_DELAY);\n}<\/pre>\n\n\n\n<p>If either the motor drivers or the pressure sensor are disconnected execution will halt until everything is reconnected. This means the code will go back into the respective initialization loops.<\/p>\n\n\n\n<p>The last action in the main loop is to handle the given target pressure. As discussed before, if no target is given for some time the reference pressure will be updated.<\/p>\n\n\n\n<p>Most of the rest of the code consits of utility functions to control the pumps and handle a test switch wired to the arduino, intended for manual testing of the pumps. It&#8217;s pretty straight forward and wont be discussed in detail.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"gsuiteserver\"><span class=\"ez-toc-section\" id=\"G-Suit_Server\"><\/span>G-Suit Server<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/wrongway88\/gSuitServer\" target=\"_blank\" rel=\"noreferrer noopener\">G Suit Server<\/a> application handles communication between the DCS Plugin and the Arduino Code. It is a standalone application with a simple debugging\/testing GUI written in C#.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"635\" height=\"543\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/server-1.png\" alt=\"\" class=\"wp-image-307\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/server-1.png 635w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/server-1-300x257.png 300w\" sizes=\"(max-width: 635px) 100vw, 635px\" \/><figcaption class=\"wp-element-caption\">G Suit Server GUI<\/figcaption><\/figure>\n\n\n\n<p>The GUI has a textfield to manually send commands to the Arduino, a box for debug output from the Arduino or the Server application itself, and a slider to test the G Force\/pressure range.<\/p>\n\n\n\n<p>The main components of the server are the serial port wrapper, the TCP socket listener, the message buffer, and the main form GSuit.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"677\" height=\"561\" src=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuitServer-1.png\" alt=\"\" class=\"wp-image-311\" style=\"width:674px;height:auto\" srcset=\"https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuitServer-1.png 677w, https:\/\/manueldobusch.eu\/blog\/wp-content\/uploads\/2024\/05\/gSuitServer-1-300x249.png 300w\" sizes=\"(max-width: 677px) 100vw, 677px\" \/><figcaption class=\"wp-element-caption\">Simplified Server Architecture<\/figcaption><\/figure>\n\n\n\n<p>The serial port wrapper handles communication with the Arduino. It provides an interface to send and receive messages.<br>Noteworthy is the handling of an unexpectedly closed connection. This topic seems to be a bit <a href=\"https:\/\/stackoverflow.com\/questions\/13408476\/detecting-when-a-serialport-gets-disconnected\" target=\"_blank\" rel=\"noreferrer noopener\">tricky<\/a>. I opted to simply catch and handle the exceptions resulting from accessing a disconnected <em>SerialPort<\/em>. See as an example the <em>WriteSerialPort<\/em> function.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public void WriteSerialPort(String message)\n{\n    try \/\/ isOpen doesn't catch if the serial plug was disconnected, causing an exception :(\n    {\n        lock (_serialPort)\n        {\n            if (_serialPort.IsOpen)\n            {\n                _serialPort.Write(message + \";\");\n            }\n            else\n            {\n                TryOpenPort();\n            }\n        }\n    }\n    catch(Exception  e)\n    {\n        if(_serialPortError != null)\n        {\n            _serialPortError();\n        }\n\n        return;\n    }\n}<\/pre>\n\n\n\n<p><em>_serialPortError <\/em>is a callback that will be handled in <em>GSuit<\/em>.<\/p>\n\n\n\n<p>AsynchronousSocketListener<\/p>\n\n\n\n<p>The message buffer gathers messages to be sent to the Arduino, sends them one by one (while avoiding successive duplicates) and receives responses.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public static void Run()\n{\n    String nextMessage = \"\";\n\n    while (_isRunning)\n    {\n        if (_readBuffer.Count > 0)\n        {\n            nextMessage = _readBuffer.Dequeue();\n        }\n        else\n        {\n            lock (_writeBuffer)\n            {\n                lock (_readBuffer)\n                {\n                    _readBuffer = _writeBuffer;\n                    _writeBuffer = new Queue&lt;string>();\n                }\n            }\n        }\n\n        if (nextMessage.Length > 0\n            &amp;&amp; _lastSentMessage != nextMessage)\n        {\n            _debugPrintCallback.Invoke(\"message Buffer to Serial: \" + nextMessage);\n\n            _writeToSerialPortCallback.Invoke(nextMessage);\n\n            _lastSentMessage = nextMessage;\n            nextMessage = \"\";\n        }\n\n        String message = \"\";\n\n        String fragment = _serialReadCallback();\n\n        while (fragment.Length > 0)\n        {\n            message += fragment;\n            fragment = _serialReadCallback();\n        }\n                \n\n        if(message.Length > 0)\n        {\n            _debugPrintCallback.Invoke(\"Serial to message Buffer: \" + message);\n        }\n    }\n}<\/pre>\n\n\n\n<p>A double buffer (<em>_readBuffer <\/em>and <em>_writeBuffer<\/em>) is used to avoid message jams while waiting for responses.<\/p>\n\n\n\n<p>The <em>GSuit<\/em> class scans all available serial ports for the Arduino and sets up the other components.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">void InitSerialConnection()\n{\nbool found = false;\n\nwhile (found == false)\n{\n    string[] portNames = SerialPort.GetPortNames();\n\n    foreach (string portName in portNames)\n    {\n        try\n        {\n            SerialPort serialPort = new SerialPort();\n            serialPort.PortName = portName;\n            serialPort.BaudRate = 9600;\n            serialPort.DtrEnable = true;\n            serialPort.Open();\n\n            if (serialPort.IsOpen)\n            {\n                serialPort.Write(SerialProtocol.ChallengeMessage + \";\");\n\n                Thread.Sleep(500);\n\n                string response = serialPort.ReadExisting();\n\n                serialPort.Close();\n\n                if (response == (SerialProtocol.ResponseMessage + \";\\r\\n\"))\n                {\n                    _portWrapper = new SerialPortWrapper();\n                    _portWrapper.Init(portName);\n\n                    AsynchronousSocketListener._socketCallback += MessageBuffer.SocketCallback;\n                    MessageBuffer._writeToSerialPortCallback += _portWrapper.WriteSerialPort;\n                    MessageBuffer._debugPrintCallback += WriteDebugLine;\n                    MessageBuffer._serialReadCallback += _portWrapper.ReadSerialPort;\n                    _writeToSerialPortCallback = _portWrapper.WriteSerialPort;\n\n                    WriteDebugLine(\"GSuit found at \" + portName);\n\n                    found = true;\n\n                    break;\n                }\n            }\n        }\n        catch (Exception e)\n        {\n            Console.WriteLine(e.ToString());\n        }\n    }\n}<\/pre>\n\n\n\n<p>The Arduino is identified by sending a challenge message and waiting for the correct response message. Once a serial port responds correctly all other components are initialized. This function is also used when the SerialPortWrapper loses connection to find the Arduino again if it is reconnected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"dcsplugin\"><span class=\"ez-toc-section\" id=\"DCS_Plugin\"><\/span>DCS Plugin<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The <a href=\"https:\/\/github.com\/wrongway88\/gSuitDCSPlugin\" target=\"_blank\" rel=\"noreferrer noopener\">DCS plugin<\/a> is responsible for passing on the current G-Force experienced by the player&#8217;s aircraft, similar to aookami&#8217;s <a href=\"https:\/\/github.com\/aookami\/DCS-GSOUND\" target=\"_blank\" rel=\"noreferrer noopener\">DCS-GSOUND<\/a> plugin. It consists of only the <em>GSuit.lua<\/em> file.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function LuaExportStart()\n\tsocket = require(\"socket\")\n\t\n\thost = \"127.0.0.1\"\n\tport = 56182\n\t\n\tlastTime = os.clock()\nend\n\nfunction LuaExportAfterNextFrame()\n\tdelta = os.clock() - lastTime\n\t\n\tif delta >= 0.25 then\n\t\tconnection = socket.try(socket.connect(host, port))\n\t\tconnection:setoption(\"tcp-nodelay\",true)\n\t\n\t\tsocket.try(connection:send(string.format(\"%.3f&lt;EOF>\",LoGetAccelerationUnits().y)))\n\t\t\n\t\tlastTime = os.clock()\n\tend\nend\n\nfunction LuaExportStop()\n\tconnection = socket.try(socket.connect(host, port))\n\tconnection:setoption(\"tcp-nodelay\",true)\n\t\n\tsocket.try(connection:send(\"0.0&lt;EOF>\"))\n\n\tconnection:close()\nend<\/pre>\n\n\n\n<p><em>LuaExportStart<\/em> is executed once the player enters a mission. Here it only initializes some variables for the TCP connection and message timing.<\/p>\n\n\n\n<p><em>LuaExportAfterNextFrame<\/em> is executed each frame. To throttle the message frequency to 4 per second the time since the last message is calculated. If the last message was more than 0.25 seconds ago the function opens a socket connection to the G-Suit Server and sends the current y-acceleration (vertical acceleration) as a string.<\/p>\n\n\n\n<p><em>LuaExportStop<\/em> executes when the player exits a mission. It just sends a force of 0 to the G-Suit Server to make sure the leg-wraps deflate.<\/p>\n\n\n\n<p>To enable the G-Suit plugin this script has to be copied into DCS&#8217; scripts folder, typically <em>&#8216;C:\/Users\/Username\/Saved Games\/DCS.openbeta\/Scripts\/&#8217;<\/em>. In this folder there is a script called <em>Export.lua<\/em> to which the following line has to be added<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">local dcsGs=require('lfs');dofile(dcsGs.writedir()..[[Scripts\\GSuit.lua]])<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mce_0\"><span class=\"ez-toc-section\" id=\"Known_Issues_and_further_Development\"><\/span>Known Issues and further Development<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>After testing and using the G Suit during normal game play I can say in some regards it works as well or even better than I hoped. In some regards there is room for improvement as well.<\/p>\n\n\n\n<p>For very low g forces it works better than I thought. The sensation of changing pressure is perceivable even for very small changes. It is not easy however to judge the actual g load just from the pressure sensation. This might change over time though as I get more used to it.<\/p>\n\n\n\n<p>Given that pressure changes are easy to perceive the G Suit helps to maintain a desired g load once it is established.<\/p>\n\n\n\n<p>Even though it is hard to judge the actual force magnitude, the difference between low forces and high forces is pretty noticable. Therefore it is easier to notice accidentally burning energy in stress situations.<\/p>\n\n\n\n<p>I was worried that the pumps would be too slow for large and quick changes. This is far less an issue than I feared, but it could be better.<\/p>\n\n\n\n<p>The pumps and drivers I am using have limited power, so the maximum possible pressure is not very high. A higher maximum would allow to make different g load easier to distinguish by feeling.<br>On the other hand, the G Suit as it is cannot create nearly enough pressure to risk injuries. <\/p>\n\n\n\n<p>Trying to use more powerfull pumps should improve most of the issues mentioned. However this would make it necessary to mitigate the risk of accidentally turning the leg wraps into tourniquets.<\/p>\n\n\n\n<p>Lastly I want to mention that the pumps create a not insignificant amount of noise. I tend to play with headphones, so it does not bother me much. It is audible with headphones on though, and other people might not appreciate the noise in the living room.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mce_1\"><span class=\"ez-toc-section\" id=\"Acknowledgement\"><\/span>Acknowledgement<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Thanks to my father for <s>his riveting help<\/s> help with riveting the case (and many other things).<br>A big thanks to my aunt who helped with making the leg-wraps (read: made the leg-wraps while I pretended to help sewing)<br>Also thanks to my uncle for his advice with the electronics.<br>Once again, thanks to <a aria-label=\"Arduino (opens in a new tab)\" href=\"https:\/\/www.arduino.cc\/\" target=\"_blank\" rel=\"noreferrer noopener\">Arduino<\/a> for making programmable hardware that even an electronics-noob like me can use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mce_2\"><span class=\"ez-toc-section\" id=\"Resources\"><\/span>Resources<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul>\n<li><a href=\"https:\/\/learn.sparkfun.com\/tutorials\/serial-controlled-motor-driver-hookup-guide\">https:\/\/learn.sparkfun.com\/tutorials\/serial-controlled-motor-driver-hookup-guide<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.instructables.com\/Serial-Port-Programming-With-NET\/\">https:\/\/www.instructables.com\/Serial-Port-Programming-With-NET\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/network-programming\/asynchronous-server-socket-example\">https:\/\/docs.microsoft.com\/en-us\/dotnet\/framework\/network-programming\/asynchronous-server-socket-example<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/desktop\/winsock\/winsock-client-application\">https:\/\/docs.microsoft.com\/en-us\/windows\/desktop\/winsock\/winsock-client-application<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/aookami\/DCS-GSOUND\">https:\/\/github.com\/aookami\/DCS-GSOUND<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.arduino.cc\/resources\/pinouts\/A000057-full-pinout.pdf\">https:\/\/docs.arduino.cc\/resources\/pinouts\/A000057-full-pinout.pdf<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.instructables.com\/Arduino-Nano-Altimeter-Using-GY-BMP280\/\">https:\/\/www.instructables.com\/Arduino-Nano-Altimeter-Using-GY-BMP280\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>As a live-long aviation enthusiast I&#8217;ve been playing flight simulators since childhood. For about as long as that I had a fascination for associated computer peripheries, joysticks, pedals and such. Anything to improve the illusion of sitting in an actual cockpit. So anyways, here is my attempt at inflating my pants. Motivation If you are &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/manueldobusch.eu\/blog\/index.php\/2024\/05\/25\/dcs-g-suite\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;DCS G-Suit&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":291,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[3,6,7],"_links":{"self":[{"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/151"}],"collection":[{"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=151"}],"version-history":[{"count":124,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/151\/revisions"}],"predecessor-version":[{"id":369,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/posts\/151\/revisions\/369"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/media\/291"}],"wp:attachment":[{"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=151"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=151"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/manueldobusch.eu\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}