1. Do not share user accounts! Any account that is shared by another person will be blocked and closed. This means: we will close not only the account that is shared, but also the main account of the user who uses another person's account. We have the ability to detect account sharing, so please do not try to cheat the system. This action will take place on 04/18/2023. Read all forum rules.
    Dismiss Notice
  2. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Now a Download Plan!
  3. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  4. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant. Do not follow these rules can lead to permanent exclusion from this website: Read the forum rules.
    Are you a company? Read our company rules

Writing a motion cueing software from scratch.

Discussion in 'DIY Motion Simulator Projects' started by Dirty, Feb 28, 2019.

  1. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    Tilt coordination

    Here’s a concrete example: Let’s briefly go over what happens with the platform when your vehicle starts to accelerate:

    Forget these block diagrams with their fancy notation, greek letters and hieroglyghic layout!

    Basic_scheme_of_a_motion_cueing_algorithm.png

    Rather, try to get an intuitive understanding of what’s going on by understanding this diagram:

    Step - Tilt coordination.png

    The blue dotted line is the vehicles longitudinal acceleration. First it’s zero. Vehicle standing still. Then the driver steps on the gas or the pilot slams the thrust levers forward and the acceleration is present instantly. I know that in real life it is not gonna be present instantaneously, but this is a test case. It won’t get any trickier than that.:thumbs

    Now the platform reacts in two different ways:
    1. The Surge DOF will make a jolt forward and then softly return to center.
    2. The Pitch DOF will tilt the platform back to make the occupant feel being pressed back into their seat.
    Bildschirmfoto 2019-05-21 um 14.13.13.png

    These two go hand in hand! They belong together like chocolate and brownies. Still there is a key difference:
    • In the Surge DOF we move the platform forward and we actually want the occupant to feel the forward motion. —> The motion itself shall be perceivable.
    • In the Pitch DOF we rotate the platform nose-up, but we don’t want the occupant to feel this rotation. —> The motion itself shall not be perceivable!
    Being IN that tilted position is totally fine, it’s just the „getting there“ that we want to conceal! The rotation itself is a false cue! We need to mitigate those.

    From this diagram I think it’s obvious that we should take the (green) low pass filtered signal to drive the pitch DOF and the (orange) high pass filtered signal to drive the surge DOF. Exactly which order of filter will become clear later in this post.



    Human perception:

    I will stay intentionally vague on this as it is not my area of deepest expertise, but at least you should be aware, that in general humans perceive changes of a value a lot better than the constant value itself.

    Example:
    If I could alter gravity and dial up the Earth’s accceleration from 1.0 to 1.05 G (5% increase) )over let’s say 120 seconds, you would probably not even notice it. You would maybe wonder why you all of a sudden felt so weak.
    But if I were to flip a switch and changed it in a single step from 1.0 to 1.01 (only 1% increase) you’d feel it in an instance.

    Similarly, I guess you will not be able to estimate the temperature of a bowl of water to within a few degrees C° when you put your hand in it. But if I had two bowls (20°C and 20.5°C), and you put your hands in one, and then in the other, you would immediately notice the difference.

    You might wanna google „phasic receptor“ and „tonic receptor“

    Bildschirmfoto 2019-05-21 um 14.56.06.png



    Applied to motion cueing:

    SURGE: In the vehicle the longitudinal acceleration is present instantaneously (that’s the test case), so let’s show the occupant that by using a filter that…
    1. Gives him the acceleration immediately.
    2. --> Has curvature immediately. Remember, that’s acceleration.
    3. --> Provides tangency, but no curvature continuity.
    That would be a high pass filtered signal that is then smoothened out by a 2nd order LP filter to give us G1 Continuity.


    PITCH: Since the surge DOF has already provided the occupant with 100-500ms of acceleration fun, we have a little time to rotate the platform nose-up. Let’s invest that time into a smoothened-out motion during rotation. We need a filter that…
    1. Achieves the desired rotation with cues that are as little perceivable as possible.
    2. —> May not have abrupt changes in curvature. Those are easiest to perceive.
    3. —> Must provide curvature continuity on the signal.
    That would be a 3rd order low pass filter, which gives us G2 continuity.

    Bildschirmfoto 2019-05-21 um 14.13.21.png


    This is how I intend to process longitudinal and lateral vehicle accelerations to drive DOFs in my software for now. The roll channel from the hieroglyph is being approached with the same "toolset". As with everything, that is until I get (or are being told) a better idea :)

    Eventually the coordination channel is mixed in with the angular rates channel.
    Accel.lon -->Pitch channel
    Accel.lat --> Roll channel

    Cheers, Dirty :)




    Notes:
    If you do want to take a look a the hieroglyphs, these are the paths I described in this post:
    Basic_scheme_of_a_motion_cueing_algorithm 2.png
    The „1/s^2“ in the translational channel is a double integration, which makes total sense if…

    • you use a „1-EMA“ as HP filter
    …and…
    • live in Math-Land where they wouldn’t drift.
    …then the top row would be quasi equivalent to a HP filter followed by a 2nd order LP filter.

    ...thanks a lot to @harwoodr for helping/confirming/puzzling me in just the right amount :thumbs

    • Like Like x 1
    • Agree Agree x 1
    Last edited: Apr 13, 2020
  2. hexpod

    hexpod http://heXpod.xyz

    Joined:
    Apr 18, 2016
    Messages:
    1,185
    Location:
    berlin
    Balance:
    7,636Coins
    Ratings:
    +369 / 5 / -0
    My Motion Simulator:
    DC motor, 6DOF
    Again @Dirty is going to the point.

    Finally we have demystified the "classic washout" approach.

    The need of second and third order of a simple EMA smoothing filter seems now obvious !

    I could implement and experiment myself with the EMAx3 behavior in heXpod and I confirm, it adds an very much needed entry ramp curve. Btw. @yobuddy just successfully added it in SimTools 2.4beta.

    @pmvcda , remember ? we started disscussing together this topic on 9th april.

    You should also go for it to make out of FLYpt a complete solution.
  3. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    Hey :)

    Thank you, for the kind words!

    Did you get it implemented already? Man, you're fast! It was Friday afternoon when we drew those sketches on a shaky table in a café in Berlin, and you have it implemented on Sunday??? Is there a difference noticeable?

    Indeed, the "washout" I implemented is a combination of a highpass filter followed by a 1/2/3 order lowpass filter. The behaviour of the filter-system as a whole can be changed by using different HP and LP filters to get the desired behaviour. What gives me confidence that this is a good approach, is the fact that I came up with this as a result of a few logical deductions and the fact that it matches with what I see on plenty (not all) of the block diagrams on MCAs out there.

    But if there is another approach to this, I am totally open for ideas 'cos so far, all I have is an Excel sheet with plenty of colourful graphs...
    I wonder particularly why I see those integrations and double integrations so often, when afaict those will drift over time with even the slightest of errors in the measurements!?!

    Dirty :)
    • Agree Agree x 1
    Last edited: May 26, 2019
  4. pmvcda

    pmvcda aka FlyPT

    Joined:
    Nov 3, 2010
    Messages:
    2,158
    Location:
    Portugal
    Balance:
    15,264Coins
    Ratings:
    +2,532 / 17 / -0
    My Motion Simulator:
    6DOF
    Yes, I think I will put them in the new program.
    Current washout is already an EMALP(EMAHP).
    I always looked at the curve "S" as a reaction lag... But @Dirty explanation made me look at it in a different way.
    We don't want to feel the rotation made to simulate a surge generate force...
  5. hexpod

    hexpod http://heXpod.xyz

    Joined:
    Apr 18, 2016
    Messages:
    1,185
    Location:
    berlin
    Balance:
    7,636Coins
    Ratings:
    +369 / 5 / -0
    My Motion Simulator:
    DC motor, 6DOF
    Cool,

    Understand that you don’t have time to support FLYpt anymore being busy by the new project.

    Only to say, that it’s really easy if you avoid the mistake trying to use the filter to filter its own value again. It can’t work

    Putting the values of the signal into the filter, in the correct order, (several different objects of the same math in a row) exactly once per sample is the correct way.

    Cheers
    • Agree Agree x 1
  6. hexpod

    hexpod http://heXpod.xyz

    Joined:
    Apr 18, 2016
    Messages:
    1,185
    Location:
    berlin
    Balance:
    7,636Coins
    Ratings:
    +369 / 5 / -0
    My Motion Simulator:
    DC motor, 6DOF
    Tilt coordination:
    Pitch:
    - “Third order” EMA Low Pass (“S2 curve” smoothing)

    Surge:
    - “Second order” EMA Low Pass (“S1 curve” smoothing)
    - “Third order” EMA High Pass (“S2 curve” washout)

    0BB0B4FC-512E-4034-B45C-DA9167F59DD0.jpeg

    With a bit of luck, we will be able soon to construct this inside the SimTools matrix as well. ;-)



    Cheers
    • Like Like x 3
    • Winner Winner x 1
    Last edited: May 29, 2019
  7. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    That looks even better then the videos you sent me earlier!

    I'm impressed! That's what it's supposed to look like!
  8. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    Just a quick Update:

    I put the project on GitHub: https://github.com/Dirt-e/Nutkicker_Motion_Controller

    Here's a synoptic representation of the data flow in the software.
    Processing_flowchart.PNG

    I left plenty of space, because there is still a to to be added.

    Certainly a lot clearer than the representation I had before:
    processing_hierachy.PNG

    Dirty :)
    • Like Like x 2
    • Winner Winner x 2
  9. Trip Rodriguez

    Trip Rodriguez VR Pilot

    Joined:
    May 8, 2016
    Messages:
    675
    Location:
    Lake Ariel, Pennsylvania
    Balance:
    3,922Coins
    Ratings:
    +330 / 6 / -0
    My Motion Simulator:
    6DOF
    Greetings friends! I just wanted to say hello and let you all know that I have spoken with Dirty and I will be taking on the job of breaking, oops I mean testing, his software!

    I will also be installing HeXpod @hexpod in the next few days and beginning testing on both these programs as soon as the sim is running. There's so much to do and never enough time! If I stop hitting delays my simulator Mk. 2 mods should be finished and sim fully reassembled in less than a week. It should be operable by this weekend, after that I think it's really just cosmetic appearance work. I will post an update in the showroom when it's all prettied up. =) I think you will all agree that the main change I made is shocking!
    Last edited: May 30, 2019
  10. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    Hey there :)

    please, keep in mind though, that at this stage you can only look at the program and not really use it for actual motion :) Sorry, I didn't specifically mention that. I will have to put it in the readme of the Github page.

    If you want to see what the program outputs you can connect an Arduino to listen to the serial port. Also "Com0Com" with a Serial reader will show you the output.

    It is all pretty rudimentary still. You will only see something like... <float,float,float,float,float,float> 50 times/second.
    Those floats represent the position ot the actuators between min and max.

    I eventually want to suport the AMC1280. @Thanos , is there any documentation about the serial communication?
    Last edited: Jun 27, 2019
  11. pmvcda

    pmvcda aka FlyPT

    Joined:
    Nov 3, 2010
    Messages:
    2,158
    Location:
    Portugal
    Balance:
    15,264Coins
    Ratings:
    +2,532 / 17 / -0
    My Motion Simulator:
    6DOF

    For the AMC1280, you have to send 20 bytes:

    <255><255><Axis1a><Axis2a><Axis3a><Axis4a><Axis5a><Axis6a><0><0><0><0><10><13>

    All numbers inside <> is the value of the byte
    Axis1a to Axis6a are the axis values in 16 bit format, so 2 bytes for each (0 to 65535).
    The order depends on how you are calculating the rig.
    But I think Thanos uses:

    [​IMG]

    I think those last zeros are for other axis.
    • Informative Informative x 2
    • Agree Agree x 1
    Last edited: May 30, 2019
  12. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    Thanks a lot, @pmvcda and @Thanos!

    So, just twenty bytes in the format...
    <byte><byte><bytebyte><bytebyte><bytebyte><bytebyte><bytebyte><bytebyte><byte><byte><byte><byte><byte><byte> ?

    I hope you don't mind the silly question, but do I send a string and the angular brackets are part of the message? Or can I send an array of bytes?

    Like so...
    Code:
    SerialPort serialport = new SerialPort("COM6",9600);
    
    byte[] messsage = {255, 255, 23, 125, 45, 85, 35, 112, 101, 43, 82, 99, 34, 54, 0, 0, 0, 0, 10, 13 };
    
    serialport.Write(messsage, 0, 20);
    
    ...just to illustrate an example.

    So basically I have to calculate a number between 0 and 65535 that "represents" the travel of the actuator between min and max, right? Then convert that into a binary representation, chop this binary up into two parts that are 8 bits each, and then transmit each of those 8bit-chunks as a single byte?

    Example:
    - One of the actuators is at 56% travel.
    - Means it's at position 39321 of 65535.
    - Which is 1000111101011100 in binary
    - Broken up into 10001111 and 01011100.
    - Transmitted as 143 and 92

    So, the message could be...
    Code:
    byte[] messsage = {255, 255, 143, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 13 };
    
    Did I understand correctly?
    • Agree Agree x 1
    Last edited: May 31, 2019
  13. pmvcda

    pmvcda aka FlyPT

    Joined:
    Nov 3, 2010
    Messages:
    2,158
    Location:
    Portugal
    Balance:
    15,264Coins
    Ratings:
    +2,532 / 17 / -0
    My Motion Simulator:
    6DOF
    I'm on the phone arghh
    But that's right
    Send the bytes not the brackets
  14. Thanos

    Thanos Building the Future one AC Servo at a time... or 6

    Joined:
    Jul 6, 2017
    Messages:
    1,358
    Occupation:
    Electronics Engineer
    Location:
    United States
    Balance:
    2,773Coins
    Ratings:
    +1,051 / 9 / -0
    My Motion Simulator:
    AC motor, Motion platform, 4DOF, 6DOF
    That is correct. The 16bit values are transmitted with MSB first. See examples for positions of 0% , 15%, 50%, 85% and 100% ...

    The "#" in the strings are used as indicators to separate the bytes in my examples values! Do not use the # in your code... ;)
    Code:
    #255#255#000#001#000#001#000#001#000#001#000#001#000#001#000#000#000#000#010#013
    #255#255#064#000#064#000#064#000#064#000#064#000#064#000#000#000#000#000#010#013
    #255#255#128#000#128#000#128#000#128#000#128#000#128#000#000#000#000#000#010#013
    #255#255#192#000#192#000#192#000#192#000#192#000#192#000#000#000#000#000#010#013
    #255#255#255#255#255#255#255#255#255#255#255#255#255#255#000#000#000#000#010#013
  15. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    OK, I think before I bug you with further questions (which I surely will), I will have to learn a little "bit" about bits and bytes :) I have only a very general concept of it, because I have never actually done anything in code on byte-level. Always used higher level abstractions.

    I can certainly see the point in using bytes here, because you get a rather high information density in the message. The way I did it (by sending strings containing the values), I had to use a message of ~55bytes to get values with 5 digits behind the decimal. And I only transmitted the 6 values, absolutely no extras!!

    Your method is a lot quicker for sure.

    Thanks!
    Last edited: May 31, 2019
  16. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    I played around with different filters a little more, because I wanted to better understand which "dials" allowed me to change the filter in which way.

    If you haven't understood what I meant by "tangency" and "curvature continuity", maybe these picture can illustrate:
    Bildschirmfoto 2019-05-31 um 21.24.08.png

    You can see two straight lines connected by a radius (magenta). The curvature of that radius is indicated by the blue "curvature comb" and the red "hull curve". As you can see, the radius is tangential to the two straight lines. But the curvature pops up out of nowhere. The line has zero curvature, the radius has full curvature, and then the next line has zero curvature again. The curvature comb (representing acceleration!) starts and ends very abruptly. This is the step response you want in surge, because when the input (acceleration) makes a "step up", this comb should also "step up".

    On the other hand, here are two similar lines, but they are connected by "G2 continuity".
    Bildschirmfoto 2019-05-31 um 21.28.31.png
    They too have a curvature-comb but it does not pop up out of nowhere. It gradually builds and then gradually disappears. Curvature (aka. acceleration) sets on smoothly and goes away smoothly. This profile has a much higher chance of going undetected. This is what you want to use for Tilt coordination, because you don't wanna feel the pitch come and go, you just want to feel it being there. :)

    These curvature combs allow for something else: They can tell you where the graph changes direction. I think the English term would be "infliction points". Those are important, because you wanna make sure that by the time the surge reverses acceleration you have built up a noticeable amount of tilt to take over the job of keeping the illusion "alive". I have modelled the highpass signal for the surge channel in CAD with and without the curvature comb:
    Bildschirmfoto 2019-05-31 um 21.19.15.png Bildschirmfoto 2019-05-31 um 21.20.11.png

    Here it becomes apparent that at some point (before the "peak travel"!) the curvature reverses and thus the acceleration reverses. You want to check where that point lies and tune your filters in a way that by the time this happens you have reached a sufficient tilt angle. This adverse curvature is false cueing and the only way to mitigate it is to try to spread it out over the course of a few seconds to make it "stand out" less.

    To apply this to my filters: Tilt coordination.png

    At roundabout t = 2.3 seconds the orange (surge) reverses curvature (acceleration) and thereby loses effectiveness. By that time the green (tilt) has reached ~50% of its tilt and generates sufficient cues for the occupant to still feel being pushed back into it's seat. As the adverse curvature of the surge inevitably builds up, the false cues coming from this adverse curvature are being compensated for by the proverse cues now coming from the tilt. You may have to imagine the curvature combs in this picture to see the point.

    After playing back and forth with the filter variables in Excel, I noticed that I was most probably wrong back then when I said that I think it makes sense to use a frequency splitter to have one signal as the "complement" to the other. It appears those curves turn out nicer when the HP and LP signals keep a little "overlap". I mean that the LP signal keeps a little bit of the higher frequencies and the HP signal keeps a little bit of the lower frequencies.

    I can't tell you why, but those curves turned out nicer after I tuned them with an overlap in their frequency composition *scratching head*

    Dirty :)
    Last edited: Jun 4, 2019
  17. Thanos

    Thanos Building the Future one AC Servo at a time... or 6

    Joined:
    Jul 6, 2017
    Messages:
    1,358
    Occupation:
    Electronics Engineer
    Location:
    United States
    Balance:
    2,773Coins
    Ratings:
    +1,051 / 9 / -0
    My Motion Simulator:
    AC motor, Motion platform, 4DOF, 6DOF
    Yes sending 8 axis information, in less than 1ms period, thanks to 250k baud speed, and it includes some markers for start-end of the packets. This way the AMC can offer as much as 1000 positions per second, that is fast enough to accommodate even vibrations up to 100hz with fast servomotors... ;)
    • Useful Useful x 1
  18. Trip Rodriguez

    Trip Rodriguez VR Pilot

    Joined:
    May 8, 2016
    Messages:
    675
    Location:
    Lake Ariel, Pennsylvania
    Balance:
    3,922Coins
    Ratings:
    +330 / 6 / -0
    My Motion Simulator:
    6DOF
    This sounds exactly right, but I think that for flight sim you kinda want this on all 6DOF. I can tell you for sure that on my sim all three translational and all three rotational axes have an "abruptness" that drives me nuts and I just can't get rid of without slowing the sim to a crawl by reducing "P" (PID) to a super low value.

    In my experience the harsh movements you are trying to eliminate (thank you, thank you, thank you!) are actually worse on translations than rotations. Heave in particular is really bad.

    Side Note: I tried using curve settings in the VFD's to fix this and it basically didn't seem to make any difference. Probably not useful information but I wanted to mention it.
  19. Dirty

    Dirty Well-Known Member Gold Contributor

    Joined:
    Oct 15, 2017
    Messages:
    744
    Occupation:
    All the way up front.
    Location:
    Germany
    Balance:
    7,909Coins
    Ratings:
    +878 / 3 / -0
    That's interesting feedback actually. Like I said: so far I am talking about a few colourful graphs in Excel :)

    What I describe is the" test case" of putting the system through a step input of longitudinal acceleration. In (simulated) reality you will of course never have accelerations that set on so abruptly. Engines spool up gradually, brakes deploy gradually, flight control surfaces extend gradually,... Cars are probably a bit more likely to have quicker load changes.
    The question in these considerations was: How should the system react to such a hypothetical step input to represent the changing accelerations as good as possible while...
    1. ...staying within it's physical constraints and
    2. ...avoiding/mitigating false cues

    I guess I will add a 3-view to the software to see the platform from the side, back and top to better judge the motion, like the videos that @hexpod published. I think it does allow to get a general idea of what the motion on the platform is going to be like. I don't know how to describe it properly, but sometimes I "just see" that something is "off" and sometimes I "just see" that something "looks right".


    ...and I guess I will have to add a "Minimise me" button to reduce the graphical representation to a minimum if I want to keep up with these speeds :) So far I am running at ~250fps (4ms) and there is still more to come that will slow things down further. Up until now I have been rigorously following the first rule of optimisation: Don't optimise! :):):)
  20. Trip Rodriguez

    Trip Rodriguez VR Pilot

    Joined:
    May 8, 2016
    Messages:
    675
    Location:
    Lake Ariel, Pennsylvania
    Balance:
    3,922Coins
    Ratings:
    +330 / 6 / -0
    My Motion Simulator:
    6DOF
    This may not be much help, but just FYI the suddenness/harshness at the beginning of a cue that I find bothersome is not generally visible when watching the real simulator be flown. I mention this because it's possible that may be the case with the simulated...simulator........ as well. That's a bit of a strange phrase LOL. In the coming weeks I will compare your graphical simulation to HexPod's, then compareHexPod's to the real simulator and see if the abrupt movements I feel on the real sim seem visible in the software. In the end though, what you really need is true practical tests on a real simulator. Your butt feels a lot more than your eyes see!
    • Agree Agree x 1
    Last edited: Jun 1, 2019