{"id":21531942,"url":"https://github.com/matrixai/inertial-orbit-detection","last_synced_at":"2025-03-17T19:27:58.426Z","repository":{"id":151338469,"uuid":"67536821","full_name":"MatrixAI/Inertial-Orbit-Detection","owner":"MatrixAI","description":"Building a Physical Analogue for Feedback Rich Systems","archived":false,"fork":false,"pushed_at":"2017-02-05T12:21:17.000Z","size":3462,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-24T06:29:45.583Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MatrixAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-09-06T18:44:29.000Z","updated_at":"2025-01-19T22:18:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"683aec45-f18a-4314-8f3e-559a1e526156","html_url":"https://github.com/MatrixAI/Inertial-Orbit-Detection","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MatrixAI%2FInertial-Orbit-Detection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MatrixAI%2FInertial-Orbit-Detection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MatrixAI%2FInertial-Orbit-Detection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MatrixAI%2FInertial-Orbit-Detection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MatrixAI","download_url":"https://codeload.github.com/MatrixAI/Inertial-Orbit-Detection/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244095995,"owners_count":20397320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-24T02:18:14.244Z","updated_at":"2025-03-17T19:27:58.410Z","avatar_url":"https://github.com/MatrixAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Inertial-Orbit-Detection\n\nThis project contains Arduino device code, Processing game code and Python server code implementing a game controller that uses inertial navigation to detect orbit around a rotational axis outside of the controller's body. This data is then used as a controller input to a flappy bird clone.\n\nSubmitted for Department of Engineering thesis \"Building a Physical Analogue for Feedback Rich Systems\" at Australian National University. The completed thesis is attached to this repository.\n\n---\n\n## Resources Used\n\n* http://www.dsfcode.com/using-processing-via-the-command-line/\n* http://eli.thegreenplace.net/2009/08/12/framing-in-serial-communications\n* https://github.com/firmata/protocol\n* https://docs.python.org/3/howto/sockets.html\n* https://en.wikipedia.org/wiki/Asynchronous_I/O#Polling\n* http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html\n* https://en.wikipedia.org/wiki/Keepalive\n* https://docs.python.org/3/library/_thread.html#module-_thread \u0026 http://www.dabeaz.com/python/UnderstandingGIL.pdf - that Python threads are actually pthreads limited by the GIL, which means context switches occur with `timer.sleep(0)`, IO operations, and a timer interrupt specified by the Python runtime.\n* For the event loop to work with have to deal with the possibility of partial reads and partial writes. In most cases, we should only care about partial reads, we'll make sure the write goes through before continuing (so we will have blocking writes). This is because writes are meant to be real time, so bad writes can just be dropped. But partial reads means we have to maintain a buffer, and the buffer pair algorithm is needed to in case we have read overflow, that is read more than enough for 1 message (this is to improve performance rather than to read 1 byte a time).\n    - http://compilerdesigndetails.blogspot.com.au/2012/02/buffering.html\n    - http://ecomputernotes.com/compiler-design/input-buffering\n    - http://www.slideshare.net/dattatraygandhmal/input-buffering\n* Relationship between rolling window increment and rolling window size actually gives rise to both latency and accuracy and efficiency tradeoff.\n* http://obogason.com/fundamental-frequency-estimation-and-machine-learning/\n* http://tkf.github.io/2010/10/03/estimate-frequency-using-numpy.html\n* https://gist.github.com/endolith/255291\n* http://exnumerus.blogspot.com.au/2010/04/how-to-fit-sine-wave-example-in-python.html\n* http://scipy-cookbook.readthedocs.io/items/FittingData.html\n\nPolling vs Busy Waiting:\n\n\u003e The difference between the two is what the application does between polls.\n\u003e\n\u003e If a program polls a device say every second, and does something else in the mean time if no data is available (including possibly just sleeping, leaving the CPU available for others), it's polling.\n\u003e  If the program continuously polls the device (or resource or whatever) without doing anything in between checks, it's called a busy-wait.\n\u003e  \n\u003e  This isn't directly related to synchronization. A program that blocks on a condition variable (that should signal when a device or resource is available) is neither polling nor busy-waiting. That's more like event-driven/interrupt-driven I/O.\n\u003e   (But for example a thread that loops around a try_lock is a form of polling, and possibly busy-waiting if the loop is tight.)\n\u003e http://stackoverflow.com/a/10594529/582917\n\nSine wave characteristics:\n\n```\nl = lambda\nv = phase velocity\nf = frequency\nT = period\n\n     v\nl = ---\n     f\n\n     v\nf = ---\n     l\n\n     1\nf = ---\n     T\n\n     l\nv = ---\n     T\n```\n\nA phase offset is an instantaneous position on a single waveform cycle. A 0 degree or 360 degree phase offset is equivalent to the starting point of a wave. 180 degrees is in the middle of the wave. 90 degrees is the crest and 270 degrees is trough of the wave.\n\nPhase velocity = Wavelength divided by Period. Period is the time it takes to go from 1 crest to another crest, so basically start to a finish of a wave cycle. Frequency is the number of cycles per second.\n\nWhen the wavelength and period is the same, then the phase velocity is 1. Wavelength is measured in meters, while period is measured in seconds.\n\n\u003e Wavelength is given by the distance between two successive peaks/troughs in a displacement vs. position graph.\n\u003e Period is given by the distance between two successive peaks in a displacement vs. time graph.\n\nIn an accelerometer graph representing orbital motion, assuming 40 Revolutions per Minute = 2/3 Revolutions per Second, would mean that 1 revolution takes 1.5 seconds. This should show up as 0.6666... Hz on the graph and 1500 milliseconds as the period. The wavelength doesn't matter because we don't actually care about the distance travelled in our orbit controller, only the direction and frequency.\n\n![](http://www.sengpielaudio.com/WavesSinusodialTimeDistance.gif)\n\n---\n\n## How we discovered the rotation direction model\n\n\u003ca title=\"View with the Desmos Graphing Calculator\" href=\"https://www.desmos.com/calculator/i2y7fz5v1s\"\u003e  \u003cimg src=\"https://s3.amazonaws.com/calc_thumbs/production/i2y7fz5v1s.png\" width=\"394px\" height=\"394px\"     style=\"border:1px solid #ccc; border-radius:5px\"  /\u003e\u003c/a\u003e\n\nThe data is:\n\n```\n2.8697358266694493, 10.153302161258436\n6.460969159839447, 6.9903282338783743\n9.0304916052962074, 2.6756155308647633\n10.17839883866681, -2.1005916224136736\n9.7260377925625967, -6.5742215226332306\n7.7438110971825962, -10.029607133544683\n4.5402200574177174, -11.913974615019903\n0.6138514486397435, -11.925873082486047\n-3.4242193954793008, -10.063399083682736\n-6.945532507391289, -6.6245011026244169\n-9.4020528452473773, -2.1593153778824958\n-10.411463022501062, 2.6178419076657491\n-9.8166647831462441, 6.9427470536936493\n-7.710228786944179, 10.123525203104277\n-4.4199874937304147, 11.651332727361739\n-0.45801337974073675, 11.28175926905354\n3.5590768042977032, 9.0739271846290865\n7.0060883889102223, 5.3810334706297853\n9.3465501549839978, 0.79384722473040692\n10.216207342675848, -3.9537983888284671\n9.4797119729492003, -8.1024007868643704\n7.2516875563932324, -10.988289069235661\n3.8788898104229705, -12.149794488179921\n-0.11376022127295496, -11.401105709432661\n-4.1048715809279983, -8.8619939012201083\n-7.4732927800225823, -4.9386523926766221\n-9.6947839131178366, -0.25871606917244694\n-10.423606061975299, 4.4291442509233274\n-9.5463299278775207, 8.3749901112657117\n-7.1994892547951954, 10.94758650239859\n-3.748331575569114, 11.735383413308186\n0.27002661858099841, 10.612353368997487\n4.2301933130557616, 7.7581526220746717\n7.5158330525412218, 3.6293807203281379\n9.6155895177045974, -1.1134638112923769\n10.202669808941147, -5.7116464406409646\n9.1857044394286813, -9.4295748617208428\n6.7229675078132738, -11.672475060265134\n3.1977439122238325, -12.081540033124751\n-0.84132270238858831, -10.591329785644493\n-4.7656173930128665, -7.4402400669121853\n-7.9643875975658416, -3.1323651114207935\n-9.939796825169525, 1.6431446212044598\n-10.384404798770509, 6.1223289972115298\n-9.2290155276478583, 9.5886324054563126\n-6.653446536522142, 11.487534435835212\n-3.0585431961332685, 11.515259045510792\n0.9962063310136845, 9.6673710018687764\n4.8797463119656141, 6.2394854069648282\n7.9876669915144571, 1.7799767975899237\n9.8362711278805879, -2.9977468374907192\n10.137853591460548, -7.3293711964237973\n8.845477983020773, -10.521946518892491\n6.1602815198844656, -12.064741928630792\n2.5001713035439228, -11.710949387634868\n-1.5652161151366459, -9.517166706834729\n-5.4031693886240948, -5.8343433354154559\n-8.4163735903550467, -1.2516373722899143\n-10.135872555878583, 3.4978347496269047\n-10.294054272976654, 7.6542782522569279\n-8.866300333346933, 10.552767858094485\n-6.0748173869486362, 11.729618928026229\n-2.3540542955345503, 10.996565213813398\n```\n\nAcquiring acceleration delta between T1 and T2.\n\n```\nc\\ =\\ \\left(-\\frac{\\left(U\\left[T_2\\right]-U\\left[T_1\\right]\\right)}{\\left(E\\left[T_2\\right]-E\\left[T_1\\right]\\right)}\\right)E\\left[T_1\\right]+U\\left[T_1\\right]\ny=\\left(\\frac{\\left(U\\left[T_2\\right]-U\\left[T_1\\right]\\right)}{\\left(E\\left[T_2\\right]-E\\left[T_1\\right]\\right)}\\right)x+c\n```\n\nNote whether East acceleration is Positive/Negative and Increasing/Decreasing.\n\n```\ny=U\\left[T_1\\right]\\left\\{\\left\\{E\\left[T_1\\right]\\ge E\\left[T_2\\right]:\\ E\\left[T_1\\right],E\\left[T_2\\right]\\right\\}\\ge x\\ge \\left\\{E\\left[T_1\\right]\\ge E\\left[T_2\\right]:E\\left[T_2\\right],E\\left[T_1\\right]\\right\\}\\right\\}\n```\n\nNote whether Up acceleration is Positive/Negative and Increasing/Decreasing.\n\n```\nx=E\\left[T_2\\right]\\left\\{\\left\\{U\\left[T_1\\right]\\ge U\\left[T_2\\right]:\\ U\\left[T_1\\right],U\\left[T_2\\right]\\right\\}\\ge y\\ge \\left\\{U\\left[T_1\\right]\\ge U\\left[T_2\\right]:U\\left[T_2\\right],U\\left[T_1\\right]\\right\\}\\right\\}\n```\n\nConsider the resultant change in acceleration (delta) between T1 and T2.\n\nThe opposite direction of the resultant change in acceleration is the actual rotational tangent direction.\n\nThe combination of the rotational tangent direction and the displacement position at the circle is what tells us whether we are rotating clockwise or anticlockwise.\n\n---\n\n## Future Improvements\n\n0. Service discovery between the game client and server (OS-specific)\n1. Autobuilding the processing application via command line\n2. Custom IDing of the USB controller\n3. Udev script to autostart game upon plugging the controller (using mdns for service discovery, and python-avahi for the game code)\n4. Packaging up the game to be deployable\n5. Detailing controller manufacturing\n6. In the future, the server should be resilient to device plugins and unplugs. Detect both of these and continue running. When unplugging, it should signal game to reset (or close the game), and then restart from the beginning. It should also deal with when the device stops answering, and attempt to reset the game controller until it works, or after a few retries, indicate that the device is broken, and signal the game to exit, and close itself. The server itself should be starting the game, so the game should be a child process of the parent process.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatrixai%2Finertial-orbit-detection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatrixai%2Finertial-orbit-detection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatrixai%2Finertial-orbit-detection/lists"}