{"action":"created","issue":{"url":"https://api.github.com/repos/ev3dev/ev3dev/issues/324","labels_url":"https://api.github.com/repos/ev3dev/ev3dev/issues/324/labels{/name}","comments_url":"https://api.github.com/repos/ev3dev/ev3dev/issues/324/comments","events_url":"https://api.github.com/repos/ev3dev/ev3dev/issues/324/events","html_url":"https://github.com/ev3dev/ev3dev/issues/324","id":75232146,"number":324,"title":"Tips to get a more constant loop time","user":{"login":"laurensvalk","id":12326241,"avatar_url":"https://avatars.githubusercontent.com/u/12326241?v=3","gravatar_id":"","url":"https://api.github.com/users/laurensvalk","html_url":"https://github.com/laurensvalk","followers_url":"https://api.github.com/users/laurensvalk/followers","following_url":"https://api.github.com/users/laurensvalk/following{/other_user}","gists_url":"https://api.github.com/users/laurensvalk/gists{/gist_id}","starred_url":"https://api.github.com/users/laurensvalk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/laurensvalk/subscriptions","organizations_url":"https://api.github.com/users/laurensvalk/orgs","repos_url":"https://api.github.com/users/laurensvalk/repos","events_url":"https://api.github.com/users/laurensvalk/events{/privacy}","received_events_url":"https://api.github.com/users/laurensvalk/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-05-11T13:57:33Z","updated_at":"2015-05-12T08:59:15Z","closed_at":null,"body":"For a balancing robot project I am running a control loop that repeats indefinitely. We would like to have an approximately constant loop time in the order of several milliseconds.\r\n\r\nWe know Linux is not a real time OS, but we would like to ask the Linux experts around here for some pointers to things we can do to improve the consistency of the loop time. As discussed below, we have more than 50% idle time, but the challenge is to allocate it properly.\r\n\r\nFirst, some background information. The control loop will read sensors (1x gyro, 2x encoder), do some calculations, and set the duty cycle of two tacho motors. For the moment we are skipping the calculation step. \r\n\r\nEverything is timed with the get_clock c function. (An external stopwatch was used to verify that the logged times and overall time actually make sense.) In the following, let's assume we would like a loop time as close as possible to 3ms.\r\n\r\nIf we cut out all the waiting loops and usleeps, we can run the loop that reads the sensors and sets the motor duty cycles 10,000 times in under 10 seconds. This is even with all the background processes running, so the control loop itself needs less than 1 ms to run. On average, the system can be idle for 2 ms.\r\n\r\nFor a very simple experiment, the timing is recorded as follows:\r\n\r\nThe loop begins by logging the current time. Then it reads sensors and sets motors. If it has run in under 3 ms, it reads the clock every 10 microseconds to wait until the 3ms loop time has elapsed. Then the loop runs again.\r\n\r\nIf a loop takes longer than 3ms, it will still finish the loop and then wait until the nearest multiple of 3ms before starting another loop.\r\n\r\nThe intervals (the difference between two subsequent logged time values) are plotted in the figure below, against the actual time. Most intervals are pretty close to the desired 3ms loop time. The 'negative' peaks occur directly after a 'positive peak'. For example, if a loop needs 4 ms, it will do the next one in 2ms, if possible.\r\n\r\n![looptime2](https://cloud.githubusercontent.com/assets/12326241/7565302/3d429bd0-f7ef-11e4-9ff9-5292460823c7.png)\r\n(Update: The vertical label should read seconds: 0.003 s = 3ms. Update 2: The above plot does not correspond exactly to the above timing description [so don't bother to try and understand it exactly], but the issues with the delays hold in any case.)\r\n\r\nThree types of delays appear to stand out as marked in the figure. Peak type 1 and 2 might be caused by another running process. I haven't yet found which ones these may be. Peak type 1 is the most serious. Peak type 3 occurs the most frequently. What would be a good way to identify the processes related to these delays?\r\n\r\nWe would like to ask for some tips to improve this behaviour. Here are some things that I imagine are possible, but I'm not sure if they're practical or even possible. If they are, which one is likely to give the best results? Please feel free to add more ideas as well.\r\n\r\n- Identify some parallel processes and reduce their priority or even delay them if they're not critical to the robot balancing.\r\n- Increase the priority of this process. (I experimented a bit with the niceness, but the results so far did not improve much.)\r\n- Use an interrupt with a timer instead of a continuous loop\r\n- Use something like the RT-Preempt patch\r\n- Don't use EV3 or Linux for near real time applications. (I'm hoping this is not the answer, but do say so if you think it is.)\r\n\r\nI'm steadily learning Linux and willing to learn more, but I'm new to this type of problem. I hope some experts around here can help.\r\n\r\nThanks!"},"comment":{"url":"https://api.github.com/repos/ev3dev/ev3dev/issues/comments/101200936","html_url":"https://github.com/ev3dev/ev3dev/issues/324#issuecomment-101200936","issue_url":"https://api.github.com/repos/ev3dev/ev3dev/issues/324","id":101200936,"user":{"login":"laurensvalk","id":12326241,"avatar_url":"https://avatars.githubusercontent.com/u/12326241?v=3","gravatar_id":"","url":"https://api.github.com/users/laurensvalk","html_url":"https://github.com/laurensvalk","followers_url":"https://api.github.com/users/laurensvalk/followers","following_url":"https://api.github.com/users/laurensvalk/following{/other_user}","gists_url":"https://api.github.com/users/laurensvalk/gists{/gist_id}","starred_url":"https://api.github.com/users/laurensvalk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/laurensvalk/subscriptions","organizations_url":"https://api.github.com/users/laurensvalk/orgs","repos_url":"https://api.github.com/users/laurensvalk/repos","events_url":"https://api.github.com/users/laurensvalk/events{/privacy}","received_events_url":"https://api.github.com/users/laurensvalk/received_events","type":"User","site_admin":false},"created_at":"2015-05-12T08:59:15Z","updated_at":"2015-05-12T08:59:15Z","body":"Thanks for your detailed response. I'll further investigate the topics you mention here.\r\n\r\nAnother option is to account for the varying loop time in our code. This will work for some applications, but it will significantly complicate some algorithms and their theoretical stability properties (or even destabilize the system.)\r\n\r\nWhile yesterday's post concerned mostly timing, I'll add some more plots to show the implications on measurements. Here is a plot of the gyro value of a segway type of robot freely swinging, in upside down orientation. (We do this to get a first estimate on the body inertia, which can approximately be found from the free swinging frequency.)\r\n\r\n![swing](https://cloud.githubusercontent.com/assets/12326241/7583382/09481520-f895-11e4-8d55-2bd3f897cf41.png)\r\n\r\nYou can see the delays show up as gaps in the measurements. On zooming in (same plot), it appears we can distinguish between the kernel not updating the measurements and the user loop not running. In the former, you can see that the sensor values appear to stay constant.\r\n\r\n![hang2](https://cloud.githubusercontent.com/assets/12326241/7583411/3b81a358-f895-11e4-88b6-daf4dd81eec6.png)"}}