{"action":"created","issue":{"url":"https://api.github.com/repos/betaflight/betaflight/issues/2879","repository_url":"https://api.github.com/repos/betaflight/betaflight","labels_url":"https://api.github.com/repos/betaflight/betaflight/issues/2879/labels{/name}","comments_url":"https://api.github.com/repos/betaflight/betaflight/issues/2879/comments","events_url":"https://api.github.com/repos/betaflight/betaflight/issues/2879/events","html_url":"https://github.com/betaflight/betaflight/issues/2879","id":221678098,"number":2879,"title":"DSHOT protocol implementation cannot reach 100% throttle","user":{"login":"lazd","id":201344,"avatar_url":"https://avatars0.githubusercontent.com/u/201344?v=3","gravatar_id":"","url":"https://api.github.com/users/lazd","html_url":"https://github.com/lazd","followers_url":"https://api.github.com/users/lazd/followers","following_url":"https://api.github.com/users/lazd/following{/other_user}","gists_url":"https://api.github.com/users/lazd/gists{/gist_id}","starred_url":"https://api.github.com/users/lazd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lazd/subscriptions","organizations_url":"https://api.github.com/users/lazd/orgs","repos_url":"https://api.github.com/users/lazd/repos","events_url":"https://api.github.com/users/lazd/events{/privacy}","received_events_url":"https://api.github.com/users/lazd/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2017-04-13T20:48:58Z","updated_at":"2017-04-13T22:47:03Z","closed_at":null,"body":"I was looking at the DSHOT ESC signals with my oscilloscope, and I noticed the least significant bit of the 11 bits that indicate throttle value was never turned on, no matter what throttle value I selected in the motors tab. I realize that's because Betaflight's internal representation of throttle only has 1000 steps, so we're only using half of the throttle resolution the DSHOT protocol is capable of and therefore only getting even numbers, but it's resulting in an off-by-one error...\r\n\r\n## Expected Behavior\r\n\r\nBetaflight sends 2047 for 100% throttle.\r\n\r\n## Actual\r\n\r\nBetaflight sends 2046 for 100% throttle.\r\n\r\n## Steps to reproduce\r\n\r\nIn this screenshot, the motor output value was set to 1001 in the Motors tab. This results in a decoded value of 48, which is the lowest non-zero throttle value in DSHOT (as 0 means disarmed and 1-47 are reserved for commands). If you consider 0 the 1st throttle step, this is the 2nd of 2000 total throttle steps, as expected.\r\n![Lowest possible throttle, decoded value 48](https://cloud.githubusercontent.com/assets/201344/25014625/6631ab54-202d-11e7-937a-72405d5a9f9c.jpg)\r\n\r\nOf course, increasing the motor output value to 1002 results in a decoded value of 50, as expected, since we're only using half the resolution of the protocol.\r\n\r\nHowever, in this screenshot, the motor output value was set to 2000 (100% throttle) in the Motors tab, but only the first 10 bits are on, resulting in a value of 2046 -- the 1999th of 2000 throttle steps -- when the actual maximum throttle value should be 2047:\r\n![Highest possible throttle, decoded value 2046](https://cloud.githubusercontent.com/assets/201344/25014102/3969ebe2-202b-11e7-9fdd-a38f335d556c.jpg)\r\n\r\nAs a result, Betaflight is never sending 100% throttle to ESCs when using the DSHOT protocol. Additionally, a motor output value of 1500 does not result in exactly 50% throttle -- both are off by 1.\r\n\r\n### Why?\r\n\r\nInside of `convertExternalToMotor()`, we have:\r\n\r\n```c\r\nmotorValue = externalValue <= EXTERNAL_CONVERSION_MIN_VALUE ? DSHOT_DISARM_COMMAND : constrain((externalValue - EXTERNAL_DSHOT_CONVERSION_OFFSET) * EXTERNAL_DSHOT_CONVERSION_FACTOR, DSHOT_MIN_THROTTLE, DSHOT_MAX_THROTTLE);\r\n```\r\n\r\n`DSHOT_MAX_THROTTLE` is defined as 2047, but because `externalValue` is multiplied by `EXTERNAL_DSHOT_CONVERSION_FACTOR` which has a value of `2`, for 2D and positive direction 3D flight, the motor output value can never be odd and can therefore never be equal to 2047.\r\n\r\nCurrently, we get the following values for 2D flight:\r\n\r\n2000 => 2046\r\n1501 => 1048\r\n1500 => 1046\r\n1499 => 1044\r\n1001 => 48\r\n1000 => 0\r\n\r\nAnd we get the following values for 3D flight:\r\n\r\n2000 => 2046\r\n1501 => 1048\r\n1500 => 0\r\n1499 => 51\r\n1001 => 1047\r\n1000 => 0\r\n\r\nAs you can see, maximum throttle is never achieved for 2D or 3D flight in the positive direction, however, maximum throttle is achieved for 3D flight in the negative direction (1047 is maximum throttle in the negative direction). Additionally, the middle throttle value of 1500 results in a signal of 1046, which is actually off by 1 from the actual middle throttle value in DSHOT (1047).\r\n\r\n### Proposed solution\r\n\r\nIf we simply add 1 to `motorValue` for normal 2D and 3D flight alike, we get the following values:\r\n\r\nFor 2D flight:\r\n\r\n2000 => 2047\r\n1501 => 1049\r\n1500 => 1047\r\n1499 => 1045\r\n1001 => 49\r\n1000 => 0\r\n\r\nFor 3D flight:\r\n\r\n2000 => 2047\r\n1501 => 1049\r\n1500 => 0\r\n1499 => 51\r\n1001 => 1047\r\n1000 => 0\r\n\r\nAfter this change, all throttle values sent to the ESC will be odd, we'll have the maximum throttle values possible for both 2D and 3D flight (equally in both directions), and the middle ESC throttle value of 1500 will result in the expected DSHOT value of 1047. \r\n\r\nHowever, we will no longer be able to send the minimum throttle value for 2D flight. That said, because `digital_idle_percent` is pretty much always a non-zero number (motors would not spin), it's very unlikely minimum ESC throttle value of 48 will be sent to the ESC, but it is very common that the maximum ESC throttle value of 2047 will be sent. As such, I believe we lose nothing by making this change."},"comment":{"url":"https://api.github.com/repos/betaflight/betaflight/issues/comments/294040993","html_url":"https://github.com/betaflight/betaflight/issues/2879#issuecomment-294040993","issue_url":"https://api.github.com/repos/betaflight/betaflight/issues/2879","id":294040993,"user":{"login":"lazd","id":201344,"avatar_url":"https://avatars0.githubusercontent.com/u/201344?v=3","gravatar_id":"","url":"https://api.github.com/users/lazd","html_url":"https://github.com/lazd","followers_url":"https://api.github.com/users/lazd/followers","following_url":"https://api.github.com/users/lazd/following{/other_user}","gists_url":"https://api.github.com/users/lazd/gists{/gist_id}","starred_url":"https://api.github.com/users/lazd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lazd/subscriptions","organizations_url":"https://api.github.com/users/lazd/orgs","repos_url":"https://api.github.com/users/lazd/repos","events_url":"https://api.github.com/users/lazd/events{/privacy}","received_events_url":"https://api.github.com/users/lazd/received_events","type":"User","site_admin":false},"created_at":"2017-04-13T22:47:03Z","updated_at":"2017-04-13T22:47:03Z","body":"@borisbstyle @DieHertz I just tested 3.1.7, and when arming and throttling up, the problem is not present -- I see full throttle represented correctly on my scope. That said, is this still an issue that should be addressed?"}}
{"actor":{"display_login":"lazd"}}