tag:blogger.com,1999:blog-13236834155275273912024-03-01T01:36:50.827-08:00Reefwing RoboticsThis blog will document the building of AVA. AVA is intended to be a fully autonomous robot which can react based on a number of layered behavioural patterns. AVA's brains will be built using networked Arduino's. Arduino is an open-source electronics platform based on hardware which comes in a number of configurations based on your requirements and a free Integrated Development Environment (IDE) which allows you to program the microcontroller in C++.David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.comBlogger79125tag:blogger.com,1999:blog-1323683415527527391.post-64435186480932599112023-03-18T17:00:00.004-07:002023-03-18T17:00:34.685-07:00ChatGPT — Search Accuracy, Hallucinations, and Prompt Engineering<p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">We love the progress that is being made in Machine Learning (ML) and predictive Large Language Models (LLMs), but believe users need to be cautious in their application and aware of the pitfalls. LLMs are being spruiked as a replacement for search engines (*cough* Microsoft *cough*), but until they stop hallucinating and making up facts, caution is warranted. </span><a data-attribute-index="0" href="https://www.linkedin.com/feed/hashtag/?keywords=chatgpt&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A7043005286000861184" style="background-color: white; border: var(--artdeco-reset-link-border-zero); box-sizing: inherit; font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: var(--artdeco-reset-base-margin-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); position: relative; text-decoration: var(--artdeco-reset-link-text-decoration-none); touch-action: manipulation; vertical-align: var(--artdeco-reset-base-vertical-align-baseline); word-break: normal;">#chatgpt</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="1" href="https://www.linkedin.com/feed/hashtag/?keywords=promptengineering&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A7043005286000861184" style="background-color: white; border: var(--artdeco-reset-link-border-zero); box-sizing: inherit; font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: var(--artdeco-reset-base-margin-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); position: relative; text-decoration: var(--artdeco-reset-link-text-decoration-none); touch-action: manipulation; vertical-align: var(--artdeco-reset-base-vertical-align-baseline); word-break: normal;">#promptengineering</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="2" href="https://www.linkedin.com/feed/hashtag/?keywords=aihallucinations&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A7043005286000861184" style="background-color: white; border: var(--artdeco-reset-link-border-zero); box-sizing: inherit; font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: var(--artdeco-reset-base-margin-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); position: relative; text-decoration: var(--artdeco-reset-link-text-decoration-none); touch-action: manipulation; vertical-align: var(--artdeco-reset-base-vertical-align-baseline); word-break: normal;">#aihallucinations</a> </p><p>Check out our latest article on Medium - <a href="https://reefwing.medium.com/chatgpt-search-accuracy-hallucinations-and-prompt-engineering-c5270c15b0e4">https://reefwing.medium.com/chatgpt-search-accuracy-hallucinations-and-prompt-engineering-c5270c15b0e4</a></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-52951513194147767702022-11-09T23:12:00.006-08:002022-11-09T23:12:47.774-08:00Arduino Nano Electronic Speed Controller (ESC)<p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;">Having delved into how BLDC motors operate and provided an overview of trapezoidal sensorless control, we can bring it all together in the design of an Arduino ESC shield. This turned out to be much harder than we expected - now we know why no-one does it! </span></p><p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;">This series of articles was sponsored by PCBWay. </span></p><p><span class="ql-hashtag" style="border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: var(--artdeco-reset-base-font-size-hundred-percent); font-weight: var(--artdeco-reset-typography-font-weight-bold); margin: var(--artdeco-reset-base-margin-zero); outline: var(--artdeco-reset-base-outline-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;">#arduino</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: var(--artdeco-reset-base-font-size-hundred-percent); font-weight: var(--artdeco-reset-typography-font-weight-bold); margin: var(--artdeco-reset-base-margin-zero); outline: var(--artdeco-reset-base-outline-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;">#shield</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: var(--artdeco-reset-base-font-size-hundred-percent); font-weight: var(--artdeco-reset-typography-font-weight-bold); margin: var(--artdeco-reset-base-margin-zero); outline: var(--artdeco-reset-base-outline-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;">#ESC</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: var(--artdeco-reset-base-font-size-hundred-percent); font-weight: var(--artdeco-reset-typography-font-weight-bold); margin: var(--artdeco-reset-base-margin-zero); outline: var(--artdeco-reset-base-outline-zero); overflow-wrap: normal; padding: var(--artdeco-reset-base-padding-zero); vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;">#bldcmotor</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span></p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; background-color: white; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;"><br style="box-sizing: inherit;" /></p><p style="--artdeco-reset-typography_getfontsize: 1.6rem; --artdeco-reset-typography_getlineheight: 1.5; background-color: white; border: var(--artdeco-reset-base-border-zero); box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: var(--artdeco-reset-typography_getLineHeight); margin: 0px; padding: 0px; vertical-align: var(--artdeco-reset-base-vertical-align-baseline); white-space: pre-wrap;">https://reefwing.medium.com/an-arduino-nano-electronic-speed-controller-esc-part-1-4f65076fb2e4</p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-27304635008866394822022-07-06T18:47:00.001-07:002022-07-06T18:47:17.255-07:00How to Write your own Flight Controller Software<p> In <a href="https://reefwing.medium.com/how-to-write-your-own-flight-controller-software-part-9-c87fffb426eb" target="_blank">Part 9 of our series on "How to write your own Flight Control Software"</a>, we describe how to control the ESC and brushless motors to get the desired drone orientation.</p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-20172059686184154332022-03-20T22:38:00.002-07:002022-03-20T22:38:56.071-07:00Nexgen AHRS Arduino Library<p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">Our latest article on "How to write your own Flight Controller Software" is available on Medium. This article covers the Attitude and Heading Reference System (AHRS), IMU Filters and Sensor Fusion. We have released the open source Nexgen AHRS Arduino library to demonstrate these techniques on the Nano 33 BLE.</span> <br /><br /><a href="https://reefwing.medium.com/how-to-write-your-own-flight-controller-software-part-7-64daef8299ee">https://reefwing.medium.com/how-to-write-your-own-flight-controller-software-part-7-64daef8299ee</a></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-85247792412553771692022-02-11T22:01:00.001-08:002022-02-11T22:01:13.182-08:00NexgenTimer Arduino Library<p> <span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">LiPo batteries are great for drones but you don't want to over discharge them. To allow our Flight Controller to monitor battery capacity we used a non blocking scheduler and packaged our requirements up as an Arduino Library, NexgenTimer.</span></p><br style="background-color: white; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; line-height: inherit !important;" /><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">Our library is an amalgamation of the MillisTimer and ElapsedTimer libraries with some application specific examples and an extra Timeout class. It only uses functions from the Arduino core API and hence should work on all Arduino boards.</span><br style="background-color: white; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; line-height: inherit !important;" /><br style="background-color: white; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; line-height: inherit !important;" /><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">It can be downloaded using the Arduino Library Manager and you can read all about it in our latest article on Medium - </span><span style="color: rgba(0, 0, 0, 0.901960784313726); font-family: -apple-system, system-ui, system-ui, Segoe UI, Roboto, Helvetica Neue, Fira Sans, Ubuntu, Oxygen, Oxygen Sans, Cantarell, Droid Sans, Apple Color Emoji, Segoe UI Emoji, Segoe UI Emoji, Segoe UI Symbol, Lucida Grande, Helvetica, Arial, sans-serif;"><span style="font-size: 14px;">https://reefwing.medium.com/how-to-write-your-own-flight-controller-software-part-6-7ce0fa3e8008</span></span>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-47520772900441981592022-01-02T18:01:00.002-08:002022-01-02T18:01:29.759-08:00Write your own Flight Controller Software - Part 5<p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;">There are a number of libraries that make working with the LSM9DS1 IMU (Inertial Measurement Unit) easy. In Part 5 of our series on writing your own flight controller software we will focus on the IMU and in particular explain the best ways to convert the gyro rate and accelerometer force data to a roll and pitch angle. The yaw angle is then calculated using the pitch and roll and magnetometer data. This discussion, is in the context of building a drone flight controller based on the Arduino Nano 33 BLE. https://reefwing.medium.com/a59bf9ed8c69</span></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-8201740433661523542021-08-12T00:22:00.001-07:002021-08-12T00:22:19.169-07:00Debugging the Arduino Motor Shield<p> <span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;">Our L293 based motor shield had some problems! How do we diagnose what the problems are and create a better design? This final tutorial, will explain how we went about troubleshooting the issues and creating a better circuit to be used in version 2 of our design. </span><a data-attribute-index="0" href="https://www.linkedin.com/feed/hashtag/?keywords=arduino&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6831481100473368576" style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: 0px; padding: 0px; position: relative; text-decoration-line: none; touch-action: manipulation; vertical-align: baseline;">#arduino</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="1" href="https://www.linkedin.com/feed/hashtag/?keywords=uno&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6831481100473368576" style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: 0px; padding: 0px; position: relative; text-decoration-line: none; touch-action: manipulation; vertical-align: baseline;">#uno</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="2" href="https://www.linkedin.com/feed/hashtag/?keywords=motor&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6831481100473368576" style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: 0px; padding: 0px; position: relative; text-decoration-line: none; touch-action: manipulation; vertical-align: baseline;">#motor</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="3" href="https://www.linkedin.com/feed/hashtag/?keywords=shield&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6831481100473368576" style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: 0px; padding: 0px; position: relative; text-decoration-line: none; touch-action: manipulation; vertical-align: baseline;">#shield</a><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px;"> </span><a data-attribute-index="4" href="https://www.linkedin.com/feed/hashtag/?keywords=debugging&highlightedUpdateUrns=urn%3Ali%3Aactivity%3A6831481100473368576" style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 14px; font-weight: var(--font-weight-bold); line-height: inherit !important; margin: 0px; padding: 0px; position: relative; text-decoration-line: none; touch-action: manipulation; vertical-align: baseline;">#debugging</a></p><p><a href="https://reefwing.medium.com/debugging-the-arduino-motor-shield-21c9218bdcc2">https://reefwing.medium.com/debugging-the-arduino-motor-shield-21c9218bdcc2</a></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-26653399079892548462021-08-07T19:41:00.000-07:002021-08-07T19:41:06.641-07:00How to write your own Arduino Library<p> <span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;">Following our article on how to design your own Arduino motor shield, we have written a companion piece that explains how to create your own Arduino library. Our explanation focuses on all the things that the beginner tutorials don't cover. </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#Arduino</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#UNO</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#STEM</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#nexgencodecamp</span></p><p style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.5; margin: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;"><a href="https://reefwing.medium.com/how-to-create-your-own-arduino-library-540f833a49cf">https://reefwing.medium.com/how-to-create-your-own-arduino-library-540f833a49cf</a></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-58395222375257830412021-07-28T01:09:00.006-07:002021-07-28T01:09:50.297-07:00How to Create your own Arduino Motor Shield<p><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;">The Nexgen Rover is an Arduino based robot designed wholly by Nexgen Codecamp. It is used in our technology related STEM courses aimed at high schools. The robot is based on Arduino technology and runs an Arduino UNO with a motor controller shield on top. This article explains how we designed and manufactured our own motor shield to suit the requirements of the rover. </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#arduino</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#stemeducation</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#uno</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#motor</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#shield</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#nexgen</span><span style="background-color: white; color: rgba(0, 0, 0, 0.9); font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; white-space: pre-wrap;"> </span></p><p style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.5; margin: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">https://reefwing.medium.com/designing-your-own-arduino-uno-motor-shield-ca507ab61f4b</p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-12194095494774040682021-06-03T01:00:00.002-07:002021-06-03T01:01:12.817-07:00A Review of Open Source Flight Control Firmware<p> <span color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-color: white; font-size: 16px; white-space: pre-wrap;">The evolution of open-source flight control firmware is fascinating and involves everything from years of committed development with no reward, to convoluted betrayal from previous partners and friends. In this article, we will review the most popular open-source projects, explain their antecedents and highlight the survivors. </span><span class="ql-hashtag" color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#arduino</span><span color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-color: white; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#drone</span><span color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-color: white; font-size: 16px; white-space: pre-wrap;"> </span><span class="ql-hashtag" color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; font-size: 16px; font-weight: 600; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;">#development</span><span color="rgba(0, 0, 0, 0.9)" face="-apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif" style="background-color: white; font-size: 16px; white-space: pre-wrap;"> </span></p><p style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.5; margin: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;"><br style="box-sizing: inherit;" /></p><p style="background: rgb(255, 255, 255); border: 0px; box-sizing: inherit; color: rgba(0, 0, 0, 0.9); counter-reset: list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; cursor: text; font-family: -apple-system, system-ui, system-ui, "Segoe UI", Roboto, "Helvetica Neue", "Fira Sans", Ubuntu, Oxygen, "Oxygen Sans", Cantarell, "Droid Sans", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.5; margin: 0px; padding: 0px; vertical-align: baseline; white-space: pre-wrap;"><a href="https://reefwing.medium.com/a-review-of-open-source-flight-control-systems-2fe37239c9b6">https://reefwing.medium.com/a-review-of-open-source-flight-control-systems-2fe37239c9b6</a></p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-1340659864403464152021-02-25T21:32:00.000-08:002021-02-25T21:32:01.381-08:00Configuring an ESC using an Arduino Uno<p><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;">Using an Arduino UNO to communicate with an Electronic Speed Controller (ESC) that uses BLHeli or BLHeli_S firmware. </span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"><a class="oajrlxb2 g5ia77u1 qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 nc684nl6 p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x jb3vyjys rz4wbd8a qt6c0cv9 a8nywdso i1ao9s8h esuyzwwr f1sip0of lzcic4wl q66pz984 gpro0wi8 b1v8xokw" href="https://www.facebook.com/hashtag/arduino?__eep__=6&__cft__[0]=AZWuXlVdVyMqJfQcu0ryX8fMshlbDLV4knPs_2ni4_RhVobBRaPONoXG8KEXxfUSyJ7IWmWrQ0fAOgws2XL8z4qgZPGuH5-ygRfEVDT8EhC8LJFG4b9-IMGIpCMN9DHCWK6B9mTk0C5u2kxj9VHucCJCKyHevkYFguuCDPSAD254XeIbaWdeYGH-nmIxGmN1skY&__tn__=*NK-R" role="link" style="-webkit-tap-highlight-color: transparent; background-color: transparent; border-color: initial; border-style: initial; border-width: 0px; box-sizing: border-box; cursor: pointer; display: inline; font-family: inherit; list-style: none; margin: 0px; outline: none; padding: 0px; text-align: inherit; text-decoration-line: none; touch-action: manipulation;" tabindex="0">#Arduino</a></span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"> </span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"><a class="oajrlxb2 g5ia77u1 qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 nc684nl6 p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x jb3vyjys rz4wbd8a qt6c0cv9 a8nywdso i1ao9s8h esuyzwwr f1sip0of lzcic4wl q66pz984 gpro0wi8 b1v8xokw" href="https://www.facebook.com/hashtag/blheli?__eep__=6&__cft__[0]=AZWuXlVdVyMqJfQcu0ryX8fMshlbDLV4knPs_2ni4_RhVobBRaPONoXG8KEXxfUSyJ7IWmWrQ0fAOgws2XL8z4qgZPGuH5-ygRfEVDT8EhC8LJFG4b9-IMGIpCMN9DHCWK6B9mTk0C5u2kxj9VHucCJCKyHevkYFguuCDPSAD254XeIbaWdeYGH-nmIxGmN1skY&__tn__=*NK-R" role="link" style="-webkit-tap-highlight-color: transparent; background-color: transparent; border-color: initial; border-style: initial; border-width: 0px; box-sizing: border-box; cursor: pointer; display: inline; font-family: inherit; list-style: none; margin: 0px; outline: none; padding: 0px; text-align: inherit; text-decoration-line: none; touch-action: manipulation;" tabindex="0">#BLHeli</a></span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"> </span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"><a class="oajrlxb2 g5ia77u1 qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 nc684nl6 p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x jb3vyjys rz4wbd8a qt6c0cv9 a8nywdso i1ao9s8h esuyzwwr f1sip0of lzcic4wl q66pz984 gpro0wi8 b1v8xokw" href="https://www.facebook.com/hashtag/drone?__eep__=6&__cft__[0]=AZWuXlVdVyMqJfQcu0ryX8fMshlbDLV4knPs_2ni4_RhVobBRaPONoXG8KEXxfUSyJ7IWmWrQ0fAOgws2XL8z4qgZPGuH5-ygRfEVDT8EhC8LJFG4b9-IMGIpCMN9DHCWK6B9mTk0C5u2kxj9VHucCJCKyHevkYFguuCDPSAD254XeIbaWdeYGH-nmIxGmN1skY&__tn__=*NK-R" role="link" style="-webkit-tap-highlight-color: transparent; background-color: transparent; border-color: initial; border-style: initial; border-width: 0px; box-sizing: border-box; cursor: pointer; display: inline; font-family: inherit; list-style: none; margin: 0px; outline: none; padding: 0px; text-align: inherit; text-decoration-line: none; touch-action: manipulation;" tabindex="0">#Drone</a></span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"> </span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"><a class="oajrlxb2 g5ia77u1 qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 nc684nl6 p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x jb3vyjys rz4wbd8a qt6c0cv9 a8nywdso i1ao9s8h esuyzwwr f1sip0of lzcic4wl q66pz984 gpro0wi8 b1v8xokw" href="https://www.facebook.com/hashtag/tutorial?__eep__=6&__cft__[0]=AZWuXlVdVyMqJfQcu0ryX8fMshlbDLV4knPs_2ni4_RhVobBRaPONoXG8KEXxfUSyJ7IWmWrQ0fAOgws2XL8z4qgZPGuH5-ygRfEVDT8EhC8LJFG4b9-IMGIpCMN9DHCWK6B9mTk0C5u2kxj9VHucCJCKyHevkYFguuCDPSAD254XeIbaWdeYGH-nmIxGmN1skY&__tn__=*NK-R" role="link" style="-webkit-tap-highlight-color: transparent; background-color: transparent; border-color: initial; border-style: initial; border-width: 0px; box-sizing: border-box; cursor: pointer; display: inline; font-family: inherit; list-style: none; margin: 0px; outline: none; padding: 0px; text-align: inherit; text-decoration-line: none; touch-action: manipulation;" tabindex="0">#Tutorial</a></span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"> </span><span style="background-color: white; color: #050505; font-family: system-ui, -apple-system, system-ui, ".SFNSText-Regular", sans-serif; font-size: 15px; white-space: pre-wrap;"><a class="oajrlxb2 g5ia77u1 qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 nc684nl6 p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x jb3vyjys rz4wbd8a qt6c0cv9 a8nywdso i1ao9s8h esuyzwwr f1sip0of lzcic4wl py34i1dx gpro0wi8" href="https://reefwing.medium.com/configuring-an-esc-with-blheli-firmware-using-an-arduino-uno-9b8e5dafc1c5?fbclid=IwAR0EjqmuXdbiPKKtpoe82K48JT4iDPq4sDvhaunZhVtErgJWis_1gdARTqY" rel="nofollow noopener" role="link" style="-webkit-tap-highlight-color: transparent; background-color: transparent; border-color: initial; border-style: initial; border-width: 0px; box-sizing: border-box; cursor: pointer; display: inline; font-family: inherit; list-style: none; margin: 0px; outline: none; padding: 0px; text-align: inherit; text-decoration-line: none; touch-action: manipulation;" tabindex="0" target="_blank">https://reefwing.medium.com/configuring-an-esc-with...</a></span> </p>David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-81425831982513456272020-06-21T00:56:00.000-07:002020-06-21T00:56:46.847-07:00The Falcon DS1 - BeagleBone Blue Drone (Part 3)<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Construction</h3>
<br />
The hardest part of the build is coming up with a bracket to mount the BeagleBone on the Martian II air frame. In part 1 of these tutorials, I mentioned that there was an existing bracket design available. This doesn't fit for a number of reasons, including clashes with the XT60 socket, the propellers and the top deck of the air frame. But we will come to that...<br />
<br />
Start off by putting the frame together. There is a <a href="https://www.youtube.com/watch?v=EZ3U5K7NTsY" target="_blank">very thorough video</a> of how to do this on YouTube. They are using some different components (including the flight controller), but it does a great job of showing what goes where.<br />
<br />
As shown in Figure 20, I labelled the front of the drone and motor number locations using electrical tape. This helps keep you oriented.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG3g5_MyJcldwp6GHxAVCoQwF8G_rGqStlqy_gKbAnxluPfAeedHZDM90MxTXZmTgVHfmtsDNnM0DvbGKMkBV4jPsX-jEn_OhyghXTcBVchEd6SY2-FBAXOLCzPgIoqzH9vFfcHkGZrob7/s1600/Slide05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG3g5_MyJcldwp6GHxAVCoQwF8G_rGqStlqy_gKbAnxluPfAeedHZDM90MxTXZmTgVHfmtsDNnM0DvbGKMkBV4jPsX-jEn_OhyghXTcBVchEd6SY2-FBAXOLCzPgIoqzH9vFfcHkGZrob7/s400/Slide05.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 20. Martian II Frame Construction.</span></div>
<br />
Once you have the arms attached to the bottom frame and the Power Distribution Board (PDB) mounted, you can add the quad 20A Electronic Speed Controller (ESC). The RaceStar ESC that I bought has mounting holes which line up nicely with the PDB. I assume that this isn't a coincidence but I admit that I fluked it. Figure 21, provides an overview of what the bottom layer of the drone will look like when we are finished.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxYR65ea7zbLPfpscnIJH0lNmp3nJfMn9x5KPCAp8mgfQaLHP-q4kpH7Ye6R-T2vDOlcjw6r_PQMZdEzTYOUSHPTgw5aG6kndyH7gKlCeVdekU8EdTh1_xJpW3qJeRRjCAE8qaBJxNlaO7/s1600/Slide06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxYR65ea7zbLPfpscnIJH0lNmp3nJfMn9x5KPCAp8mgfQaLHP-q4kpH7Ye6R-T2vDOlcjw6r_PQMZdEzTYOUSHPTgw5aG6kndyH7gKlCeVdekU8EdTh1_xJpW3qJeRRjCAE8qaBJxNlaO7/s400/Slide06.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 21. Bottom layer Component layout</span></div>
<br />
Figure 22, illustrates the Quad ESC in place above the PDB. Now comes the tricky part (for me, you will find it easy since I supply the bracket design), mounting the BeagleBone. Referring to Figure 21, you can see that there is only 10 mm clearance between the PDB and the propellers, so our bracket can't overhang much. In addition the XT60 socket and associated cables must remain accessible with the BeagleBone in place. If we are going to stick with a stock Martian II frame, the available distance between the top and bottom layers is 30 mm and with the ESC in place we have already used 20 mm of that. Finally, we want to keep the weight centred as much as possible.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4vLmI3WJmRm5QWCjY12EfMCTBPycpQM4osftCBxovRlXbe32x-4nhBNN12welnHYgSFpjpmOLNW7BrUpnttxpXbe1wo1ZAD9xDxEsRbZrishx0loXiUEPRkdTaxE5J59aYy5rwFR2rdM5/s1600/IMG_4163.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="1600" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4vLmI3WJmRm5QWCjY12EfMCTBPycpQM4osftCBxovRlXbe32x-4nhBNN12welnHYgSFpjpmOLNW7BrUpnttxpXbe1wo1ZAD9xDxEsRbZrishx0loXiUEPRkdTaxE5J59aYy5rwFR2rdM5/s400/IMG_4163.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 22. Bottom layer components in place.</span></div>
<br />
In the end, I wasn't able to satisfy all of these constraints. The BeagleBone is just too big, it requires 17mm even if you didn't have to make connections to the pin headers (which you do). In addition, to provide access to the XT-60 the BeagleBone needs to be offest from the centre line of the drone.<br />
<br />
Typically with the Martian II build, the LiPo battery is attached to the top frame. Instead, I have placed it between the ESC and BeagleBone. As illustrated in Figure 23, it took 5 attempts but I eventually came up with a design that met most of the constraints.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpSH9SxHTfrRKqJaRZ8mQuMq94b6gNcnpbjP3ieUvg6iwmY0U4Cbveqohvel_RKL5VZVzMdHJrgj4qLq1I0ejMYTDH0mGeHxVpZzHyev3MYDByorF-Lw2DBxs3hNOpHa9888nVD6CiGotL/s1600/IMG_4172.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="1600" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpSH9SxHTfrRKqJaRZ8mQuMq94b6gNcnpbjP3ieUvg6iwmY0U4Cbveqohvel_RKL5VZVzMdHJrgj4qLq1I0ejMYTDH0mGeHxVpZzHyev3MYDByorF-Lw2DBxs3hNOpHa9888nVD6CiGotL/s400/IMG_4172.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 23. BeagleBone mounting plate with LiPo.</span></div>
<br />
The STL file for the <a href="https://www.thingiverse.com/thing:4098302" target="_blank">mounting plate is available for download</a> from Thingiverse.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyYPeGAcbelQz5IG_0OHqKNiu7UYmK7p3ppGi9V51oIXO7V20qwn5KNOfP_zf_ovOdIIUOoW6X_nMsfEYT0zCrbKn9oAboUqw1AO4dLN5RCwd31NasXZkoIyR1-2frSBoEESQgN9PnifLA/s1600/BBB_Mounting_v5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="887" data-original-width="1038" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyYPeGAcbelQz5IG_0OHqKNiu7UYmK7p3ppGi9V51oIXO7V20qwn5KNOfP_zf_ovOdIIUOoW6X_nMsfEYT0zCrbKn9oAboUqw1AO4dLN5RCwd31NasXZkoIyR1-2frSBoEESQgN9PnifLA/s400/BBB_Mounting_v5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 24. BeagleBone Blue 3D Printed Mounting Plate.</span></div>
<br />
Wire up the power and control cabling as per the schematics in Parts 1 and 2. As our build is a bit different to the standard Martian II, I will provide a few supplementary notes and guidelines based on my experience.<br />
<br />
<h3 style="text-align: left;">
Mounting the Motors</h3>
We need to mount the four brushless motors to work out the correct wire length to the ESC. My RacerStar motors came with two sets of M3 screws, 8mm and 6mm. The thickness of the frame arms is 4mm, so use the 6mm screws to ensure they don't short out the motor coils. For now you can just do them up finger tight but eventually you will want to apply loctite to ensure that the motors don't fall off mid flight (bad).<br />
<br />
The RacerStar ESC can be programmed using the <a href="https://github.com/bitdump/BLHeli" target="_blank">BLHeliSuite software</a> on PC. With that we can reverse the motor direction but you need compatible Flight Controller software. For our purposes, it is probably simpler to just swap two wires if the motor is going in the wrong direction.<br />
<br />
My motors indicate their default rotational direction (clockwise or anticlockwise) by arrows on the top of the motor and different coloured propeller nuts. The black nuts rotate clockwise and the red nuts anticlockwise. To minimise the amount of work, you should mount the motors in the configuration shown in Figure 25.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhneadMvcIrjtdZblRQGxef26Y0h7n8iViiajPa5P_X7WLJMOp3BpVm15XasXvBEFCGIZlxP-prUAMqVU72gRn4zuNaarJ9zqDG57-Wjs1KA1ROGiLTd4nOgJ1K-AyxhEGhD5H6CGGgRtrr/s1600/Slide09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhneadMvcIrjtdZblRQGxef26Y0h7n8iViiajPa5P_X7WLJMOp3BpVm15XasXvBEFCGIZlxP-prUAMqVU72gRn4zuNaarJ9zqDG57-Wjs1KA1ROGiLTd4nOgJ1K-AyxhEGhD5H6CGGgRtrr/s400/Slide09.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 25. Required Motor Directions (X Configuration)</span></div>
<br />
Once you have mounted the motors you can then wire them to the Quad ESC. While you are doing this, also solder the ESC battery connection to the appropriate pads (+ and -) on the Power Distribution Board and a connector to allow you to plug power into the flight controller.<br />
<br />
<br />
<br /></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com2tag:blogger.com,1999:blog-1323683415527527391.post-74016014050848564652020-06-21T00:55:00.000-07:002020-06-21T00:55:16.347-07:00The Falcon DS1 - BeagleBone Blue Drone (Part 2)<div dir="ltr" style="text-align: left;" trbidi="on">
<div>
<h3 style="text-align: left;">
Control Wiring</h3>
<br />
The BeagleBone uses mostly JST connectors. We need the following:<br />
<ul style="text-align: left;">
<li>Four (4) of the 2-pin 1.5 JST ZH female connectors, with attached 150mm 28AWG wires, for the motors,</li>
<li>Eight (8) of the 4-pin 1.0 JST SH female connectors, with attached 150mm 28AWG wires, for the encoders as well as the UART, I2C, CAN, and PWR busses, and</li>
<li>Four (4) of the 6-pin 1.0 JST SH female connectors, with attached 150mm 28AWG wires, for the SPI, GPS, GPIO, and ADC busses.</li>
</ul>
</div>
<div>
These connectors are small but they are also fiddly to crimp and a bit delicate. Nevertheless this is what we are stuck with. Despite a LOT of searching, I was unable to find a complete diagram which indicated all of the correct connections for using the BeagleBone Blue as a flight controller for ArduCopter. The best I was able to find was the <a href="https://github.com/imfatant/test">Imfatant version</a>, which he provides as part of his description regarding how to get ArduCopter onto the BeagleBone. I have reproduced his image below in Figure 12.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijm6Rn17prGLhXN9q867jAcXpofMEa6T65rr7owjYIaESYREWrioOGbNkSgDnwMOr-uYALVt48qTtWxyALJujkPTAH0mYOJoVc9IhFiV2M5grLNlx9gjGhrREg5BogWuM9M-YawxIgeVDC/s1600/BBBlue-ArduPilot.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="857" data-original-width="1131" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijm6Rn17prGLhXN9q867jAcXpofMEa6T65rr7owjYIaESYREWrioOGbNkSgDnwMOr-uYALVt48qTtWxyALJujkPTAH0mYOJoVc9IhFiV2M5grLNlx9gjGhrREg5BogWuM9M-YawxIgeVDC/s400/BBBlue-ArduPilot.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 12. BeagleBone Blue Connections (ref: <a href="https://github.com/imfatant/test" style="text-align: left;">https://github.com/imfatant/test</a>)</span></div>
<br />
<br />
I ended up doing my own drawing, to ensure I knew what connected to what. I needed this in order to work out the best layout on the airframe and what cables and connectors are required.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6yHuVY9klrf-XaBSkM8HnoI7YyT5MnbM867qK8o68BDPAcJvEhyt8Jf3JhB_LJ0EpTlGMklugvc0j0T5pGUauG6V6mYyAV8BcK1o3Fcrzl3UGTIzm8KQEFOAfzT3PooK01inA0RT2FocQ/s1600/Slide3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6yHuVY9klrf-XaBSkM8HnoI7YyT5MnbM867qK8o68BDPAcJvEhyt8Jf3JhB_LJ0EpTlGMklugvc0j0T5pGUauG6V6mYyAV8BcK1o3Fcrzl3UGTIzm8KQEFOAfzT3PooK01inA0RT2FocQ/s400/Slide3.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 13. BeagleBone Blue Control Wiring.</span></div>
<br />
Note that the front of the drone is towards the top of the diagram in Figure 13. The motor numbers match up with the nearest motor outputs on the QUAD ESC. The control wires for each motor (S1, S2, S3 and S4) then go to the corresponding servo/ESC connections on the BeagleBone Blue.<br />
<br />
Now that we have the connections worked out we can load up some software and start testing our rig.<br />
<br />
<h3 style="text-align: left;">
Loading ArduCopter on the BeagleBone Blue</h3>
<br />
The most comprehensive guide to loading the ArduCopter software onto the BeagleBone Blue is found at the <a href="https://github.com/imfatant/test">Imfatant Github repository</a>. There is also a summarised version of these instructions on the <a href="https://github.com/mirkix/ardupilotblue">Mirkix Github repository</a> (Mirko Denecke's port of ArduPilot).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiffEgXFSNiMlxfPN3a12BWUHR5c6iWHBAdWkIHlrIcJhoHG3FgZ7BhbY_RpFHX12glWjL7UR-kial-bnJmKYYHa9uaGeXDdX6M0p0eb9uTjjSw1Sg1T5v7q84rIsWFlZ3sQ8D8hC77sZsw/s1600/Screen+Shot+2019-08-01+at+6.20.19+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="676" data-original-width="780" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiffEgXFSNiMlxfPN3a12BWUHR5c6iWHBAdWkIHlrIcJhoHG3FgZ7BhbY_RpFHX12glWjL7UR-kial-bnJmKYYHa9uaGeXDdX6M0p0eb9uTjjSw1Sg1T5v7q84rIsWFlZ3sQ8D8hC77sZsw/s400/Screen+Shot+2019-08-01+at+6.20.19+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 14. Checking the BBB Connection to the Mac.</span></div>
<br />
<br />
I don't intend to reproduce what has already been written in these guides but I will point out areas where things have changed or if I had difficulties.<br />
<br />
<h3 style="text-align: left;">
PART 1 - Preparation</h3>
<ol style="text-align: left;">
<li>The first issue I found in the Imfatant Guide is that the recommended console image is no longer available at <a href="https://rcn-ee.net/rootfs/bb.org/testing/">https://rcn-ee.net/rootfs/bb.org/testing/</a>. I used the latest version that I could find: <a href="https://rcn-ee.net/rootfs/bb.org/testing/2019-06-30/stretch-console/bone-debian-9.9-console-armhf-2019-06-30-1gb.img.xz">https://rcn-ee.net/rootfs/bb.org/testing/2019-06-30/stretch-console/bone-debian-9.9-console-armhf-2019-06-30-1gb.img.xz</a> Download this and flash it to a microSD card using Etcher (or equivalent). I used a Toshiba 16GB class 10 card so that I would have plenty of room and speed.</li>
<li>I inserted the SD card (it only goes in one way) and booted up the BeagleBone Blue (BBB from here on), by connecting it to my Mac via the micro USB connection. As suggested in the instructions I tried "<span style="color: red;">ssh debian@192.168.7.2</span>" but the operation timed out. It appears that there are two drivers that you have to download and install for this to work on the Mac. </li>
<li>Download the two drivers: Network: <a href="https://beagleboard.org/static/Drivers/MacOSX/RNDIS/HoRNDIS.pkg">https://beagleboard.org/static/Drivers/MacOSX/RNDIS/HoRNDIS.pkg</a> and Serial: <a href="https://beagleboard.org/static/Drivers/MacOSX/FTDI/EnergiaFTDIDrivers2.2.18.pkg">https://beagleboard.org/static/Drivers/MacOSX/FTDI/EnergiaFTDIDrivers2.2.18.pkg</a> and then install them. The Serial driver may ask you to reboot your computer (it did for me). The Beaglebone Blue creates a network connection and emulates an Ethernet adapter. Your computer will receive IP addresses 192.168.7.1 and 192.168.6.1. The Beaglebone Blue has IP addresses 192.168.7.2 and 192.168.6.2. You can check whether this has worked by looking at Networks in system preferences (ref: Figure 14).</li>
<li>You should now be able to ssh in ("<span style="color: red;">ssh debian@192.168.7.2</span>") without difficulty. Password is "<span style="color: red;">temppwd</span>" (see Figure 15 to view a successful first log in). If you receive a “REMOTE HOST IDENTIFICATION HAS CHANGED” error, you have probably previously connected to a different computer on 192.168.7.2 (like another BBB). Remove the old ECDSA key with: "<span style="color: red;">ssh-keygen -R 192.168.7.2</span>".</li>
<li>Next thing you need to do is get WiFi up on the BBB. Follow the Imfatant instructions for this but I found that I had to power the device down and reboot before the changes would take effect. Make sure you "<span style="color: red;">sudo shutdown -h now</span>" before powering down. While you have the power off, CAREFULLY turn the antennas around so that they face off the board. They swivel so don't just try and bend them up and over. You can unplug and replug the antennas if you prefer. Once you power back up, you should have the central green LED lit to indicate a WiFi network connection (ref: Figure 16). </li>
<li>To get the WiFi IP address of your BBB, I usually use "<span style="color: red;">hostname -I</span>" or "<span style="color: red;">ip addr show wlan0</span>". Alternatively, you can just have a look on your router. Terminate your usb connection and ssh back in using the WiFi IP address. The password is the same. Verify that you have an internet connection using "<span style="color: red;">ping -c 3 google.com</span>".</li>
<li>The remainder of the <a href="https://github.com/imfatant/test">Imfatant Part 1 Preparation instructions</a> went smoothly for me.</li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTVDzJJynF9AjqoCTGD9U5cTziSDqcsfqsiIOL1VKDMOuly7oqz1NiOX-rQLCo-EKkUGwgk-QwlR-Wkcz-cIum-8hUJuH4l5KcUOkxUmUgWZzBnpxANcQekjza0w8lfpcte1B9lN6KAUSz/s1600/Screen+Shot+2019-08-01+at+6.25.05+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="477" data-original-width="697" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTVDzJJynF9AjqoCTGD9U5cTziSDqcsfqsiIOL1VKDMOuly7oqz1NiOX-rQLCo-EKkUGwgk-QwlR-Wkcz-cIum-8hUJuH4l5KcUOkxUmUgWZzBnpxANcQekjza0w8lfpcte1B9lN6KAUSz/s400/Screen+Shot+2019-08-01+at+6.25.05+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 15. Logged into the BBB via USB.</span></div>
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6H6WA3fWQLvLhXh2lsLKg95hwjVPYYRzgJatnuP4a02zRdFJf0FfEAoBNHu3IcnQHg6f_f5Bg-6E8CVWBaB_KC9SrvZaQTYnfbylp5wpM5SiWw_3Ct4rinMXMqw82t9jzMESCQnD8slzY/s1600/IMG_2183.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6H6WA3fWQLvLhXh2lsLKg95hwjVPYYRzgJatnuP4a02zRdFJf0FfEAoBNHu3IcnQHg6f_f5Bg-6E8CVWBaB_KC9SrvZaQTYnfbylp5wpM5SiWw_3Ct4rinMXMqw82t9jzMESCQnD8slzY/s400/IMG_2183.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 16. Green WiFi LED on indicating a connection.</span></div>
<br />
<br />
<h3 style="text-align: left;">
Part 2 - Installing ArduPilot</h3>
<br />
Follow the Imfatant instructions for setting up the ArduPilot environment configuration file, /etc/default/ardupilot.<br />
<br />
The switch -A in the ardupilot config file maps ArduPilot's "Console" serial port (SERIAL0, default 115200) to a target IP address and port number of one's choosing. For example, this allows MAVLink data to be transmitted over WiFi for test purposes. This data stream is auto-sensed by ground control station software like <a href="http://ardupilot.org/planner/">Mission Planner</a> (Windows) and <a href="http://qgroundcontrol.com/">QGroundControl</a> (Windows, OS X, Linux, iOS and Android).<br />
<br />
To get the IP address of your Mac, from the Apple menu pull down “System Preferences” and click on the “Network” preference pane. The IP address for your WiFi connection will be shown on the right (see Figure 17).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLWEwvkA9fSaTtKZaFyTLM8Y8IdW-MKn4rTG8bf5depngslemGb_Kt3wk0Q_QrT5K1AOtNxfSlFE5ioNLMw3m9T4X_4NNgKHjOCTH_3RySgewIbyny2iiCbwcgZv1tHt8x2Lbh2Nb7PXP6/s1600/Screen+Shot+2019-08-06+at+6.07.13+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1351" data-original-width="1560" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLWEwvkA9fSaTtKZaFyTLM8Y8IdW-MKn4rTG8bf5depngslemGb_Kt3wk0Q_QrT5K1AOtNxfSlFE5ioNLMw3m9T4X_4NNgKHjOCTH_3RySgewIbyny2iiCbwcgZv1tHt8x2Lbh2Nb7PXP6/s400/Screen+Shot+2019-08-06+at+6.07.13+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 17. Getting your Mac IP address for WiFi.</span></div>
<br />
<br />
For Windows, press the Windows Start key to open the Start screen. Type cmd and press Enter to launch the command prompt. Type ipconfig at the command prompt to check the network card settings. See Figure 18, you want the IPv4 address.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHuikJ3ZsHkO8UbELCXdURorbQEhgKynMHZgjkQKdXnAKGbZF2GJL97-7S8oXHe6lA3plK49rcZuz7ftM0iwajm3Fh7Kfwxlq-Rx7VpsjhveteWwUp3DVDgXUOEEaSfkFPseDKt6Y_qI6x/s1600/WIN_IP_Address.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="639" data-original-width="1103" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHuikJ3ZsHkO8UbELCXdURorbQEhgKynMHZgjkQKdXnAKGbZF2GJL97-7S8oXHe6lA3plK49rcZuz7ftM0iwajm3Fh7Kfwxlq-Rx7VpsjhveteWwUp3DVDgXUOEEaSfkFPseDKt6Y_qI6x/s400/WIN_IP_Address.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 18. Getting IP address for Windows</span></div>
<br />
<br />
The next tricky bit is getting the latest ArduCopter executable, built specifically for the BBBlue's Arm architecture, onto the BBB. The Mirko Denecke link no longer works but the Imfatant one will allow you to download <a href="https://github.com/imfatant/test/tree/master/bin">arducopter v3.6</a>.<br />
<br />
Once you have the file downloaded, there are a few different ways you can copy it to the BeagleBone. You can use SCP, just copy it onto a USB drive and then plug that into the BBB, or you can use something like <a href="https://filezilla-project.org/">FileZilla</a>. I took the last approach. Depending on permissions, this may be as easy as dragging the file across (Figure 19).<br />
<br />
To check the current permissions on the file type, "<span style="color: red;">ls -ld /usr/bin/ardupilot</span>". My initial result was:<br />
<span class="s1"><br /></span>
<span style="color: purple;"><span class="s1">drwxr-xr-x 2 root root 4096 Aug<span class="Apple-converted-space"> </span>6 08:29 </span><span class="s2"><b>/usr/bin/ardupilot</b></span></span><br />
<br />
Which is a problem because the directory's owner and group is root and we have FTP'ed in as debian. In the string displayed above, the first character indicates if we are looking at a directory (d), file (-) or link (l). After that, the folder and file access rights are divided into three categories:<br />
<br />
<pre style="background-color: #eff0f1; border-radius: 3px; border: 0px; box-sizing: inherit; color: #242729; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow-wrap: normal; overflow: auto; padding: 12px 8px; vertical-align: baseline; width: auto;"><code style="border: 0px; box-sizing: inherit; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline; white-space: inherit;">xxxyyyzzz
xxx are access rights for the owner
yyy are access rights for the owner's group
zzz are the access rights for everyone else</code></pre>
The access rights symbols will indicate whether you can read (r), write (w), execute (x) or are missing a right(-). Based on our results, the only person who can write a file into this directory is the owner (i.e. root). We can use chmod to fix this. In terminal type: "<span style="color: red;">sudo chmod o+rwx /usr/bin/ardupilot</span>" The "o" switch applies this change to all users and we are adding (+rwx) read, write and execute rights for this directory. Check with "<span style="color: red;">ls -ld /usr/bin/ardupilot</span>". You should get something like:<br />
<span class="s1" style="font-family: "menlo"; font-size: 11px;"><br /></span>
<span style="color: purple;"><span class="s1" style="font-family: "menlo";">drwxr-xrwx 2 root root 4096 Aug<span class="Apple-converted-space"> </span>6 08:29 </span><span class="s2" style="font-family: "menlo";">/usr/bin/ardupilot</span></span><br />
<br />
You should now be able to drag across the arducopter executable into the /usr/bin/ardupilot directory as shown in figure 19. Username and password is the same as for ssh. Use port 22.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8ZBM67-mpfOu8-EzBjhu1OAz8ZhzQqGGRpj7-nXgJpCqMFZCGou1hUhDxI3hpHef-4M_0l1GJsRLYvF4OMC8RJbbXHzDg_WPM3jo5p7j_ByKLH9cMoAN1n0jcJ2CdRaOoYYo0WB8vFOiI/s1600/Screen+Shot+2019-08-07+at+4.12.36+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1188" data-original-width="1600" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8ZBM67-mpfOu8-EzBjhu1OAz8ZhzQqGGRpj7-nXgJpCqMFZCGou1hUhDxI3hpHef-4M_0l1GJsRLYvF4OMC8RJbbXHzDg_WPM3jo5p7j_ByKLH9cMoAN1n0jcJ2CdRaOoYYo0WB8vFOiI/s400/Screen+Shot+2019-08-07+at+4.12.36+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 19. Copying the arducopter executable to the BBB using FileZilla.</span></div>
<br />
<br />
After this we "<span style="color: red;">sudo systemctl enable arducopter.service</span>" and rebooted the BBB. Job done! You can check that arducopter is enabled with "<span style="color: red;">systemctl is-enabled arducopter</span>".<br />
<br />
In Part 3 we will start putting everything together.</div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #0000a3; background-color: #149902}
</style></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-18916411333450010212020-06-21T00:32:00.000-07:002020-06-21T00:32:16.735-07:00The Falcon DS1 - BeagleBone Blue Drone (Part 1)<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Flight Controller</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ7UtAmvCWOdRFHnOyudSDpFqYcBZMgS64fhIDC6LjHI3BotH3fTZk80uZR9kFnJmxOhuRZ94DpePuRF_HeaIoUBKMEadOtQIB9P7QFWXzrFnbyEOw15a1CHbzahkcj8iR0MNPhxKtFI2r/s1600/beagle-blue-pck.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1118" data-original-width="1600" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ7UtAmvCWOdRFHnOyudSDpFqYcBZMgS64fhIDC6LjHI3BotH3fTZk80uZR9kFnJmxOhuRZ94DpePuRF_HeaIoUBKMEadOtQIB9P7QFWXzrFnbyEOw15a1CHbzahkcj8iR0MNPhxKtFI2r/s400/beagle-blue-pck.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 1. BeagleBone Blue Flight Controller</span></div>
<br />
<br />
This project will document the construction of a self built drone using the BeagleBone Blue as a flight controller.<br />
<br />
An objective of the build was that the drone should be modular, open sourced hardware and software and include an API to allow mission control.<br />
<br />
My preference would be to use a board that I already have experience with (e.g. Arduino or Raspberry Pi) as a flight controller.<br />
<br />
Unfortunately even though ArduCopter firmware was originally designed for the Arduino, the consensus seems to be that it doesn’t have enough grunt these days (ref: <a href="https://dojofordrones.com/drone-flight-controller/">https://dojofordrones.com/drone-flight-controller/</a>).<br />
<br />
I like the Navio2 & Raspberry Pi, as the hardware platform for the flight controller. The only problem is that it is expensive ($299 for the HAT alone). Also the Navio2 is not open source hardware.<br />
<br />
The PXFmini is a pHAT designed for the Raspberry Pi Zero/Raspberry Pi Zero W but is also compatible with other models from the Raspberry Pi family. It was more affordable (approx. $74) but is now discontinued. The good news is that it is open source hardware and the schematics are available. You could develop your own HAT or pHAT based on this design. It would be great to get hold of one but I haven’t been able to track it down. An issue with this design is that all the soldering is surface mount, which is a pain without the right gear (and great eye sight).<br />
<br />
I haven’t used the BeagleBone, but the BeagleBone Blue looks like a pretty good option. It is relatively cheap at $130 delivered and includes most of the sensors you need on the board. The exception is a GPS (the recommended module is the u-blox M8N GPS - $60 from Hobby King). There is an ArduCopter build available for the BeagleBone.<br />
<br />
Based on the above I am going to try out the BeagleBone for my initial prototype. The build documentation is very sketchy, so there is going to be a bit of trial and error.<br />
<div>
<br /></div>
<h3 style="text-align: left;">
Air Frame</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgExxn-tyNAePWJlGX6GPyJeNXp74AGWnj5jNAz6aFyrBDSC2n9HPp_1KSSAeET_jByZpoQ71f_FrMTx-aiDC5mR-EstSpEZxKAwr13KfMOvVb_Nmwm1u-ba_DKxlk-9gwRAstGXhIZy4oB/s1600/IMG_2174.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgExxn-tyNAePWJlGX6GPyJeNXp74AGWnj5jNAz6aFyrBDSC2n9HPp_1KSSAeET_jByZpoQ71f_FrMTx-aiDC5mR-EstSpEZxKAwr13KfMOvVb_Nmwm1u-ba_DKxlk-9gwRAstGXhIZy4oB/s400/IMG_2174.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 2. Power Distribution Board on frame.</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
For my prototype I propose using a Martian II 220mm frame, because that is what BeagleBone suggest in their <a href="https://beagleboard.org/p/jkridner/beaglebone-blue-220mm-quadcopter-9801d8#cad">half documented project</a>. Half documented is probably generous, apparently they never actually got this design flying, nevertheless there is nothing like a challenge to get the juices flowing!</div>
<div>
<br /></div>
<div>
There is a 3D printable case, designed for the BeagleBone for use on a drone, available from <a href="https://www.thingiverse.com/thing:2343741">Thingiverse</a> (Figure 3).</div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi34OjpG1Ei6cTIjyW7VdGVFR_i1EkJjOChsq-ocl71fJXiv8_zDR4D0z6f_CV1GRYbzhgy0n_UYNB7KhW3f1bv8xTjlNhPaYfLwCuOaikSugs_g7eQtSdtfb3ZVJbFXYdjS9l0zEXfqep8/s1600/Screen+Shot+2019-07-03+at+6.09.50+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="383" data-original-width="629" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi34OjpG1Ei6cTIjyW7VdGVFR_i1EkJjOChsq-ocl71fJXiv8_zDR4D0z6f_CV1GRYbzhgy0n_UYNB7KhW3f1bv8xTjlNhPaYfLwCuOaikSugs_g7eQtSdtfb3ZVJbFXYdjS9l0zEXfqep8/s400/Screen+Shot+2019-07-03+at+6.09.50+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 3. BeagleBone drone mounting case.</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
There are <a href="https://www.youtube.com/watch?v=EZ3U5K7NTsY">plenty of videos documenting how to build the Martian II air frame</a> and its various clones so I wont go into that in detail, except where you need to do something different to utilise the BeagleBone. This happens pretty early in the build.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RlrzvMSQMXYIceJwkjkvnphwKRZCmg2ROpFXaQrcd2XgUglhnqY4SBH0O3Wj0UFOx-aDZyHV0JKGxosIt7WQHeCOO0prir3BNY8VAUh2k4-3BYHDMGjn-jpqCA9_UKnbVLLumFxsOdZd/s1600/IMG_2177.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RlrzvMSQMXYIceJwkjkvnphwKRZCmg2ROpFXaQrcd2XgUglhnqY4SBH0O3Wj0UFOx-aDZyHV0JKGxosIt7WQHeCOO0prir3BNY8VAUh2k4-3BYHDMGjn-jpqCA9_UKnbVLLumFxsOdZd/s400/IMG_2177.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 4. Airframe with front and motor numbers.</span></div>
<br /></div>
<div>
<br /></div>
<div>
The first thing that you will notice is that the yellow XT60 socket mounted on the power distribution board (Figure 2) prevents you from using the 3D printed case in Figure 3. So we need to do some modifications.<br />
<br />
It is a good idea to mark your air frame with the forward direction and motor numbers (Figure 4). This will assist with layout and help ensure that you mount boards in the correct locations.</div>
<div>
<br /></div>
<h3 style="text-align: left;">
Technology Stack</h3>
<div>
<br /></div>
<div>
The proposed technology stack is shown in Figure 5. We now need to work out the specifics, there wont be a camera in the initial build, in fact my first objective is just to get things working on the bench. I will then be in a better position to work out where the various modules can fit on the airframe. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIgs0qDO6C9BsstWkMti7JnvLecz7jBsOZhQ6PZOad48WQ6R6cBekCfGr7gIr9lnefxiNo0__mo2SAWuxuiaLB3as7hXYYPOL_iptsXqkbW6g6Qu9lSXCnuNpA8aPweKmQVXoQ5KdYi-mL/s1600/Slide1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIgs0qDO6C9BsstWkMti7JnvLecz7jBsOZhQ6PZOad48WQ6R6cBekCfGr7gIr9lnefxiNo0__mo2SAWuxuiaLB3as7hXYYPOL_iptsXqkbW6g6Qu9lSXCnuNpA8aPweKmQVXoQ5KdYi-mL/s400/Slide1.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 5. Falcon Drone Technology Stack.</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3 style="text-align: left;">
Power Distribution</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2HVgbvBk2cyC4ulJmd6cPFqFQklFG5g26Ep3CtWW8OYmWu3veyAXbEsSbZoz3L8o8Nbnn5FFkwjP4wKakesYe3HaEycVW0NYQ5f7YqJ4DpGdXLwqyFdOeuKvBBBI2azqvWLpNyUBjoW9p/s1600/IMG_2180.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2HVgbvBk2cyC4ulJmd6cPFqFQklFG5g26Ep3CtWW8OYmWu3veyAXbEsSbZoz3L8o8Nbnn5FFkwjP4wKakesYe3HaEycVW0NYQ5f7YqJ4DpGdXLwqyFdOeuKvBBBI2azqvWLpNyUBjoW9p/s400/IMG_2180.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 6. Turnigy 1300mAh 2S 20C Lipo Pack</span></div>
<br />
<br />
All of the drones power comes from our 2S 1300 mAh Lithium Polymer battery (Figure 6). The specifications for our battery are:<br />
<br />
Minimum Capacity: 1300mAh<br />
Configuration: 2S1P / 7.4v / 2Cell<br />
Constant Discharge: 20C<br />
Peak Discharge (10sec): 30C<br />
Pack Weight: 81g<br />
Pack Size: 73 x 35 x 17mm<br />
Charge Plug: JST-XH<br />
Discharge plug: XT60<br />
<br />
At 3.7V per cell our 2S battery will deliver a nominal 7.4V from the contacts on the power distribution board. The 2S indicates that we have two cells in series so the sum of the two cells voltage is the output voltage. As an aside, cells in parallel add to the batteries capacity (i.e. mAh) not voltage.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9hDWwLmmv3ItD4eTIKxl67U4g3nUmP1BTZaGlAL3PeCVat85xPHQvUFLOzU2v5AHc4jEwTZJoaYEyqhtqMcAJZnFeypp5GbU8s3MlYMv2M_Zy5dMTFrxWmHwTcqP5_VV5wkuSQI3-K17N/s1600/IMG_2181.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9hDWwLmmv3ItD4eTIKxl67U4g3nUmP1BTZaGlAL3PeCVat85xPHQvUFLOzU2v5AHc4jEwTZJoaYEyqhtqMcAJZnFeypp5GbU8s3MlYMv2M_Zy5dMTFrxWmHwTcqP5_VV5wkuSQI3-K17N/s400/IMG_2181.jpeg" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 7. BeagleBone connected to LiPo</span></div>
<br />
The BeagleBone Blue includes a 2-cell LiPo battery charger with balancing, and an LED state-of-charge monitor. The state of charge LED's are shown in Figure 7. They are just above the 3-pin JST XH battery charging connector.<br />
<br />
One of our considerations when mounting the BeagleBone is that we will need access to the JST XH connector in order to get power off the micro-controller. We will also need access to the XT60 in order to power down the distribution board. Ideally the battery needs to be less than 50mm from the BeagleBone or we will need to extend the charging cables.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFuLAACbczt-b3vQb-YJ8Nc2YlBxvekLRvP1ZyITntZ-ggCukd-D2srSCkcihVkSe5UY4jUL2vkJTW5vYAUdpgMbl14mc3FsVOBF2L24NRfkzDsS1SfT4fSxrU0XQhIGcsrDvLWgAEJIKf/s1600/Screen+Shot+2019-07-22+at+6.30.18+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="431" data-original-width="600" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFuLAACbczt-b3vQb-YJ8Nc2YlBxvekLRvP1ZyITntZ-ggCukd-D2srSCkcihVkSe5UY4jUL2vkJTW5vYAUdpgMbl14mc3FsVOBF2L24NRfkzDsS1SfT4fSxrU0XQhIGcsrDvLWgAEJIKf/s400/Screen+Shot+2019-07-22+at+6.30.18+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 8. Racerstar Quad 20A ESC.</span></div>
<br />
The other modules we will need to power are:<br />
<br />
<ul style="text-align: left;">
<li>The Racerstar BLHeli_S 20A Quad Electronic Speed Control - shown in Figure 8 (connects to the battery, receiver and the four motors). It doesn't have a BEC (Battery Elimination Circuit) to provide a regulated supply but the BeagleBone does.</li>
<li>The UBLOX Micro M8N GPS Compass Module - shown in Figure 9. This module expects a regulated 5V on VCC but control voltages are 3.3V (see Figure 10). The BeagleBone supplies 3.3VDC and 5VDC power output via 4 pin JST connector.</li>
<li>The FrSKY X8R 2.4Ghz SBUS Receiver. The receiver will also need to be connected to the regulated 5VDC bus.</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ9QRCY485CDA4fmENYPxh7sGqa3lAwRIWp5CSnsMDLQlMP42QnGB79Bm9CzWusvfhkrSeFG0b2bBCY2m1wo9j11_0EPVW5VdXVvKD-Fe768jl61Oh7-wrSFItFYqYifH7iF3TlnMYwX4k/s1600/86436_high.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="416" data-original-width="566" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQ9QRCY485CDA4fmENYPxh7sGqa3lAwRIWp5CSnsMDLQlMP42QnGB79Bm9CzWusvfhkrSeFG0b2bBCY2m1wo9j11_0EPVW5VdXVvKD-Fe768jl61Oh7-wrSFItFYqYifH7iF3TlnMYwX4k/s400/86436_high.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 9. <span style="text-align: left;">The UBLOX Micro M8N GPS Compass Module.</span></span></div>
<br />
<br />
The overall power distribution block diagram is shown in Figure 11. The 3 wire LiPo charging cable will connect directly to the BeagleBone as mentioned above. We will then have two power buses, 7.4VDC which powers the ESC and 5VDC to power the GPS and Receiver modules.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdpJrd6_G8SoIv3NPFO_OGCCsmuznf3KfXk4Hm_ytyKcDuMeqStiASUnQj_GCgQzqKcqR-vG_h7XGBv4TbVljeG7PaJTTSlkm7FKVEIzgEXseSp4fm8kEYfVRIAJkZkcy_KPFe3cgZfwDj/s1600/Screen+Shot+2019-07-22+at+6.48.25+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="178" data-original-width="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdpJrd6_G8SoIv3NPFO_OGCCsmuznf3KfXk4Hm_ytyKcDuMeqStiASUnQj_GCgQzqKcqR-vG_h7XGBv4TbVljeG7PaJTTSlkm7FKVEIzgEXseSp4fm8kEYfVRIAJkZkcy_KPFe3cgZfwDj/s1600/Screen+Shot+2019-07-22+at+6.48.25+pm.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 10. GPS Compass Module connections.</span></div>
<br />
<br />
When building robots I have had problems when there is a common supply for the motors and the micro-controller. The current surge when starting the motor can bring down the voltage to the micro-controller and cause it to reboot. It may not be an issue with the drone since the motors are always on. The bench test will demonstrate whether this is going to be a problem.<br />
<br />
In part 2 we will cover the control wiring required for our drone.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM7z0hdDSU5rkCbtqgmsdEusyL9NuVAEMH1HAFU4ypwftfOjdbymN8oxpyfGpwxwo_HP33XlYwTR_JRI4Mnt-48s8K06gK1i5-ehtqiiph9D5vdlScizo8dpIOrrMSjKkQ7U8GDtc1beBN/s1600/Slide2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM7z0hdDSU5rkCbtqgmsdEusyL9NuVAEMH1HAFU4ypwftfOjdbymN8oxpyfGpwxwo_HP33XlYwTR_JRI4Mnt-48s8K06gK1i5-ehtqiiph9D5vdlScizo8dpIOrrMSjKkQ7U8GDtc1beBN/s400/Slide2.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 11. Falcon DS1 Power Distribution.</span></div>
<br />
<h3 style="text-align: left;">
</h3>
</div>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-12467550356794726202020-05-26T01:27:00.000-07:002020-05-26T15:45:28.460-07:00Arduino ESC Tester - Adding DShot<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
The Arduino Servo/ESC Tester Series (Part 4)</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-5n9Phhd6Zyi07DqeuU9wLci9EhICbo_XbXe-FrJJmFAUrQgBmN6wjexEBduT5B8lO2nBEIKyXNm91EPNpSdP-Eh4t8QadSRpMVEZGb4qbeSHZiX5jNzC0DkNPVxuBTEDFZPe9wFTWGTl/s1600/IMG_0762.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-5n9Phhd6Zyi07DqeuU9wLci9EhICbo_XbXe-FrJJmFAUrQgBmN6wjexEBduT5B8lO2nBEIKyXNm91EPNpSdP-Eh4t8QadSRpMVEZGb4qbeSHZiX5jNzC0DkNPVxuBTEDFZPe9wFTWGTl/s400/IMG_0762.jpeg" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. Arduino & Tester Shield.</div>
<br />
<br />
In our <a href="https://medium.com/@reefwing/multiprotocol-esc-servo-tester-using-the-altronics-megabox-f11333c65e41">first article</a> in this series, we built a prototype ESC/Servo Tester using the Altronics MegaBox as our hardware platform. We followed this up with <a href="https://medium.com/@reefwing/arduino-shield-multiprotocol-esc-servo-tester-55e36ff162b9">an article using a custom Arduino shield</a> to make construction cheaper and easier. In <a href="https://medium.com/@reefwing/arduino-esc-tester-adding-fast-pwm-and-oneshot125-20690f9f42f1">Part 3 we added the Fast PWM and OneShot</a> protocols.<br />
<div style="text-align: left;">
<span style="background-color: white; color: #333333; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13px;"><br /></span></div>
In this final article we will add the DShot protocol and show the tester in action. By protocol, we are referring to the agreed communication method between the Flight Controller and the ESC. One of the issues we found was that there doesn't appear to be a single document which clearly defines what the Dshot protocol is. We have tried to pull all the available information together here, and explain how Dshot operates.<span style="background-color: white; color: #333333; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13px;"><br /></span>
<br />
<br />
<h3 style="text-align: left;">
Synchronous vs Asynchronous Serial Protocols</h3>
<br />
Before leaping into DShot, it is useful to review other serial protocols to see how it compares.<br />
<br />
Most serial digital communication protocols (e.g. RS232, OneWire, RS485, SPI, and I2C) require fairly precise timing in order to determine which bit is being read. We can further break down serial protocols into synchronous and asynchronous. Synchronous protocols require a separate wire for the clock signal (Figure 2) in addition to the data lines. Examples of synchronous serial communication are I2C and SPI. On the ATMega328P, SPI is the fastest synchronous communication interface allowing data transfer speeds up to half of the core clock (i.e. 8 MHz on an UNO).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvbagZyYUvlg1Qtqxe5845Br0B5QOuRxt4OT6HB_J4ZbIzr6xEREzgCtw_OGVdXN11EiiIqk3RI1eMvzXJrYCFKbVuFFBYVpqwbnqV7BZshIYPYkXOG6lxH5Z0OFhwuQO7p717oUN8v5IP/s1600/Synchronous-Serial-Communication.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="282" data-original-width="398" height="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvbagZyYUvlg1Qtqxe5845Br0B5QOuRxt4OT6HB_J4ZbIzr6xEREzgCtw_OGVdXN11EiiIqk3RI1eMvzXJrYCFKbVuFFBYVpqwbnqV7BZshIYPYkXOG6lxH5Z0OFhwuQO7p717oUN8v5IP/s400/Synchronous-Serial-Communication.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 2. Synchronous Serial Data (<a href="https://circuitdigest.com/tutorial/serial-communication-protocols" target="_blank">credit</a>)</div>
<br />
With an asynchronous Serial Interface, the external clock signal is absent (Figure 3). This is useful when we need to transmit over longer distances. With asynchronous communication you need to know when a packet starts and stops (start bit and stop bit) and the baud rate (i.e. when to expect the next bit). Common examples of asynchronous serial protocols are RS-232, RS-422 and RS-485. Spoiler alert - DShot is an asynchronous serial protocol.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXo4KYyCMDpFgzVf6w_fvLD1r8YWSOmk3QZ1TwkxVgt-xV5FQCjGukauvcxjD_ZSlq13XNavxu4SQfFyFkOAaJTrM2kwVVicl834xTQc1H9lKlxq6bt1kljyzpQsfA05CIHfc9R9Fv4ice/s1600/Asynchronous-Serial-Communication.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="197" data-original-width="447" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXo4KYyCMDpFgzVf6w_fvLD1r8YWSOmk3QZ1TwkxVgt-xV5FQCjGukauvcxjD_ZSlq13XNavxu4SQfFyFkOAaJTrM2kwVVicl834xTQc1H9lKlxq6bt1kljyzpQsfA05CIHfc9R9Fv4ice/s400/Asynchronous-Serial-Communication.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 3. Asynchronous Serial Data (<a href="https://circuitdigest.com/tutorial/serial-communication-protocols" target="_blank">credit</a>)</div>
<br />
<h3 style="text-align: left;">
A Review of DShot</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpIhHZoApI6-JPt89Pkena1pbgMoHMZbsAf3ZcKjyuuHtt8DMIJy7Mrg0cKQa5LuTDDIU3tfx9OYonKQFMdffir-Koh3tx3P739OIFNMGpDM3YNhtdjd5gv1Q4YOKHMCtxy4b5ixY1hMd4/s1600/Screen+Shot+2020-05-17+at+11.09.57+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="223" data-original-width="416" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpIhHZoApI6-JPt89Pkena1pbgMoHMZbsAf3ZcKjyuuHtt8DMIJy7Mrg0cKQa5LuTDDIU3tfx9OYonKQFMdffir-Koh3tx3P739OIFNMGpDM3YNhtdjd5gv1Q4YOKHMCtxy4b5ixY1hMd4/s320/Screen+Shot+2020-05-17+at+11.09.57+am.png" width="320" /></a></div>
<br />
In case you haven't read the previous articles in our series (*gasp*), here is a quick review of the DShot ESC protocol. DShot stands for Digital Shot and is the proposed replacement for previous analogue protocols like PWM, OneShot and MultiShot. DShot was developed by Flyduino in collaboration with Betaflight.<br />
<div>
<br /></div>
<div>
Compared to the protocols already considered, DShot is the only one which is truly digital. You could argue that PWM and OneShot are also digital since they use pulses with encoded data but the point is moot. PWM protocols, such as Multishot, Oneshot42, and Oneshot125 rely on the width of the pulse to indicate throttle position. This can introduce issues like jitter where timing variations cause errors in the desired throttle speed. The shorter the protocol pulse width the higher the likelihood and impact of jitter.<br />
<br />
A comparison of the theoretical data rates for OneShot and DShot are shown in Figure 4. DShot is almost as fast as Multishot v1. The advantage of DShot over OneShot is not so much about speed but reliability and flexibility. Moving to a fully digital protocol allows the introduction of error correction and bi-directional data flow. In addition, with DShot no ESC calibration is required. Calibration is about tweaking the PWM pulse width which isn't required with a digital protocol. The final advantage of DShot is higher throttle value resolution (2000 steps), which should lead to smoother control.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjELOx-J143YR8R82EGd2g1_Oq-R-p-WYH6gvbwUgoSNbN6_hgCaeW2qhFIauM6LQ0A8JaOZULOO-rIbxj7ONZ-O8DNNQHYwKobve1xMGNWuyj3u4IrhUmU9IlyNPCC3YFNDHHUPkdiWtjL/s1600/difference-bet-oneshot-and-multishot-768x339.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="339" data-original-width="768" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjELOx-J143YR8R82EGd2g1_Oq-R-p-WYH6gvbwUgoSNbN6_hgCaeW2qhFIauM6LQ0A8JaOZULOO-rIbxj7ONZ-O8DNNQHYwKobve1xMGNWuyj3u4IrhUmU9IlyNPCC3YFNDHHUPkdiWtjL/s400/difference-bet-oneshot-and-multishot-768x339.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 4. DShot vs OneShot (<a href="https://robu.in/what-is-oneshot-and-multishot-in-esc-difference-between-oneshot-and-multishot-esc-esc-calibration-protocol/" target="_blank">credit</a>)</div>
<div>
<br /></div>
<div>
<div>
A DShot digital message (Figure 5) consists of 16 bits (called a frame) in three parts, throttle value (11 bits), telemetry request (1 bit) and the CRC checksum (4 bits).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLZ2mawzJm8vhx2hjwIrPk18hlBRq2zFzhVCAmCfpre_UZdp5VV6yeHReyjAafU52Lk0TPnBaZ1lCxyGzlYAuGCArOdTEc4z5pJ-Xp0KSu34jWBCHXGueagJfIUZ5KCYsNjMbK31it2OqY/s1600/Dshot_logo_kiss_flyduino-1024x379.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="379" data-original-width="1024" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLZ2mawzJm8vhx2hjwIrPk18hlBRq2zFzhVCAmCfpre_UZdp5VV6yeHReyjAafU52Lk0TPnBaZ1lCxyGzlYAuGCArOdTEc4z5pJ-Xp0KSu34jWBCHXGueagJfIUZ5KCYsNjMbK31it2OqY/s400/Dshot_logo_kiss_flyduino-1024x379.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 5. DShot Message Format (<a href="https://blog.seidel-philipp.de/dshot-digital-esc-signal/" target="_blank">credit</a>)</div>
<br />
Figure 6 shows a DShot message captured on an oscilloscope. Details on the three components of the DShot packet are as follows:<br />
<br />
<ol style="text-align: left;">
<li>The <b>throttle</b> contains 11-bit data sent from the flight controller to the ESC. It gives a resolution of 2000 throttle values. The values 0-47 are reserved for special commands (see enum code listing below), 48-2047 are for throttle control, and 0 is for disarming. In the throttle portion of the frame the most significant bits are first, consequently the bit sequence 11111111111 represents full throttle, and 10000000000 represents half throttle. In standard mode, code 48 (0b110000) is the lowest throttle setting and code 2047 (0b11111111111) is the highest throttle setting, for a full range of 2000 throttle settings.</li>
<li>The <b>telemetry</b> bit is set if the flight controller signals a telemetry update to the ESC. The telemetry update uses a separate return wire. </li>
<li>The <b>checksum</b> comprises a 4-bit CRC value. The checksum is calculated using CRC12, and is calculated over the throttle and telemetry request bit. The exact methodology is explained below.</li>
</ol>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj26TR11nk959fE3ttjEFBXeXFHJaA303PiC6Tz2vuUjEcAlTbDMpBpnkMf0jBLUj-eq0MEog_bSf6FRmQd-qyX5kbzG4CNI6IRNTk2UW54Rld5oBYEZ0IAmVZETG-03kl16R6tXN5T9Ah4/s1600/dshot.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="675" data-original-width="1200" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj26TR11nk959fE3ttjEFBXeXFHJaA303PiC6Tz2vuUjEcAlTbDMpBpnkMf0jBLUj-eq0MEog_bSf6FRmQd-qyX5kbzG4CNI6IRNTk2UW54Rld5oBYEZ0IAmVZETG-03kl16R6tXN5T9Ah4/s400/dshot.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 6. DShot message on oscilloscope (<a href="https://www.rcgroups.com/forums/showthread.php?2756129-Dshot-testing-a-new-digital-parallel-ESC-throttle-signal" target="_blank">credit</a>)</div>
<br />
The 47 special reserved commands in the throttle value can be seen in the source code of betaflight:<br />
<br />
<pre class="source-code" id="yui_3_17_2_1_1589701760522_163" style="background-color: white; color: #5c5c5c; font-family: monospace, monospace; font-size: 14px; overflow-wrap: break-word; overflow: auto;">//this typedef taken from src\main\drivers\pwm_output.h in the betaflight github page
typedef enum {
DSHOT_CMD_MOTOR_STOP = 0,
DSHOT_CMD_BEACON1,
DSHOT_CMD_BEACON2,
DSHOT_CMD_BEACON3,
DSHOT_CMD_BEACON4,
DSHOT_CMD_BEACON5,
DSHOT_CMD_ESC_INFO, // V2 includes settings
DSHOT_CMD_SPIN_DIRECTION_1,
DSHOT_CMD_SPIN_DIRECTION_2,
DSHOT_CMD_3D_MODE_OFF,
DSHOT_CMD_3D_MODE_ON,
DSHOT_CMD_SETTINGS_REQUEST, // Currently not implemented
DSHOT_CMD_SAVE_SETTINGS,
DSHOT_CMD_SPIN_DIRECTION_NORMAL = 20,
DSHOT_CMD_SPIN_DIRECTION_REVERSED = 21,
DSHOT_CMD_LED0_ON, // BLHeli32 only
DSHOT_CMD_LED1_ON, // BLHeli32 only
DSHOT_CMD_LED2_ON, // BLHeli32 only
DSHOT_CMD_LED3_ON, // BLHeli32 only
DSHOT_CMD_LED0_OFF, // BLHeli32 only
DSHOT_CMD_LED1_OFF, // BLHeli32 only
DSHOT_CMD_LED2_OFF, // BLHeli32 only
DSHOT_CMD_LED3_OFF, // BLHeli32 only
DSHOT_CMD_AUDIO_STREAM_MODE_ON_OFF = 30, // KISS audio Stream mode on/Off
DSHOT_CMD_SILENT_MODE_ON_OFF = 31, // KISS silent Mode on/Off
DSHOT_CMD_SIGNAL_LINE_TELEMETRY_DISABLE = 32,
DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_TELEMETRY = 33,
DSHOT_CMD_MAX = 47
} dshotCommands_e;</pre>
<br />
Notes on the Special Commands (<a href="https://www.swallenhardware.io/battlebots/2019/4/20/a-developers-guide-to-dshot-escs" target="_blank">credit</a>):<br />
<ol style="text-align: left;">
<li>If you change any settings with DShot commands, you have to issue the save settings command for them to take effect;</li>
<li>To change the spin direction, set 3D mode, or save settings you must enable the telemetry bit in the associated command packet, and you must issue the command 10 times in a row for the command to take effect.</li>
<li>If you issue command 0 and the ESC is not armed, it arms the ESCs with the throttle ranges set. If the ESC is armed it stops the motors. This command should be used if you want the motor to be stopped. If you try to use a throttle setting to stop the motor, it still spins slowly.</li>
<li>If you stop sending commands, the ESC disarms. I haven’t timed the required update rate, but it’s pretty fast (10ms or less). </li>
</ol>
<br />
There are four types (or protocol modes) of DShot, differentiated by their speed of connection:<br />
<ul style="text-align: left;">
<li>DShot150 – 150 kbits per second or 9375 Hz update frequency</li>
<li>DShot300 – 300 kbits per second or 18.75 kHz update frequency</li>
<li>DShot600 – 600 kbits per second or 37.5 kHz update frequency</li>
<li>DShot1200 – 1,200 kbits per second or 75 kHz update frequency</li>
</ul>
<br />
The maximum practical ESC update frequencies (i.e. Flight Controller loop frequencies) are substantially slower than the theoretical update rates above:<br />
<ul style="text-align: left;">
<li>DShot150: 4.05 kHz max</li>
<li>DShot300: 8.09 - 10.6 kHz max (10.6 kHz is only available on 32 kHz gyro boards)</li>
<li>DShot600: 16.0 kHz max</li>
<li>DShot1200: >32.0 kHz max (Currently only KISS24 supports DSHOT1200)</li>
</ul>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0R6-mcOo-HXkLgTrL0iUj9p0i2c6MaOTbPInuMAcsZwIPjk4jxmG2NsWiml2kukPBIs3qYahJopsGlVbQSrNvVXXJF9FGXbCEwxquD-8ea-hTc2AwYaTb5FZgkKb9K-Nrt2954MuLN4Le/s1600/Screen+Shot+2020-05-17+at+11.57.05+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="430" data-original-width="677" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0R6-mcOo-HXkLgTrL0iUj9p0i2c6MaOTbPInuMAcsZwIPjk4jxmG2NsWiml2kukPBIs3qYahJopsGlVbQSrNvVXXJF9FGXbCEwxquD-8ea-hTc2AwYaTb5FZgkKb9K-Nrt2954MuLN4Le/s400/Screen+Shot+2020-05-17+at+11.57.05+am.png" width="400" /></a></div>
<div class="" style="clear: both; text-align: center;">
Figure 7. DShot Pulse Width according to mode (<a href="https://www.speedgoat.com/help/slrt/page/io_main/refentry_dshot_usage_notes" target="_blank">credit</a>)</div>
<br />
In our discussion about asynchronous serial protocols, we noted that the baud rate was critical in determining bit values. This is not as important for DShot because the bit value (1 or 0) is determined by the pulse width as a proportion of the total period. In other words, the duty cycle. Bits 1 and 0 are represented by a 74.850% and 37.425% duty cycle respectively.<br />
<br />
As detailed in Figures 7 and 8, the signals for 0 and 1 are distinguished by their different high times, and the bit period is constant for each protocol mode. For example, with DShot600<br />
<br />
<ul style="text-align: left;">
<li>Bit length (Period Time) is 1.67 microseconds = (T0H + T0L or T1H + T1L).</li>
<li>For a bit to be 0, the pulse width is 625 nanoseconds (T0H – time the pulse is high for a bit value of ZERO)</li>
<li>For a bit to be 1, the pulse width is 1250 nanoseconds (T1H – time the pulse is high for a bit value of ONE)</li>
</ul>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD6TYKQ6ILPy6JXtEUvong-F2fT0XMjLqaNHyizcGKivSyRDoGzL3IEZefAS-Jf-gsUmZvainOfRWifdoi5bFBmO8ekrX3hidvYaxSPm7_lVhiiTP_hFZvq8tb1JeMFOMXE6suuQJ602Cn/s1600/dshot-sequence.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="157" data-original-width="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD6TYKQ6ILPy6JXtEUvong-F2fT0XMjLqaNHyizcGKivSyRDoGzL3IEZefAS-Jf-gsUmZvainOfRWifdoi5bFBmO8ekrX3hidvYaxSPm7_lVhiiTP_hFZvq8tb1JeMFOMXE6suuQJ602Cn/s1600/dshot-sequence.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 8. DShot Sequence Chart (<a href="https://blck.mn/2016/11/dshot-the-new-kid-on-the-block/" target="_blank">credit</a>)</div>
<br />
The reason for the difference in pulse length for 0 and 1 is that it allows for some tolerance when determining the value. So these timings can be off slightly and the result will still be the same.<br />
<br />
Unlike a number of other asynchronous serial protocols, DShot has no start or stop bit. Instead, there is normally a pause between frames of at least 2 microseconds (recommended reset time is 21 bits) to indicate a frame reset. A reset simply indicates the end of one frame and thus any future bits are the start of a new frame. With DShot occurring at the end of a Flight Controller PID loop this pause is actually considerably longer. If DShot were to be made to continuously output a signal then this delay would be required.<br />
<br />
<h3 style="text-align: left;">
DShot Compatible Flight Controllers & ESC's</h3>
<br />
Any ESC that comes with BLHeli_S or KISS 24A (v1.02 or higher) firmware should support DShot.<br />
<br />
A list of flight controllers tested to support DShot on Betaflight 3.1 is provided on the <a href="https://github.com/betaflight/betaflight/wiki/DSHOT-ESC-Protocol" target="_blank">Betaflight Github repository</a>.</div>
<div>
<br /></div>
<div>
<h3 style="text-align: left;">
Generating DShot on an Arduino UNO</h3>
<br />
Our first issue is that most flight controllers use Direct Memory Access (DMA) to generate the DShot frames. DMA allows hardware subsystems to access main system memory without using the MPU. You can think of DMA as a co-processor that is used to transfer data between main memory and peripherals without the intervention of the MPU. The advantage of this is that MPU cycles are not wasted on DShot communication and can focus on the flight controlling PID loop. A lot of the ESC's use DMA as well.<br />
<br />
The problem is that the ATMega328P MPU does not have DMA - so neither does the Arduino UNO. The Arduino DUE has DMA but we are not using that board. There are three approaches to generating DShot on the UNO that we could find:<br />
<br />
<b>1. Use The UNO Hardware SPI (Serial Peripheral Interface)</b><br />
Remember how the duration of the ON and OFF states in DShot are different. This is not generally how serial protocols work but you can use four SPI bytes to construct one DShot bit. This is a bit of a hack and there are a few problems with this:<br />
<ul style="text-align: left;">
<li>We didn't break out the SPI pins on our custom shield (doh!);</li>
<li>It uses up your SPI port which may be used for something else (in theory you can have multiple devices on the SPI bus but that is probably not practical - if this is an issue then approach 2 may be the answer);</li>
<li>You can only connect one ESC (not a problem for our tester but it would be if you were using the code for a quadcopter);</li>
<li>Timing is a problem. As mentioned, DShot has some tolerance on pulse timing but there is at least a 250 nS pause (two clock pulses - 16 MHz clock divided by 2 for each pulse) between bytes in a SPI transmission. In practise, we measured a 0.5 μs delay between bytes (Figure 11).</li>
</ul>
Nevertheless, I thought it was worth attempting this approach to see if it would work. If necessary we could modify the shield and I wanted to make some other changes to the layout anyway. Let me explain the theory behind the code. Figure 8 illustrates the bit pattern that we are attempting to replicate. We will start with DShot150 since being the slowest mode it should give us the best chance of success. The required bit timings for DShot150 (Figure 7) are:<br />
<br />
<ul style="text-align: left;">
<li>T1H = 5 μs</li>
<li>T0H = 2.5 μs</li>
<li><span style="background-color: white; color: #333333; font-family: "arial" , "tahoma" , "helvetica" , "freesans" , sans-serif; font-size: 13px;">T (Period) = T1H / </span>74.850% = 6.68 μs</li>
</ul>
<br />
So the period of each SPI bit needs to be 6.68 / 3 = 2.23 μs (i.e a frequency 0.45 MHz). The default frequency setting for SPI is to use the system clock speed (16 MHz) divided by four, that is, one SPI clock pulse every 250 ns. You can change the SPI frequency by setting the divider to one of the following options:<br />
<br />
<ul style="text-align: left;">
<li>SPI_CLOCK_DIV2</li>
<li>SPI_CLOCK_DIV4</li>
<li>SPI_CLOCK_DIV8</li>
<li>SPI_CLOCK_DIV16</li>
<li>SPI_CLOCK_DIV32</li>
<li>SPI_CLOCK_DIV64</li>
<li>SPI_CLOCK_DIV128</li>
</ul>
<br />
<div>
The fastest rate is "divide by 2" or one SPI clock pulse every 125 ns. We need:</div>
<div>
<br /></div>
<div>
divider = 16 (clock speed in MHz) / 0.45 = 35.6</div>
<div>
<br /></div>
<div>
This doesn't really work as the closest available divider is 32. We are better of using a divider of 4 (i.e. a SPI frequency of 4 MHz) which gives us a SPI bit period of 0.25 μs. This period divides evenly into T1H and T0H. It also happens to be the default.</div>
<div>
<br />
<ul style="text-align: left;">
<li>T1H = 5 μs = 20 ON SPI bits</li>
<li>T1L = T - T1H = 7 OFF SPI bits</li>
<li>T0H = 2.5 μs = 10 ON SPI bits</li>
<li>T0L = T - TOH = 17 OFF SPI bits</li>
<li>T = 6.68 μs ≅ 27 SPI bits (actually 26.7, we may need to tweak this. We will need 4 SPI bytes for every DShot bit)</li>
</ul>
</div>
<div>
<br /></div>
<div>
The other important thing for us to set is the bit data order. The DShot protocol expects MSB first. Our SPI initalisation code is thus:</div>
<br />
<pre style="background-color: moccasin;"><code style="font-size: larger;">SPI.beginTransaction (SPISettings (4000000, MSBFIRST, SPI_MODE0));</code></pre>
<br />
The final parameter in the SPI initialisation is the clock mode. We are not using the clock signal or expecting a response, so it doesn't matter what you set here but for completeness, the options are:<br />
<br />
<ul style="text-align: left;">
<li><b>Mode 0</b> (the default) - clock is normally low (CPOL = 0), and the data is sampled on the transition from low to high (leading edge) (CPHA = 0)</li>
<li><b>Mode 1</b> - clock is normally low (CPOL = 0), and the data is sampled on the transition from high to low (trailing edge) (CPHA = 1)</li>
<li><b>Mode 2</b> - clock is normally high (CPOL = 1), and the data is sampled on the transition from high to low (leading edge) (CPHA = 0)</li>
<li><b>Mode 3</b> - clock is normally high (CPOL = 1), and the data is sampled on the transition from low to high (trailing edge) (CPHA = 1)</li>
</ul>
<br />
<div>
To test our code and allow us to measure the results, we will repeatedly send the same DShot frame with a delay between frames. The test frame will consist of:<br />
<br />
Throttle = 10101010101<br />
Telemetry = 0<br />
Checksum = 1010 (See Calculating the DShot Checksum below)<br />
<br />
There is normally a pause between frames of at least 2 microseconds and the recommended reset time is 21 bits. We will delay for 200 μs (i.e. plenty of space between frames).<br />
<br />
In the test sketch we are calculating the check sum every time we loop. Since the frame isn't changing we could just do this once in setup() or even hard code the check sum value, but for the ESC tester this frame will be changing and we will need to update the check sum each time that it does. By including it here we will be able to see if it creates a timing issue.<br />
<br />
As described in the <a href="https://gist.github.com/reefwing/e2598bd6dd394c0fe0e3e150d7eeeff2" target="_blank">DShot SPI Test Sketch</a> and explained above, for the Arduino UNO (16MHz CPU):<br />
<br />
<ul style="text-align: left;">
<li>DShot LOW (0) = 10 SPI bits ON, 17 SPI bits OFF = 0x07FE 0000</li>
<li>DShot HIGH (1) = 20 SPI bits ON, 7 SPI bits OFF = 0x07FF FF80</li>
</ul>
<br />
Thus there is a total of 27 SPI bits for every DShot bit. In practise we are using 32 SPI bits (4 bytes) sent 16 bits at a time.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKyXc216sTkjKdFXMrceQkh5SRoyf9MdPlwAyOwPUPI3BxDW9diyw_B7LmcUfhG77dJkTnn3xKyPLnqFcYVayujxEQ2F9WOh_c0sM8fOnQK2nDbzQQ8OuTOybCZ3myYnFPx1vnyhmTeQic/s1600/Screen+Shot+2020-05-22+at+5.48.35+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="196" data-original-width="1480" height="52" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKyXc216sTkjKdFXMrceQkh5SRoyf9MdPlwAyOwPUPI3BxDW9diyw_B7LmcUfhG77dJkTnn3xKyPLnqFcYVayujxEQ2F9WOh_c0sM8fOnQK2nDbzQQ8OuTOybCZ3myYnFPx1vnyhmTeQic/s400/Screen+Shot+2020-05-22+at+5.48.35+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 9. A DShot ON bit = 20 SPI bits ON & 7 SPI bits OFF = 0x07FF FF80</div>
<br />
Looking at the protocol analyser (Figure 9) we can see that this sort of works. Channel 0 on the analyser is SS (SPI Enable). This goes low at the start of transmission as expected.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibIIQJiZonkirhkb7QSteE7GtxKH8Y-px9HTLJOjd-p65b-muQ0tSTWFW2nCr2fmeThYiEHIYL_qNyuTr6mSE6qOMfpo1E1DocMtUgZQzOGBG0JTcK-Q9lTJwUTL8nDs4n0OJkCgxQ5Y4l/s1600/Screen+Shot+2020-05-22+at+6.13.44+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="315" data-original-width="522" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibIIQJiZonkirhkb7QSteE7GtxKH8Y-px9HTLJOjd-p65b-muQ0tSTWFW2nCr2fmeThYiEHIYL_qNyuTr6mSE6qOMfpo1E1DocMtUgZQzOGBG0JTcK-Q9lTJwUTL8nDs4n0OJkCgxQ5Y4l/s400/Screen+Shot+2020-05-22+at+6.13.44+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 10. DShot ON (First 16 SPI Bits = 0x07FF)</div>
<br />
It is hard to see the details in Figure 9, so we have split it up and zoomed in (Figures 10 and 11). Notice that even using the SPI.transfer16() command, there is a 0.5 μs delay between bytes as illustrated by the gap in the clock signal (channel 2 in Figure 11). Between every 16 bits there is another 1.3 μs delay. The length of a DShot "bit" is 8.7 μs. We were aiming for 6.7 μs. Most of this difference we can attribute to the delays between sending bytes.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgApACMbTlo-pL_HYSGrwjCJSlo5mit8aQWI1nG9UbBjt-XK5OWKCdEfJ1lRsPyiZLKPh_HRxnbLpvKrktq9EXOr5Ttd1JUJya3DFt9dxNOUh6RqGG1QoWNfgkoKa3Impj3zoUL8e_37Hj-/s1600/Screen+Shot+2020-05-22+at+6.20.54+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="357" data-original-width="491" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgApACMbTlo-pL_HYSGrwjCJSlo5mit8aQWI1nG9UbBjt-XK5OWKCdEfJ1lRsPyiZLKPh_HRxnbLpvKrktq9EXOr5Ttd1JUJya3DFt9dxNOUh6RqGG1QoWNfgkoKa3Impj3zoUL8e_37Hj-/s400/Screen+Shot+2020-05-22+at+6.20.54+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 11. DShot ON (Second 16 SPI Bits = 0xFF80)</div>
<br />
The important thing with DShot is the duty cycle. Bits 1 and 0 should be represented by a 74.850% and 37.425% duty cycles respectively. We measured the relevant high and low bit components (Figure 12) and found:<br />
<br />
<ul style="text-align: left;">
<li>T1H = 7 μs (should be 5 μs)</li>
<li>T1L = 1.7 μs (correct)</li>
</ul>
<br />
<br />
The second LOW bit is messed up because we are seeing voltage spikes on the SS line.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit_iHNtZ_aiFxSy1T1nUc0NbtszoCBMiy8oy_RHxD9rYyQZSbPMh4quvxmGsMYoMkGDyn-51exsJx6bxKfXR2Pp2hScruxakcAw6iKrHGn9ry3STAvA3ZtEwl5YHrGnURjCLgMUuisZls4/s1600/Screen+Shot+2020-05-23+at+3.12.48+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="319" data-original-width="394" height="323" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit_iHNtZ_aiFxSy1T1nUc0NbtszoCBMiy8oy_RHxD9rYyQZSbPMh4quvxmGsMYoMkGDyn-51exsJx6bxKfXR2Pp2hScruxakcAw6iKrHGn9ry3STAvA3ZtEwl5YHrGnURjCLgMUuisZls4/s400/Screen+Shot+2020-05-23+at+3.12.48+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 12. DShot T1H</div>
<br />
At this point we gave up on the SPI approach. As we will see in Approach 3, the bit banging methodology gives a much better frame pattern, runs at DShot600 and we can use it on any digital pin, so there is no need to adjust the ESC tester hardware.</div>
<br />
<b>2. Additional SPI Port using USART</b><br />
This is similar to Approach 1. For most Arduino devices, using the USART (Universal Serial Asynchronous Receiver Transmitter) in SPI mode is a way of generating a hardware-timed stream of bits out of one pin. This gives the UNO an additional SPI port. Unfortunately the UNO only has one serial port and it is used for programming and debugging. This option is better on the Arduino variants with more than one serial port (e.g. the Mega2560 which has four). Example code for using the <a href="https://feilipu.me/2015/02/17/avr-atmega-usart-spi-mspim/" target="_blank">USART in “Master SPI Mode” (MSPIM) is available here</a>.<br />
<br />
<b>3. Bit Banging</b><br />
Bit banging is slang for any method of data transmission that employs software as a substitute for dedicated hardware. In our case we are managing all the details of DShot communication, unlike SPI or USART for example which as shown in Figures 13 and 14, have dedicated hardware in the MPU to facilitate communication.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0CTns3CCQqrL-NEUCslKp0JsoRcpKppirXdTPu-zVRF4I5jEJt7YVyraLqCddG6FUOJJAliGycDmzJhl57mc5CfRO2yJvErYdAJhuQH3a912wX-qicWn-gU43XXa-_O7bPK7MQQJSmFsC/s1600/Screen+Shot+2020-05-19+at+4.33.07+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="653" data-original-width="429" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0CTns3CCQqrL-NEUCslKp0JsoRcpKppirXdTPu-zVRF4I5jEJt7YVyraLqCddG6FUOJJAliGycDmzJhl57mc5CfRO2yJvErYdAJhuQH3a912wX-qicWn-gU43XXa-_O7bPK7MQQJSmFsC/s400/Screen+Shot+2020-05-19+at+4.33.07+pm.png" width="261" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 13. ATMega328P Block Diagram (<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf" target="_blank">credit</a>)</div>
<br />
<a href="https://github.com/gueei/DShot-Arduino" target="_blank">Andy Tsui has written a DShot library for the Arduino</a>, so lets compare the output of this bit banging with our SPI test.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikP_DsyG1mqzrdDnwPq_9zmQYR2ZrpxwBQpadjfp0HWutCqfQf3KjYQxXTNrpotwNl940hFZZTlHbAu8-mro0DHwaU1oY9kbQjXOPMvJxbta1PTIF9ZvbxCoiU7SrL9Tp2OO4Ij1yzzZyp/s1600/Screen+Shot+2020-05-19+at+4.43.55+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="443" data-original-width="462" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikP_DsyG1mqzrdDnwPq_9zmQYR2ZrpxwBQpadjfp0HWutCqfQf3KjYQxXTNrpotwNl940hFZZTlHbAu8-mro0DHwaU1oY9kbQjXOPMvJxbta1PTIF9ZvbxCoiU7SrL9Tp2OO4Ij1yzzZyp/s400/Screen+Shot+2020-05-19+at+4.43.55+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 14. SPI Hardware Block Diagram in the ATMega328P (<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf" target="_blank">credit</a>)</div>
<br />
The DShot packet produced by Andy's DShot library is shown in Figure 15. The results are so consistent that you can read the packet bits just by looking at it (1010101010101010). When using the DShot library you only pass the throttle value, the telemetry bit is fixed at 0 and the checksum is calculated within the library. This does mean that you can't use the telemetry request feature of DShot but it wouldn't be hard to tweak the library if you needed it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLg5FTGwzzeE2Qmhpk4REmUNaOHUkM-Q3qrZDMYvlPmo0BQxhVGxCycfBRKP_oTInkee39RgNiPdA09uTo0iq3c9VF46juLlGjJ3qAbAYE7hmwhOtb28BjKdgu81ppugefeiWsFNApj9fK/s1600/DShot_Packet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="301" data-original-width="467" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLg5FTGwzzeE2Qmhpk4REmUNaOHUkM-Q3qrZDMYvlPmo0BQxhVGxCycfBRKP_oTInkee39RgNiPdA09uTo0iq3c9VF46juLlGjJ3qAbAYE7hmwhOtb28BjKdgu81ppugefeiWsFNApj9fK/s400/DShot_Packet.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 15. Dshot frame produced by library</div>
<br />
Comparing the timing of the library bits against theory we find:<br />
<br />
<ul style="text-align: left;">
<li>T1H = 1.3μs (Figure 16 - theoretically 1.25 μs)</li>
<li>T1L = 0.3 μs (Figure 16 - theoretically 0.42 μs)</li>
<li>T0H = 0.7 μs (Figure 17 - theoretically 0.625 μs)</li>
<li>T0L = 1.0 μs (Figure 17 - theoretically 1.045 μs)</li>
</ul>
<br />
The results are good and there are no unwanted delays between bytes as with SPI.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO8N6rafs5WRk7re2obwKi5Jh11O9xl2-xlsLjUD_qewtv8iSUyyK3w_1Et5kgmK8JQrp3pS3AZuAZpBamYzJDYGBcEFxmI0EtpRhcdihfh7aq4TN9EhtDUAuNkRKNyP3SW7_JJoRPSvHL/s1600/DShot_HIGH.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="253" data-original-width="283" height="357" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO8N6rafs5WRk7re2obwKi5Jh11O9xl2-xlsLjUD_qewtv8iSUyyK3w_1Et5kgmK8JQrp3pS3AZuAZpBamYzJDYGBcEFxmI0EtpRhcdihfh7aq4TN9EhtDUAuNkRKNyP3SW7_JJoRPSvHL/s400/DShot_HIGH.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 16. DShot HIGH bit (T1H = W, T1L = 𝜏 - W).</div>
<br />
If you want to produce DShot on the UNO then this library is definitely the way to go. This is the approach that we have used for our Tester.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzUSHkNi3hx6pqEgAHFhl6OIczUy_z0AiV_sDT04xPLdYqiCexGajbadBdREfOFvfvt77saDP-oQkkxAgUOnXjJkCNGxCsNA4GC2391rGD9_vmQ9Q5jHIpDNkuAYFB9jgnzDNp9H2iQtCA/s1600/DShot_LOW.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="290" data-original-width="308" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzUSHkNi3hx6pqEgAHFhl6OIczUy_z0AiV_sDT04xPLdYqiCexGajbadBdREfOFvfvt77saDP-oQkkxAgUOnXjJkCNGxCsNA4GC2391rGD9_vmQ9Q5jHIpDNkuAYFB9jgnzDNp9H2iQtCA/s400/DShot_LOW.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 17. DShot LOW bit (T0H = W, T0L = 𝜏 - W).</div>
<br />
<br />
<h3 style="text-align: left;">
Calculating the DShot Checksum</h3>
<br />
There are LOTS of different <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check" target="_blank">ways that a CRC checksum can be calculated</a>. Like just about everything else with the DShot protocol this needs to be reverse engineered. The algorithm in Figure 18 is taken from the <a href="https://github.com/cleanflight/cleanflight/blob/bd523ced7cc3a8c000068cca08da96eff43716a1/src/main/drivers/pwm_output.c#L405-L414" target="_blank">cleanflight/betaflight source code</a>.<br />
<br />
This code starts with 0 and XOR's the 12 bits of our packet (11 throttle bits + 1 telemetry request bit) with that (which wont change anything since, 0 XOR 0 = 0 and 1 XOR 0 = 1). The code then right-shifts the data by four bits and XOR's the result with the value obtained in the previous step. It does this for each nibble (4 bits) in our packet (i.e. three times).<br />
<br />
<pre class=" prettyprinted" style="background: rgb(238, 238, 238); box-sizing: inherit; color: #3c3c3c; font-family: "Courier 10 Pitch", Courier, monospace; font-size: 0.9375rem; line-height: 1.6; margin-bottom: 1.6em; max-width: 100%; overflow: auto; padding: 1.6em;"><span class="com" style="box-sizing: inherit; color: #880000;">// compute checksum</span><span class="pln" style="box-sizing: inherit; color: black;">
</span><span class="kwd" style="box-sizing: inherit; color: #000088;">int</span><span class="pln" style="box-sizing: inherit; color: black;"> csum </span><span class="pun" style="box-sizing: inherit; color: #666600;">=</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">0</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;">
</span><span class="kwd" style="box-sizing: inherit; color: #000088;">int</span><span class="pln" style="box-sizing: inherit; color: black;"> csum_data </span><span class="pun" style="box-sizing: inherit; color: #666600;">=</span><span class="pln" style="box-sizing: inherit; color: black;"> packet</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;">
</span><span class="kwd" style="box-sizing: inherit; color: #000088;">for</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="pun" style="box-sizing: inherit; color: #666600;">(</span><span class="kwd" style="box-sizing: inherit; color: #000088;">int</span><span class="pln" style="box-sizing: inherit; color: black;"> i </span><span class="pun" style="box-sizing: inherit; color: #666600;">=</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">0</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;"> i </span><span class="pun" style="box-sizing: inherit; color: #666600;"><</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">3</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;"> i</span><span class="pun" style="box-sizing: inherit; color: #666600;">++)</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="pun" style="box-sizing: inherit; color: #666600;">{</span><span class="pln" style="box-sizing: inherit; color: black;">
csum </span><span class="pun" style="box-sizing: inherit; color: #666600;">^=</span><span class="pln" style="box-sizing: inherit; color: black;"> csum_data</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="com" style="box-sizing: inherit; color: #880000;">// xor data by nibbles</span><span class="pln" style="box-sizing: inherit; color: black;">
csum_data </span><span class="pun" style="box-sizing: inherit; color: #666600;">>>=</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">4</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;">
</span><span class="pun" style="box-sizing: inherit; color: #666600;">}</span><span class="pln" style="box-sizing: inherit; color: black;">
csum </span><span class="pun" style="box-sizing: inherit; color: #666600;">&=</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">0xf</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span><span class="pln" style="box-sizing: inherit; color: black;">
</span><span class="com" style="box-sizing: inherit; color: #880000;">// append checksum</span><span class="pln" style="box-sizing: inherit; color: black;">
packet </span><span class="pun" style="box-sizing: inherit; color: #666600;">=</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="pun" style="box-sizing: inherit; color: #666600;">(</span><span class="pln" style="box-sizing: inherit; color: black;">packet </span><span class="pun" style="box-sizing: inherit; color: #666600;"><<</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="lit" style="box-sizing: inherit; color: #006666;">4</span><span class="pun" style="box-sizing: inherit; color: #666600;">)</span><span class="pln" style="box-sizing: inherit; color: black;"> </span><span class="pun" style="box-sizing: inherit; color: #666600;">|</span><span class="pln" style="box-sizing: inherit; color: black;"> csum</span><span class="pun" style="box-sizing: inherit; color: #666600;">;</span></pre>
<div style="text-align: center;">
Figure 18. Calculating the DShot (4 bit) Checksum.</div>
<div style="text-align: center;">
<br /></div>
<h3 style="text-align: left;">
The Tester Code</h3>
<br />
You can <a href="https://gist.github.com/reefwing/fc728913c1c77187a87f221c4581892b" target="_blank">download the updated Servo/ESC Tester sketch</a> with DShot functionality from the Reefwing Gist.<br />
<br />
One thing to check is that the pin you want to use is on PORTD (D0-D7) for the UNO or PORTB (D8-D11) for the Leonardo. These are the default port allocations for the library. If you are connecting more than one ESC, these need to be all attached to pins on the same port.<br />
<br />
For our tester, we are using D9 for the PWM output and this is the only pin with a header on our arduino shield. PORTB maps to Arduino UNO digital pins 8 to 13 The two high bits (6 & 7) map to the crystal pins and are not usable.<br />
<br />
Thus in our sketch we have to define the DShot port as PORTB. We found that defining this in the sketch didn't work, so we modified the library to use Port B.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); line-height: 1.1em; padding: 1em;"><span style="color: #333333; font-family: monospace , "courier";"><span style="font-size: 12.7px;">#define DSHOT_PORT PORTB</span></span></pre>
<br />
The other issue is that our PWM code is using Timer1 in a different manner to the DShot library. In other words there is a conflict. The ATMega328P has a couple of other timers. Timer 0 is used by the Arduino millis() and delay() functions, so we won't use that since we are using delay().<br />
<br />
To address this issue we will modify the DShot library to use Timer 2. This is an 8 bit timer, whereas Timer 1 is a 16 bit timer. The DShot library is using the timer to send out packets with a frequency of 1 kHz. They used the <a href="http://www.8bit-era.cz/arduino-timer-interrupts-calculator.html" target="_blank">Arduino Timer Interrupts Calculator</a> to generate ISR code which fires 1,000 times a second (1 kHz). We can use this same site to generate code which uses Timer 2.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); line-height: 1.1em; padding: 1em;"><span style="color: #333333; font-family: monospace , "courier";"><span style="font-size: 12.7px;"><span style="color: magenta;">static void</span><span style="color: #333333;"> </span><span style="color: blue;">initISR</span><span style="color: #333333;">(){
// TIMER 2 for interrupt frequency 1000 Hz:
cli(); // stop interrupts
TCCR2A = 0; // set entire TCCR2A register to 0
TCCR2B = 0; // same for TCCR2B
TCNT2 = 0; // initialize counter value to 0
// set compare match register for 1000 Hz increments
OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
// turn on CTC mode
TCCR2B |= (1 << WGM21);
// Set CS22, CS21 and CS20 bits for 64 prescaler
TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
sei(); // allow interrupts
}</span></span></span></pre>
<br />
In addition to changing the ISR initialisation code we also need to change the ISR to refer to the appropriate Timer 2 vector.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); line-height: 1.1em; padding: 1em;"><span style="color: #333333; font-family: monospace , "courier";"><span style="font-size: 12.7px;"><span style="color: blue;">ISR</span><span style="color: #333333;">(TIMER2_COMPA_vect){
sendData();
}</span></span></span></pre>
<br />
To test our modifications to the DShot library we used the following sketch. The DShot data stream is on Pin D9. The output was identical to Figure 15.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); line-height: 1.1em; padding: 1em;"><span style="color: #333333; font-family: monospace , "courier";"><span style="font-size: 12.7px;"><span style="color: #38761d;">#include</span><span style="color: #333333;"> <DShotTimer2.h></span><span style="color: #333333;">
DShot esc;
</span><span style="color: blue;">uint16_t</span><span style="color: #333333;"> throttle = 0b10101010101; // 0x555 or 1365 Decimal (68% throttle)
</span><span style="color: blue;">void</span><span style="color: #333333;"> setup() {
esc.</span><span style="color: #b45f06;">attach</span><span style="color: #333333;">(9);
esc.setThrottle(0);
}
</span><span style="color: blue;">void</span><span style="color: #333333;"> loop() {
esc.setThrottle(throttle);
</span><span style="color: #b45f06;">delay</span><span style="color: #333333;">(10);
}</span></span></span></pre>
<br />
Because we are using a common pin for DShot and PWM, we need to be able to disable DShot once we return to the home menu of the ESC Tester. To do this we detach interrupts from pin D9 and set timerActive to false. To be able to do this, we added a new public function to the DShot library called setTimerActive(bool active).<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); line-height: 1.1em; padding: 1em;"><span style="color: #333333; font-family: monospace , "courier";"><span style="font-size: 12.7px;"><span style="color: blue;">void</span><span style="color: #333333;"> DShot::setTimerActive(</span><span style="color: blue;">bool</span><span style="color: #333333;"> active){
timerActive = active;
}</span></span></span></pre>
<br />
<div class="graf graf--p">
You can <a class="markup--anchor markup--p-anchor" data-href="https://gist.github.com/reefwing" href="https://gist.github.com/reefwing" rel="noopener" target="_blank"><strong class="markup--strong markup--p-strong">download a copy of the modified DShot library using Timer 2</strong></a> from the Reefwing Gist. You will need 2 files:</div>
<ul class="postList">
<li class="graf graf--li" name="0032"><a class="markup--anchor markup--li-anchor" data-href="https://gist.github.com/reefwing/fb3e7c3f09031aafd44e3f25ec30e7e0" href="https://gist.github.com/reefwing/fb3e7c3f09031aafd44e3f25ec30e7e0" rel="noopener" target="_blank">DShotTimer2.h</a>; and</li>
<li class="graf graf--li" name="3ec7"><a class="markup--anchor markup--li-anchor" data-href="https://gist.github.com/reefwing/8a08d0fbe063540f313dea5062b79203" href="https://gist.github.com/reefwing/8a08d0fbe063540f313dea5062b79203" rel="noopener" target="_blank">DShotTimer2.cpp</a>.</li>
</ul>
<div class="graf graf--p" name="30e5">
Make a copy of the original DShot Library in your Arduino libraries folder. Name the new library DShotTimer2. Replace the two files in the src directory with those you have downloaded.</div>
</div>
</div>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com1tag:blogger.com,1999:blog-1323683415527527391.post-48568103442106083342020-05-05T23:57:00.000-07:002020-05-05T23:57:51.491-07:00Arduino ESC Tester - Adding Fast PWM and OneShot125<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
The Arduino Servo/ESC Tester Series (Part 3)</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrvMDx73CugaX_QHR4H0XrMzHUEXn8DP-R_0lUknQ-EyAWYXCSahEUftXBGRDfHU4-ctclG-H0P1mnvN9zqgKCrpwWTFkHhn95FHa_u9KB7CU4IpoLmzITfF29MBnhIjJU6-NU4ZKH9Oxv/s1600/IMG_0694.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrvMDx73CugaX_QHR4H0XrMzHUEXn8DP-R_0lUknQ-EyAWYXCSahEUftXBGRDfHU4-ctclG-H0P1mnvN9zqgKCrpwWTFkHhn95FHa_u9KB7CU4IpoLmzITfF29MBnhIjJU6-NU4ZKH9Oxv/s400/IMG_0694.jpeg" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. Arduino and Tester Shield mounted in 3D printed enclosure.</div>
<br />
<br />
In our <a href="https://medium.com/@reefwing/multiprotocol-esc-servo-tester-using-the-altronics-megabox-f11333c65e41" target="_blank">first article</a> in this series, we built a prototype Servo Tester using the Altronics MegaBox as our hardware platform. We followed this up with <a href="https://medium.com/@reefwing/arduino-shield-multiprotocol-esc-servo-tester-55e36ff162b9" target="_blank">an article using a custom Arduino shield</a> to make construction cheaper and easier.<br />
<br />
As shown in Figure 1, we have created a 3D printed case for the shield version of our tester. You can download the STL files for the base, lid and LCD mount from Thingiverse. The LCD mounting bracket and hinges are connected using M3 bolts and nuts.<br />
<br />
If we do another version of this shield, I would do a few things differently. These include:<br />
<br />
<ul style="text-align: left;">
<li>Moving the group of 15 tester pin headers away from the left hand hinge, towards the centre of the PCB.</li>
<li>Moving the LCD connector towards the top of the PCB (or use a 90 degree connector) to allow the LCD mount to close like a lid.</li>
<li>Move the potentiometer a bit further towards the front of the PCB.</li>
<li>Break out the D13 LED onto the shield.</li>
<li>Adding four mounting holes to the PCB and use this as the lid to the box.</li>
</ul>
<br />
Our previous prototypes only provided PWM output at varying frequencies (50 Hz, 125 Hz and 250 Hz). In this article we will add PWM 490 Hz and the OneShot125 protocol to our tester. This will be used for testing ESC's which utilise this protocol.<br />
<br />
<h3 style="text-align: left;">
PWM 490 Hz (Fast PWM)</h3>
<br />
In standard PWM the maximum pulse width is 2 ms, so the highest theoretical frequency using this control strategy is 500 Hz. To get pulse separation, the practical upper limit is 490 Hz.<br />
<br />
Adding this protocol is very easy. In <a href="https://medium.com/@reefwing/multiprotocol-esc-servo-tester-using-the-altronics-megabox-f11333c65e41" target="_blank">part 1 of our series</a> we found that the simplest way to output PWM is to use the <b>analogWrite</b>(pin, dutyCycle) command. The ATmega328P PWM default frequency is 490 Hz for all PWM capable pins (3, 9, 10 and 11), with the exception of pins 5 and 6, whose default frequency is 980 Hz.<br />
<br />
We tested this using our protocol analyser and found that a 50% duty cycle [<b>analogWrite</b>(9, 127)] provides PWM with a 1.016 ms pulse width and a frequency of 490 Hz.<br />
<br />
For our existing shield sketch we may as well continue to use the register method of setting PWM frequency. The formula that we derived in Part 1 gives us the value for ICR1 at a particular PWM frequency:<br />
<br />
ICR1 = 1MHz / fPWM = 1MHz / 490 = 2040<br />
<br />
Setting the ICR1 register to this value should give us PWM at 490 Hz. Updating the sketch accordingly, we measured the output on our protocol analyser (Figure 2). We ended up with a PWM frequency very close to 490 Hz. The updated code will be provided at the end of the article.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb6q_h3WuvXA6n2ULT167m_qU5lU9Hm0wVUJaELlmOpMt2DH8A6yz62RbB_Vf_Up7r5qyRKr5HM2WVlV7wExjPWqJO0_PNaaSlEfooE16ff2gcSyCxRl38gpGGC2OGkE4oQV2Xle6O-Qbz/s1600/Screen+Shot+2020-04-03+at+6.51.13+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="130" data-original-width="500" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb6q_h3WuvXA6n2ULT167m_qU5lU9Hm0wVUJaELlmOpMt2DH8A6yz62RbB_Vf_Up7r5qyRKr5HM2WVlV7wExjPWqJO0_PNaaSlEfooE16ff2gcSyCxRl38gpGGC2OGkE4oQV2Xle6O-Qbz/s400/Screen+Shot+2020-04-03+at+6.51.13+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 2. Output for PWM 490 Hz</div>
<br />
We also tried connecting the 9G Servo to see if it would work at this frequency. It did to a certain extent but there was a LOT of jitter. The servo is expecting a nominal frequency of 50 Hz so these results are not surprising.<br />
<br />
<h3 style="text-align: left;">
What is an ESC?</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjErxOepWGPOACI-FFvj-pYWEs0i1Soz9FVgQoJ1pg2cqb79Ucritj4q2wZZlFY2gDYo80iRlLj1sHt3TEtlMsuH6RuawNwdllfWOLPFeXd4lowsJH3XXFHbOoFXet60zsrQinX0ZZ_ugM/s1600/HTB1JQl5OVXXXXa1aXXXq6xXFXXXJ.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1000" data-original-width="1000" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjErxOepWGPOACI-FFvj-pYWEs0i1Soz9FVgQoJ1pg2cqb79Ucritj4q2wZZlFY2gDYo80iRlLj1sHt3TEtlMsuH6RuawNwdllfWOLPFeXd4lowsJH3XXFHbOoFXet60zsrQinX0ZZ_ugM/s320/HTB1JQl5OVXXXXa1aXXXq6xXFXXXJ.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 3. An example of an ESC.</div>
<br />
An Electronic Speed Control or ESC is an electronic circuit that controls and regulates the speed of an electric motor. ESC's come in many different packages, one version is shown in Figure 2.<br />
<br />
ESC's contain a microcontroller which take an input (e.g. direction or speed from a flight controller) and convert this to the appropriate motor control output. The flight controller (or ESC tester in our case), communicates with the ESC using an ESC protocol. The available protocols depend on the ESC firmware being used. Some examples of ESC firmware are:<br />
<br />
<ul style="text-align: left;">
<li>BLHeli ESC.</li>
<li>BLHeli_S ESC.</li>
<li>SimonK ESC.</li>
<li>Kiss.</li>
<li>BLHeli_32.</li>
</ul>
<br />
The ESC in Figure 3 is encapsulated in yellow heatshrink. The 3 x blue leads with bullet connectors, go to the brushless motor that is being controlled. With brushless motors, the speed of the motor is varied by adjusting the timing of pulses of current delivered to the windings of the motor. The ESC effectively creates three-phase AC power to deliver these pulses.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-oQl_-2clBe0pUknT4jmVb88i1-cQl1ER-robYLZr8Pxhbb_L1uMngaNJcs92BB7k3vjlqas0Kz3RMa74zFRbNf4IrxwS2lAlJzwsgKMgyufekxKpfypsdqWrVldzla_4bcOczSBepRjr/s1600/Slide04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-oQl_-2clBe0pUknT4jmVb88i1-cQl1ER-robYLZr8Pxhbb_L1uMngaNJcs92BB7k3vjlqas0Kz3RMa74zFRbNf4IrxwS2lAlJzwsgKMgyufekxKpfypsdqWrVldzla_4bcOczSBepRjr/s400/Slide04.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 4. Example ESC control wiring.</div>
<br />
In Figure 3, the thick red and black wires (ending in a male Deans T-plug) connect to the LiPo batteries and the 3 smaller wires (white, black and red) are for the ESC control (white) and to provide a regulated 5 VDC (red and black). Not all ESC's provide this regulated 5 VDC (also called a Battery Eliminator Circuit or BEC).<br />
<br />
An example of how an ESC is used in a quadcopter design is shown in Figure 4. This design uses a quad ESC (i.e. four ESC's mounted on one PCB), controlled by a Beaglebone Blue flight controller.<br />
<br />
The idea is that our ESC tester can be used in place of the flight controller, to allow us to test each part of the system separately.<br />
<br />
<h3 style="text-align: left;">
What is OneShot?</h3>
<br />
The OneShot125 protocol consists of:<br />
<ul style="text-align: left;">
<li>A single pulse (hence the name OneShot) with the new response required (this is different to PWM which is a stream of pulses);</li>
<li>Pulse width is between 125 µs (stop) and 250 µs (full power). This is where the 125 in the name comes from.</li>
</ul>
Oneshot comes in three varieties:<br />
<ul style="text-align: left;">
<li>Oneshot125 (pulse width 125-250 μs, maximum frequency 4 kHz); </li>
<li>Oneshot42 (pulse width 42-84 μs, maximum frequency 11.9 kHz); and </li>
<li>Multishot (pulse width 5-25 μs, maximum frequency 40 kHz). </li>
</ul>
<br />
OneShot125 was created by Flyduino and is supported by flight controllers which use Cleanflight, Betaflight, Raceflight and Kiss. From an ESC perspective you will need SimonK, BLHeli rev13, or KISS firmware.<br />
<br />
OneShot42 was also developed by Flyduino as part of their KISS FC and ESC program. It is not widely supported at the moment.<br />
<br />
Out of the three varities in the OneShot stable, Multishot is the fastest ESC protocol. To take advantage of this it requires a fast flight controller and ESC processor. It was developed by RaceFlight and again is not widely supported.<br />
<br />
The Raceflight firmware and Multishot protocol were introduced by RS2K (RCGroups user). Raceflight is a fork (or branch) of Betaflight, meaning it used the original Betaflight code and was modified for the purpose of F4 flight controller targets.<br />
<br />
<h3 style="text-align: left;">
How about DShot?</h3>
<br />
Compared to the protocols already considered, DShot is the only one which is truly digital. You could argue that PWM and OneShot are also digital since they use pulses with encoded data but the point is moot. A comparison of the theoretical data rates for OneShot and Dshot are shown in Figure 5. The advantage of DShot over OneShot is not so much about speed but reliability and flexibility. Moving to a fully digital protocol allows the introduction of error correction and bi-directional data flow.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxgrSe-1nGiPsyRAEyxKd2sgk_XOpKSf_gT9vE8lef7bq7Exr3i_LJzG_dgS8DILU30hpSnJU74vDVMkEGX2AMLTztS5u78rI_J38aI6Rs-Fb0o4hHJNsXwsQFgDSXZKhDZ_VUGK8RCiS5/s1600/difference-bet-oneshot-and-multishot-768x339.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="339" data-original-width="768" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxgrSe-1nGiPsyRAEyxKd2sgk_XOpKSf_gT9vE8lef7bq7Exr3i_LJzG_dgS8DILU30hpSnJU74vDVMkEGX2AMLTztS5u78rI_J38aI6Rs-Fb0o4hHJNsXwsQFgDSXZKhDZ_VUGK8RCiS5/s400/difference-bet-oneshot-and-multishot-768x339.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 5. DShot vs OneShot</div>
<br />
<br />
A DShot digital message consists of 16 bits in three parts, throttle value (11 bits), telemetry request (1 bit) and the CRC checksum (4 bits). The telemetry request asks for data back from the ESC on models that support it. Transmission of telemetry data is done on a different wire. Any ESC that comes with BLHeli_S firmware should support DShot.<br />
<br />
There are four types of DShot, differentiated by their speed of connection:<br />
<br />
<ul style="text-align: left;">
<li>DShot150 – 150 kbits per second or 9375 Hz update frequency</li>
<li>DShot300 – 300 kbits per second or 18.75 kHz update frequency</li>
<li>DShot600 – 600 kbits per second or 37.5 kHz update frequency</li>
<li>DShot1200 – 1,200 kbits per second or 75 kHz update frequency</li>
</ul>
<br />
We will look at developing DShot capability for our ESC Tester in a subsequent article.<br />
<br />
<h3 style="text-align: left;">
Is OneShot125 better than standard PWM?</h3>
<br />
In our <a href="https://medium.com/@reefwing/multiprotocol-esc-servo-tester-using-the-altronics-megabox-f11333c65e41" target="_blank">original article</a> in this series, we talked about how PWM is used to control a servo. TLDR - a 1 ms pulse width equates to stop and a 2 ms pulse width = full power. As mentioned above, the theoretical fastest refresh rate is 1 / 2ms = 500 Hz. In practice it is more like 490 Hz as you need some gap between the pulses. A consequence of this is that there is no point your flight controller running faster than 490 Hz since we can only update the motor control at this rate.<br />
<br />
By reducing the pulse width band to 125 - 250 µs, OneShot125 is theoretically eight times faster than PWM 490 Hz. A consequence of this faster update speed is no jitter in your controls. Jitter is caused when your flight model updates quicker than your ESC can respond. With OneShot125, your flight controllers PID loop can update eight times faster than Fast PWM.<br />
<br />
A comparison of Fast PWM and OneShot is shown in Figure 6.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizoSpnGSIwif2NqvLTNiA6teXfjv-C_H0KaN8MOSEsD9eQrn9a0ZV0C8TQsHPtYQdk6WFHjUTkbRWbzJk2M95xPNyrHmZovrYVx9ZJmyHoROKhLrhcHIwhn_kDXOw2sZmZsZpqQepGMFZB/s1600/Screen+Shot+2020-05-05+at+12.35.54+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="379" data-original-width="503" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizoSpnGSIwif2NqvLTNiA6teXfjv-C_H0KaN8MOSEsD9eQrn9a0ZV0C8TQsHPtYQdk6WFHjUTkbRWbzJk2M95xPNyrHmZovrYVx9ZJmyHoROKhLrhcHIwhn_kDXOw2sZmZsZpqQepGMFZB/s400/Screen+Shot+2020-05-05+at+12.35.54+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 6. Fast PWM vs OneShot</div>
<br />
<br />
<h3 style="text-align: left;">
Programming OneShot125 for the Arduino UNO</h3>
<br />
Using our approach to date we would send continuous OneShot125 pulses in the 125 - 250 µs range (see Figure 6) as we have done for the previous PWM solutions, but that is not how OneShot operates. OneShot sends one pulse when the throttle information changes.<br />
<br />
However, we are not writing flight controller software but an ESC tester. The ESC wont care if it gets repeated pulses with the same value. So for simplicity we will produce a stream of pulse at a frequency of about 1 kHz. The pulse width will be between 125 - 250 µs, based on the potentiometer position (simulating the throttle input).<br />
<br />
Taking this approach allows us to reuse a lot of our exisiting code. If you need a more purist solution then you can use the <a href="https://forum.arduino.cc/index.php?topic=520395.0" target="_blank">OneShot125 code written for the Arduino Mega which is available on the Arduino forum</a>.<br />
<br />
Once again, the formula that we derived in Part 1 gives us the value for ICR1 at a particular PWM frequency:<br />
<br />
ICR1 = 1MHz / fPWM = 1MHz / 1kHz = 1000<br />
<br />
Setting the ICR1 register to this value should give us PWM at 1 kHz. The only other changes we need to make are to the minimum and maximum pulse widths. Register OCR1A can then be set to the required pulse width between 125 and 250.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinXi6BhYi0c_uz7iCeLJRddees0zgo5CoIWp22LiMYPYzL-Wu3asXB3BkSacYaj5sqwAc8SEDPXrKVtTO6fXhaPVaPgVOO2Js3mH9ON0kzRKOb1RnoCdP0BMmVzIow3b2gqxvLz7CWve-P/s1600/IMG_0746.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinXi6BhYi0c_uz7iCeLJRddees0zgo5CoIWp22LiMYPYzL-Wu3asXB3BkSacYaj5sqwAc8SEDPXrKVtTO6fXhaPVaPgVOO2Js3mH9ON0kzRKOb1RnoCdP0BMmVzIow3b2gqxvLz7CWve-P/s400/IMG_0746.jpeg" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 7. OneShot125 with pulse width set to 193 <span style="text-align: left;">µs</span></div>
<br />
<br />
Connecting the output of our Servo/ESC tester to our protocol analyser provides the output shown in Figures 7 and 8. As expected we get a pulse width of 193 µs at a frequency of 1kHz.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv7h_0MnvS_17G8jbKGOK5pcMmgHp6RG5jrMZs9hbGYGv__OsG8xast7y2iTby4f2RgQDpe7swZbM7U1sBM1WyQlqUG6w-ZpoAM7w2Gbyn2OSHU119rUn44QTm1D9HrQ3GfzIymyRbuSpN/s1600/Screen+Shot+2020-05-06+at+11.05.15+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="107" data-original-width="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv7h_0MnvS_17G8jbKGOK5pcMmgHp6RG5jrMZs9hbGYGv__OsG8xast7y2iTby4f2RgQDpe7swZbM7U1sBM1WyQlqUG6w-ZpoAM7w2Gbyn2OSHU119rUn44QTm1D9HrQ3GfzIymyRbuSpN/s1600/Screen+Shot+2020-05-06+at+11.05.15+am.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 8. Output on Protocol Analyser.</div>
<br />
Adding OneShot42 or Multishot to our ESC Tester is trivial. You just need to change the minimum and maximum pulse width values and use the same approach as that used for OneShot125. I'm not going to add it to our code because I have no need for it.<br />
<br />
You can download a copy of the updated sketch from the Reefwing Gist.<br />
<br /></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-18498605398484157892020-03-26T15:30:00.001-07:002020-03-26T15:30:05.547-07:00Arduino Shield Multiprotocol ESC/Servo Tester<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
The Story So Far...</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUJtEimdPw3od4dQhbqcG8JBulEfoq5tez58H7M_ra471r8YcxWcX5frfbcw3B6JnkUwu5MBaqWYLgS_2gZP50zZ4OFc6lJnODrnJFa6Q4jd8VFRmPpNdKyga69yGfeNgObO4PM0MNwgpk/s1600/IMG_0692.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUJtEimdPw3od4dQhbqcG8JBulEfoq5tez58H7M_ra471r8YcxWcX5frfbcw3B6JnkUwu5MBaqWYLgS_2gZP50zZ4OFc6lJnODrnJFa6Q4jd8VFRmPpNdKyga69yGfeNgObO4PM0MNwgpk/s400/IMG_0692.jpeg" width="400" /></a></div>
<br />
<br />
In a <a href="http://reefwingrobotics.blogspot.com/2020/03/multiprotocol-escservo-tester-using.html" target="_blank">previous article</a> we used the Altronics MegaBox to create a prototype multiprotocol servo/ESC tester. We will build on the techiques and code from that article to create a custom Arduino UNO shield which can be used to deliver the same functionality. As the UNO uses a different microprocessor to the Mega 2560, we may need to change some of the timer and register specific code (actually it turns out only minor changes are required - our PWM output D9 uses Timer 1, which is the same as D11 on the Mega).<br />
<br />
<h3 style="text-align: left;">
The Arduino Shield</h3>
<br />
Using Fritzing we designed a simple 2 layer Arduino shield (Figure 1) to make it easier to test our hardware. We have made a few changes to our prototype. To save cost we are using a 10k potentiometer in place of the encoder (this saves one digital input as well). We have also replaced the LCD with a version that is controlled via I2C (saving another 5 digital inputs). PWM is being driven via D9. The board has five male header pins in the standard servo connection configuration. This allows you to control up to 4 servo/ESC's (current permitting) and still have an extra connection to view the output on an oscilloscope (for example).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCWpKp3Gp-XiafvTwETdrhpTMN8njgeNWtgD-4kuN5kgaTpB8oiMGUEVtKaWyQg34CjqLAxxhuN5fq6w0zzih0E56wdfyhXRaWIuSydHrE5osMHR5CUZaxZ1Laf-jw3qAT9oigB-TrmzRR/s1600/Screen+Shot+2020-03-13+at+5.58.42+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="919" data-original-width="1173" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCWpKp3Gp-XiafvTwETdrhpTMN8njgeNWtgD-4kuN5kgaTpB8oiMGUEVtKaWyQg34CjqLAxxhuN5fq6w0zzih0E56wdfyhXRaWIuSydHrE5osMHR5CUZaxZ1Laf-jw3qAT9oigB-TrmzRR/s400/Screen+Shot+2020-03-13+at+5.58.42+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. ESC/Servo Tester Shield</div>
<br />
As the shield will cover the reset button on the UNO, we have provided another one on the shield. An External Reset is generated by a low level on the RESET pin. In case the other pin connections are not obvious from Figure 1, here are the Arduino UNO pin defintions that you will need.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;"><span style="color: #333333;">//PIN CONNECTIONS
// POTENTIOMETER INPUT
const byte POT = A0;
// PWM OUTPUT
const byte PWM = 9;
// PUSH BUTTON INPUTS
const byte PB_DEC = 8; // Decrement button
const byte PB_INC = 7; // Increment button
const byte PB_SLT = 6; // Select Button
const byte PB_BCK = 5; // Back Button
//END PIN CONNECTIONS</span></pre>
Following testing we will design a 3D printed case for our tester. The LCD is a bit wider than the UNO PCB and we need to allow access to the buttons on the shield.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtbnv3emoXVUjrkISiSlT8NS-m2_CjbxMTGuIsPX_80-Th_Oog5TJMLyJrPcWBgsJ7D0Wa7LDjiCDueWNSaY8X3hfSpVZfcUv5aX7QYQJ0IzUdE2iHMa_lLtOmVACtlNB1dwKViHGqY4Z/s1600/IMG_0693.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtbnv3emoXVUjrkISiSlT8NS-m2_CjbxMTGuIsPX_80-Th_Oog5TJMLyJrPcWBgsJ7D0Wa7LDjiCDueWNSaY8X3hfSpVZfcUv5aX7QYQJ0IzUdE2iHMa_lLtOmVACtlNB1dwKViHGqY4Z/s400/IMG_0693.jpeg" width="400" /></a></div>
<br />
<br />
<h3 style="text-align: left;">
Parts List</h3>
<br />
I used the parts in Figure 2, there is nothing special required, but you need to ensure that the dimensions of the parts you select are correct for the PCB design. The part numbers and prices are from Jaycar (these are in AUD and subject to change).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJZxp05C4TmtnDXAu-hLnjYa4Tti_t3Y1arkM3nlg_a_Skbuduk8LIvP6w0fbAr9W_fMsGan_JEhTP_Kg5WXDYXIqi69N2_I5w9Cds3_5z-BsvNLxT2mWsP1NF9Ht54Ilwf-b6K7Cqwz22/s1600/Screen+Shot+2020-03-13+at+6.31.43+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="370" data-original-width="627" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJZxp05C4TmtnDXAu-hLnjYa4Tti_t3Y1arkM3nlg_a_Skbuduk8LIvP6w0fbAr9W_fMsGan_JEhTP_Kg5WXDYXIqi69N2_I5w9Cds3_5z-BsvNLxT2mWsP1NF9Ht54Ilwf-b6K7Cqwz22/s400/Screen+Shot+2020-03-13+at+6.31.43+pm.png" width="400" /></a></div>
<div style="text-align: center;">
Figure 2. Parts List</div>
<br />
In addition to the parts listed above you will need an UNO (or an equivalent clone), a plugpack to power the UNO, the shield PCB, 4 x male to female Dupont cable (Figure 4) and an I2C capable 16 x 2 LCD (Figure 3).<br />
<br />
Note that the DPDT switch isn't used in this version of the shield (a subsequent version will include a connection for external power for the servo/ESC's).<br />
<br />
<h3 style="text-align: left;">
I2C Serial 16 x 2 LCD Module</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjah3EUxhO-PbFrFxb8s_fJ47DPO5YwrtuVt3lAhCYgsO9MLP8r74Q0S_1vos3bsnB9lE18xe2Hsleq2d5rtZ-yh4KGXddr-OcvbPyQKTGjO2jRlZmqV7u5K6AHol73IWvil9PZPnZ6lX3g/s1600/Screen+Shot+2020-03-13+at+6.39.37+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="421" data-original-width="449" height="375" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjah3EUxhO-PbFrFxb8s_fJ47DPO5YwrtuVt3lAhCYgsO9MLP8r74Q0S_1vos3bsnB9lE18xe2Hsleq2d5rtZ-yh4KGXddr-OcvbPyQKTGjO2jRlZmqV7u5K6AHol73IWvil9PZPnZ6lX3g/s400/Screen+Shot+2020-03-13+at+6.39.37+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 3. I2C capable LCD 16 x 2</div>
<br />
<br />
You can buy one of these LCD's online from places like Aliexpress, at the time of writing they were available for USD2.53 (again, this will change). The LCDs are usually attached to another module which performs the serial to parallel conversion using a Philips/NXP PCF8574T. You may have to solder this module on yourself (I did).<br />
<br />
The four LCD connection pins (GND, 5V, SDA and SCL) line up with the corresponding connection on the PCB and you could straighten the pins and solder it in place but then you wouldn't have access to the push buttons on the shield or the contrast pot on the back of the LCD. A better option is to use some male to female Dupont cable (Figure 4).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCD5MR_iPI2P7VM0gVTOw63GWJqN66y-oGJHsP2blw85Zjm958UqBKuSixrQxe7B1oL1d6CXbMnJiFZxbFmONvZKeqL7JeABFCUNOS66QfbMCXLLFw3dSy7YwcxLH0ORGoxFKq6dJ1I7ZU/s1600/Screen+Shot+2020-03-13+at+6.53.47+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="457" data-original-width="506" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCD5MR_iPI2P7VM0gVTOw63GWJqN66y-oGJHsP2blw85Zjm958UqBKuSixrQxe7B1oL1d6CXbMnJiFZxbFmONvZKeqL7JeABFCUNOS66QfbMCXLLFw3dSy7YwcxLH0ORGoxFKq6dJ1I7ZU/s320/Screen+Shot+2020-03-13+at+6.53.47+pm.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 4. Male to Female Dupont Cable</div>
<br />
This <a href="https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library" target="_blank">link will allow you to download an I2C LCD Arduino Library</a>, which you will need when we develop the firmware in the next section.<br />
<br />
<h3 style="text-align: left;">
The Firmware</h3>
<br />
The ATmega328P has 6 PWM outputs, 2 are located on each timer/counter. Each timer has two Output Compare Registers (OCR) that control the PWM width for the timer's two outputs. The PWM capable pins are normally marked with a "~" on the UNO and we have replicated this on our shield (Figure 1). The relation between timers and PWM outputs is:<br />
<br />
<ul style="text-align: left;">
<li>Timer 0 controls Pins 5 and 6;</li>
<li>Timer 1 controls Pins 9 and 10; and</li>
<li>Timer 2 controls Pins 11 and 3.</li>
</ul>
<br />
We are using D9 to deliver our PWM signal, this is on Timer 1 and the relevant OCR for this pin is OCR1A (refer to <a href="https://reefwingrobotics.blogspot.com/2020/03/multiprotocol-escservo-tester-using.html" target="_blank">Figure 9 in the ATmega2560 article</a>). The settings we put in place will effect D10 as well.<br />
<br />
To assign D9 as an output, we need to know which Port it is mapped to (or just use pinMode). For the UNO:<br />
<br />
<ul style="text-align: left;">
<li>Port B controls digital pin 8 to 13;</li>
<li>Port C controls the analog input pins; and</li>
<li>Port D controls digital pins 0 to 7.</li>
</ul>
<br />
From the Arduino pin mapping diagram (Figure 5), we see that digital input 9 (D9) is controlled by bit 1 of Port B's Data Direction Register (DDR). The DDR determines whether a pin is an input or an output (Figure 6).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4WU9oSHerj_tye4ftPSzg5z4O42LvN4h3DgJkXfoPXlHtkDWJBMCSqmib87CPQ53cR5PWaqrmBOjDJxt98TaAjvWpY7brqQC7AW6j4zHJ2J9LpQVSWVHtQKQ9p4gPoa3nPShI0LMU95Sv/s1600/Atmega168PinMap2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="407" data-original-width="609" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4WU9oSHerj_tye4ftPSzg5z4O42LvN4h3DgJkXfoPXlHtkDWJBMCSqmib87CPQ53cR5PWaqrmBOjDJxt98TaAjvWpY7brqQC7AW6j4zHJ2J9LpQVSWVHtQKQ9p4gPoa3nPShI0LMU95Sv/s400/Atmega168PinMap2.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 5. ATmega168/328P Arduino Pin Mapping</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHXi1MX3j24VOzoqTtRwRP7GUHZdDVI1CmYyetIkJ3V6mRMWd-AG0KCIX_I-iuQFWJC24EAoANKGKimPQiC_NMrFQ5SnHtu-dCrpoQx_zNYfR92Bpsd99jj5thXfmhpSn8VI8HpUyTqnxz/s1600/Screen+Shot+2020-03-14+at+3.50.31+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="91" data-original-width="659" height="55" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHXi1MX3j24VOzoqTtRwRP7GUHZdDVI1CmYyetIkJ3V6mRMWd-AG0KCIX_I-iuQFWJC24EAoANKGKimPQiC_NMrFQ5SnHtu-dCrpoQx_zNYfR92Bpsd99jj5thXfmhpSn8VI8HpUyTqnxz/s400/Screen+Shot+2020-03-14+at+3.50.31+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 6. Port B Data Direction Register Bits</div>
<br />
<br />
Thus we set the DDR of Port B, bit 1 to assign D9 as an ouput:<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, Courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">DDRB |= 1 << DDB1;</pre>
<br />
Alternatively, you can just use:<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, Courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">pinMode(9, OUTPUT);</pre>
<br />
As with the ATmega2560, the 328P PWM is capable of running in 3 different modes: Fast PWM, Phase Corrected PWM and Phase and Frequency Phase Corrected PWM.<br />
<br />
Every PWM square wave has a duty cycle. This is defined as:<br />
<br />
<b><span style="color: magenta;">Duty Cycle = [ON time / (ON time + OFF time) ] * 100 </span></b><br />
<br />
We can manipulate the Output Compare Register (OCR) mentioned above, to adjust the PWM duty cycle. The OCR's (A and B) for Timer 1 are 16 bit registers. So for example, to get a 50% duty cycle, you set the OCR to half of the top counter value - referred to as "TOP" in the datasheet. The TOP value can be assigned to be one of the fixed values: 0xFFFF, 0x00FF, 0x01FF, or 0x03FF, or to the value stored in the OCRnA or ICRn Register. The assignment is dependent on the mode of operation.<br />
<br />
<h3 style="text-align: left;">
Fast PWM using Registers</h3>
<br />
In Fast PWM mode, the timer repeatedly counts from 0 to 255. The output turns on when the timer is at 0, and turns off when the timer matches the output compare register. The higher the value in the output compare register, the higher the duty cycle.<br />
<br />
To get hardware PWM working on a pin, you need to as a minimum:<br />
<br />
<ol style="text-align: left;">
<li>Set that pin as an output;</li>
<li>Set the PWM mode and frequency using the Timer Counter Control Registers (TCCR); and</li>
<li>Set the Output Compare Register to determine the pulse width / duty cycle.</li>
</ol>
<br />
So let's move on to steps 2 and 3. Firstly, there are two TCCR's (A and B). The control bits for TCCR1A are shown in Figure 7.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWb0Bpt5ezscglAwuUKp8NCYkIoCQgWd89V7vtrs1l15qdY3mSXsIJvv5czwd5_ts2OqVDQwNMIkBkcUFRwKOkt6tvhN_EQKbOa7uMYdIrUPmT99R3JfRnHJJfhyipA10sS5Tw9lLa6gXh/s1600/Screen+Shot+2020-03-14+at+4.14.01+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="75" data-original-width="557" height="53" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWb0Bpt5ezscglAwuUKp8NCYkIoCQgWd89V7vtrs1l15qdY3mSXsIJvv5czwd5_ts2OqVDQwNMIkBkcUFRwKOkt6tvhN_EQKbOa7uMYdIrUPmT99R3JfRnHJJfhyipA10sS5Tw9lLa6gXh/s400/Screen+Shot+2020-03-14+at+4.14.01+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizT5VoKmzbZm_zsBfhRbN0vQaXxgiotRcaxY4-fOrxOSJeLFz8fEO_kwa64o08RmziZ42pYSOUOGCr0qBW4lHFmJ4Gsm_BteIJB-2W2TflgRvzbZgZQrYoCQKapgeEn5XSH_D8iotHIUuZ/s1600/Screen+Shot+2020-03-14+at+4.36.11+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="68" data-original-width="554" height="48" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizT5VoKmzbZm_zsBfhRbN0vQaXxgiotRcaxY4-fOrxOSJeLFz8fEO_kwa64o08RmziZ42pYSOUOGCr0qBW4lHFmJ4Gsm_BteIJB-2W2TflgRvzbZgZQrYoCQKapgeEn5XSH_D8iotHIUuZ/s400/Screen+Shot+2020-03-14+at+4.36.11+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 7. TCCR1 (A and B) Control Bits.</div>
<br />
For fast PWM, we want non-inverting mode, thus from Figure 8, COM1A = 10 (BINARY).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzUYv9YgWuOsMuc-_dUtdbPxhLGonUl_C81y6PsUsGt1ZXHrHYXCqj8Z-Yr7P3CbjK0pwPLpfNr0heEcDECmCMu8jUl7436hBv1nPwTmblXSacYU_PPKV3qLk6yEh0Y9l6juWu2AqcZwTW/s1600/Screen+Shot+2020-03-14+at+4.29.54+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="214" data-original-width="576" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzUYv9YgWuOsMuc-_dUtdbPxhLGonUl_C81y6PsUsGt1ZXHrHYXCqj8Z-Yr7P3CbjK0pwPLpfNr0heEcDECmCMu8jUl7436hBv1nPwTmblXSacYU_PPKV3qLk6yEh0Y9l6juWu2AqcZwTW/s400/Screen+Shot+2020-03-14+at+4.29.54+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 8. Compare Output Mode Options, Fast PWM.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidjyQvCTWhngyEg9y8AdE9Gi63GD6lT1FjDQ2Mg4pYS_MVRjl1vM67x9DPl94LiM6Z9xeWD-2eswHu_HK7DRXifCteqEaaFQC83YIcKdSUSWnNX7wArMK6Dd9vFl3Z6AqEJOeI8UsIURoh/s1600/Screen+Shot+2020-03-14+at+4.34.07+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="731" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidjyQvCTWhngyEg9y8AdE9Gi63GD6lT1FjDQ2Mg4pYS_MVRjl1vM67x9DPl94LiM6Z9xeWD-2eswHu_HK7DRXifCteqEaaFQC83YIcKdSUSWnNX7wArMK6Dd9vFl3Z6AqEJOeI8UsIURoh/s400/Screen+Shot+2020-03-14+at+4.34.07+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 9. Waveform Generation Mode Bit Description.</div>
<br />
Next we need to set the Waveform Generation Mode. We will use mode 5 (Fast PWM, 8 bit) which has a TOP = 0x00FF = 255. To get mode 5 (ref: Figure 9), we need to set the following bits within the TCCR's:<br />
<br />
WGM10:3 = 0101<br />
<br />
We will also set the Clock Select (CS) Bits (Figure 10) to set the prescaler to 1. The appropriate value for this is:<br />
<br />
CS10:2 = 001<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyOPRfCMEgH2TyZDsMmxqB8kEgze_JuptFsq1O9-oUvs3QO1cZQdIpuKe7igglNPLkCVttF1b886VPLUjYCYB2ByTipzG3b4DGfeD2FFzhkgBypF3iQS9dsq1LZWn0wBkVqhb0ZbjdlnmY/s1600/Screen+Shot+2020-03-14+at+5.52.02+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="231" data-original-width="582" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyOPRfCMEgH2TyZDsMmxqB8kEgze_JuptFsq1O9-oUvs3QO1cZQdIpuKe7igglNPLkCVttF1b886VPLUjYCYB2ByTipzG3b4DGfeD2FFzhkgBypF3iQS9dsq1LZWn0wBkVqhb0ZbjdlnmY/s400/Screen+Shot+2020-03-14+at+5.52.02+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 10. Clock Select Bits.</div>
<br />
The Fast PWM frequency for the output can be calculated by the following equation:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixOPMLN6USWE58ypeR9uBPtjCzeXkzYGXo6N1d6O05kM1SWqbjpM1FeS_77poN1oAf1sr8mwgAog2LD3D22VzcT4E2XTFUQ1KLHZmx1B-FTXLoyFfjASnhdGRNnJHyV-UMioXw-fAxodsM/s1600/Screen+Shot+2020-03-14+at+5.55.42+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="65" data-original-width="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixOPMLN6USWE58ypeR9uBPtjCzeXkzYGXo6N1d6O05kM1SWqbjpM1FeS_77poN1oAf1sr8mwgAog2LD3D22VzcT4E2XTFUQ1KLHZmx1B-FTXLoyFfjASnhdGRNnJHyV-UMioXw-fAxodsM/s1600/Screen+Shot+2020-03-14+at+5.55.42+pm.png" /></a></div>
<br />
The N variable represents the prescaler divider (1, 8, 64, 256, or 1024). For our settings:<br />
<br />
fPWM = 16 Mhz / (1 * (1 + 255) = 16000000 / 256 = 62.5 kHz.<br />
<br />
The register code to achieve the register operations explained above is as shown in Figure 11.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; color: #333333; font-size: 13px; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;">DDRB |= 1 << DDB1; // Set D9 as an output pin<span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>
</b></span></span><span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>TCCR1A = 0;</b></span><b style="font-size: 12px;"> // Clear TCCR A & B bits</b><b style="font-size: 12px;">
TCCR1B = 0;</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1A = (1 << COM1A1) | (1 << WGM10);</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1B = (1 << WGM12) | (1 << CS10); </b><span style="font-size: 12px;">
<b>OCR1A = 127; // 50% Duty Cycle (i.e. 127/255)</b></span></span></pre>
<div style="text-align: center;">
Figure 11. Fast PWM using Registers.</div>
<br />
Measuring the results on our protocol analyser provides the expected outcome (Figure 12), 50% duty cycle, pulse width 8 µs and frequency 62.5 kHz. The pulse width is a product of the duty cycle and the frequency (as period is the inverse of frequency).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvsYvOolYw8RpI0rsLzoWfcsMRhgmeCSozHDUncQeunp3ndkcMTG-9gXkLVpJxeVIJd_nzA6QNKHJVJurQuV2mrUtt0rWzmNRaxQfTQ3VM7UyW8cccgLcl-7ba4daycuwxFZaH_Bnj6Zo/s1600/Screen+Shot+2020-03-14+at+6.15.32+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="108" data-original-width="503" height="85" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvsYvOolYw8RpI0rsLzoWfcsMRhgmeCSozHDUncQeunp3ndkcMTG-9gXkLVpJxeVIJd_nzA6QNKHJVJurQuV2mrUtt0rWzmNRaxQfTQ3VM7UyW8cccgLcl-7ba4daycuwxFZaH_Bnj6Zo/s400/Screen+Shot+2020-03-14+at+6.15.32+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 12. Fast PWM Output on D9.</div>
<br />
<h3 style="text-align: left;">
Changing PWM Frequency using Registers</h3>
<br />
Coincidently, the PWM pin (D9) that we chose on the UNO uses the same timer as the D11 pin on the Mega2560, so apart from the pin output definitions the code for phase and frequency correct PWM is the same (Figure 13). The <a href="https://reefwingrobotics.blogspot.com/2020/03/multiprotocol-escservo-tester-using.html" target="_blank">article on the ATmega2560 version</a> explains why we selected the control register bits in Figure 13. It also explains more about how phase and frequency correct PWM differs from Fast PWM. Of course you can also refer to the ATmega328P data sheet.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; color: #333333; font-size: 13px; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;">DDRB |= 1 << DDB1; // Set D9 as an output pin<span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>
</b></span></span><span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>TCCR1A = 0;</b></span><b style="font-size: 12px;"> // Clear TCCR A & B bits</b><b style="font-size: 12px;">
TCCR1B = 0;</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1A = (1 << COM1A1); // Non-inverting output</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1B = (1 << WGM13) | (1 << CS11); // Phase & Freq correct PWM, prescaler N = 8</b><span style="font-size: 12px;">
<b>ICR1 = 20000; // Freq = 50 Hz
OCR1A = 1500; // pulse width = 1500 us;</b></span></span></pre>
<div style="text-align: center;">
Figure 13. Phase & Frequency Correct PWM on the UNO.</div>
<br />
The default PWM mode, set by init() in the Arduino boiler plate code, for Timer 1 is mode 1 and we want mode 8 (PWM, Phase and Frequency Correct) - see Figure 9. In mode 8 we can adjust the PWM frequency using register ICR1. To get mode 8 we just set the WGM13 bit. We will use a non-inverting output as before so set the COM1A1 bit in TCCR1A. We set the prescaler (N) to 8, to do this, the CS11 bit in TCCR1B needs to be ON.<br />
<br />
From the data sheet, the frequency formula for phase and frequency correct PWM is:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFh9aCDqgT5zY44yc4NHaHaQi6m1MWfGIcxG3feyePG8kb4e_NIt8j4xiLaoyhl9PNx_mp2OiIWTuwxOeb1npk5l677x4qvLbD9UrciL6BejQQxqVXbxABu2tWTSX3QTNuqdQ-XRy4RLIY/s1600/Screen+Shot+2020-03-15+at+4.55.13+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="57" data-original-width="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFh9aCDqgT5zY44yc4NHaHaQi6m1MWfGIcxG3feyePG8kb4e_NIt8j4xiLaoyhl9PNx_mp2OiIWTuwxOeb1npk5l677x4qvLbD9UrciL6BejQQxqVXbxABu2tWTSX3QTNuqdQ-XRy4RLIY/s1600/Screen+Shot+2020-03-15+at+4.55.13+pm.png" /></a></div>
<br />
For our settings, the calculation is:<br />
<br />
fPWM = 16 MHz / (2 * 8 * ICR1) = 16000000 / (2 * 8 * 20000) = 50 Hz<br />
<br />
From this formula, it is apparent that we can adjust the PWM frequency by adjusting the value in register ICR1. It also explains why we use a prescaler of 8. The system clock is 16 MHz and to get the PWM frequency we divide by 2N. If we make 2N = 16 then the relationship between fPWM and ICR1 (i.e. TOP) is straight forward. Rearranging the formula:<br />
<br />
ICR1 = 1MHz / fPWM<br />
<br />
For a fPWM of 50 Hz, ICR1 = 1,000,000 / 50 = 20,000.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBKIThGA-8kz1Fm-3NvGLE043yNK-H0O6QVvJkuTgITXDgDJ-NWkmNW91ZASbaMtFeF4ZV0hUaJC6JOe7YRUSayYsUOJM0tHYfjrtw0leoOTrEF_s9jXq7bRp2kVsVj35FCDElnqi-L7Rl/s1600/Screen+Shot+2020-03-14+at+6.21.45+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="109" data-original-width="502" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBKIThGA-8kz1Fm-3NvGLE043yNK-H0O6QVvJkuTgITXDgDJ-NWkmNW91ZASbaMtFeF4ZV0hUaJC6JOe7YRUSayYsUOJM0tHYfjrtw0leoOTrEF_s9jXq7bRp2kVsVj35FCDElnqi-L7Rl/s400/Screen+Shot+2020-03-14+at+6.21.45+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 14. Phase & Frequency Correct PWM waveform at 50 Hz.</div>
<br />
The results of the code in Figure 13 is shown in Figure 14. So for our tester we can adjust the pulse width using the value of register OCR1A and we can adjust the PWM frequency using ICR1.<br />
<br />
<h3 style="text-align: left;">
Servo Tester Firmware</h3>
<br />
We previously used a rotary encoder to select menu options and adjust the PWM pulse width. This functionality is now provided by a 10k linear potentiometer (i.e. variable resistor).<br />
<br />
The Arduino ATmega328P has a 10-bit ADC which means it can return 2¹⁰ (i.e. 0–1023) values. This is where the 1024 comes from in the equation from the data sheet:<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">ADC = (Vin * 1024)/Vref</pre>
<br />
If you want to convert the ADC value to a voltage use the following formula (as the hardware rounds down):<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;"><b>float</b> voltage = ((<b>float</b>) rawADC + 0.5 ) / 1024.0 * Vref;</pre>
<br />
I have written a separate article on <a href="https://medium.com/@reefwing/programming-the-atmega328p-adc-registers-c2bfb2c5717a" target="_blank">Programming the ATmega328P ADC Registers</a> which goes into a lot more detail if you are interested but for our purposes we only care about the relative position of the potentiometer so we can just analogRead() the input connected to the middle pin of the potentiometer. The other two pins on the pot are connected to GND and 5V so moving the pot shaft should give us a value between 0 and 1023. The schematic looks like Figure 15.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuqzR82I5GKBGM4rMbrrKOfdML4wK7KHO4c83-7phvcKhymoXTNB5DQHluq-zyfKFrXAf1Vc9ZwLIyxOH_DFTV3G_OXIhdMOZDS-KoRp3nq1pc-E4WWVXfvl0hyphenhyphene2N74_-D7s-kgcj-8I/s1600/AnalogReadSerial_sch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="610" data-original-width="503" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpuqzR82I5GKBGM4rMbrrKOfdML4wK7KHO4c83-7phvcKhymoXTNB5DQHluq-zyfKFrXAf1Vc9ZwLIyxOH_DFTV3G_OXIhdMOZDS-KoRp3nq1pc-E4WWVXfvl0hyphenhyphene2N74_-D7s-kgcj-8I/s400/AnalogReadSerial_sch.png" width="328" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 15. 10K Potentiometer Connected to an UNO</div>
<br />
To test this we can use the sketch shown in Figure 16. As expected, rotating the potentiometer shaft caused the analog input read to vary between 0 and 1023.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;"><span style="color: #333333;">#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Set the LCD I2C address to 0x3F with 16 chars and a 2 line display
<b>LiquidCrystal_I2C</b> lcd(0x3F, 16, 2);
//PIN CONNECTIONS
// POTENTIOMETER INPUT
<b>const byte</b> POT = A0;
//END PIN CONNECTIONS
void setup() {
lcd.begin(); // Initialize the LCD
lcd.backlight(); // Turn on the backlight
}
void loop() {
// Read A0
<b>int</b> potValue = analogRead(POT);
lcd.clear();
lcd.print("Pot Value: ");
lcd.setCursor(0, 1);
lcd.print(potValue);
delay(100); // Reduce LCD flicker
}</span></pre>
<div style="text-align: center;">
Figure 16. Potentiometer Test Sketch.</div>
<br />
To convert the potValue to a PWM pulse width, we can use the Arduino map() function. You can define the minimum and maximum pulse widths to whatever values you like. I used 800 and 2200.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">pulseWidth = map(potValue, 0, 1023, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);</pre>
<br />
I have updated the UNO code to provide the same functionality as the Mega 2560 version. The full source listing of the Arduino code is available for download from the <a href="https://gist.github.com/reefwing/15313ebdfd194593d01d0b64ddb318cd" target="_blank">Reefwing Gist</a>. In the articles following we will design a 3D case and add additional digital protocols.<br />
<br /></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-72769572764171072012020-03-19T00:14:00.001-07:002020-03-19T00:14:09.458-07:00Loading 3D Models in SceneKit<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
COLLADA 3D Models</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheObj5t7LbEIR4wjybZdyZ7WTn6LGBQDN1EqkO2-UIkfzuv923-siyXm_dvgHehaCip_29KiTZqc_rfcuubU0JGGX0WEIcuRmTFZTRiSaBX_i2gRLPTj-YOu9YaVfxpOWU81XHMddC8TGv/s1600/Neuron+Model.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="640" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheObj5t7LbEIR4wjybZdyZ7WTn6LGBQDN1EqkO2-UIkfzuv923-siyXm_dvgHehaCip_29KiTZqc_rfcuubU0JGGX0WEIcuRmTFZTRiSaBX_i2gRLPTj-YOu9YaVfxpOWU81XHMddC8TGv/s400/Neuron+Model.gif" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. 3D Model of a Neuron.</div>
<br />
The Mac has supported the visualization of COLLADA 3D models since 2009. If you created or downloaded a model this could be viewed in Finder and Preview. With the introduction of the 3D Framework, SceneKit, it is relatively simple to load and display a 3D model in iOS or OSX.<br />
<br />
<h3 style="text-align: left;">
What is COLLADA?</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXNCkFRKkS_fGnuWEjgOcVL-0Zpro5u5GjilII-uw07pJ1yxuoDcArNxeQ4qMsi1XB6pVnfU0i1YDxpoLhWWUzf_Ipts_xHuDsYRnES8-6vIlqUYu-klbxhFb3b-ldt0GlgXCUtDzsG0sS/s1600/COLLADA_logo_vect.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="66" data-original-width="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXNCkFRKkS_fGnuWEjgOcVL-0Zpro5u5GjilII-uw07pJ1yxuoDcArNxeQ4qMsi1XB6pVnfU0i1YDxpoLhWWUzf_Ipts_xHuDsYRnES8-6vIlqUYu-klbxhFb3b-ldt0GlgXCUtDzsG0sS/s1600/COLLADA_logo_vect.svg.png" /></a></div>
<br />
<br />
COLLADA (COLLAborative Design Activity) is a file format for 3D applications. COLLADA documents are effectively XML files, usually identified with a .dae (digital asset exchange) filename extension. This file format has its own ISO standard (17506:2012).<br />
<br />
So if you are choosing a 3D software application to create digital assets for your iOS app, make sure that it can export to the COLLADA (.dae) file format.<br />
<br />
In addition to being able to use .dae files with SceneKit, many game engines also provide native support for COLLADA.<br />
<br />
<h3 style="text-align: left;">
Getting a 3D Model</h3>
<br />
In order to import and display a 3D model we are going to need to have one! For this tutorial, I downloaded a model from <a href="http://clara.io/">clara.io</a>. Clara.io has free online modelling tools plus free downloads from their library. Make sure that your model is in COLLADA format.<br />
<br />
<h3 style="text-align: left;">
SceneKit</h3>
<br />
SceneKit is an iOS/OSX framework that allows you to build and manipulate 3D objects within a 3D scene. SceneKit has a high-performance rendering engine and a descriptive API for import, manipulation, and rendering of 3D assets.<br />
<br />
SceneKit is based on the concept of nodes. Each 3D object that you want to render using SceneKit is a node. The SCNScene object is a container for the node hierarchy and global properties that together form a displayable 3D scene.<br />
<br />
To build a 3D scene, you use nodes to create its structure, and then add lights and a camera to create the visible content. SceneKit implements content as a hierarchical tree structure of nodes, also known as scene graph. The rootNode object in a scene defines the coordinate system of the rendered 3D world.<br />
<br />
<h3 style="text-align: left;">
The Code</h3>
<br />
Assuming you now have the 3D model which you want to display, drag it into the art.scnassets folder in Xcode. You can then load a 3D model in SceneKit using one line of code.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, Courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">let scene = SCNScene(named: "art.scnassets/brain-simple.dae")!</pre>
<br />
If you select the iOS Game template when you create a new project in Xcode, then the remainder of the boiler plate code will do everything else. The only class you need to modify is GameViewController. I have moved things around a bit to make the functionality more obvious. The viewDidLoad function becomes:<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;"><span style="color: #333333;">var cameraNode: SCNNode!
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/brain-simple.dae")!
// create and add a camera to the scene
cameraNode = setupCamera(for: scene)
// create and add a light to the scene
setupLighting(for: scene)
// Setup our scene view:
setupSceneView(with: scene)
}</span></pre>
The functions called from viewDidLoad are then:<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;"><span style="color: #333333;">func setupCamera(for scene: SCNScene!) -> SCNNode {
// Create and add a camera to the scene:
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
return cameraNode
}
func setupLighting(for scene: SCNScene!) {
// Create and add a light to the scene:
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// Create and add an ambient light to the scene:
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
}
func setupSceneView(with scene: SCNScene!) {
// retrieve the SCNView
let sceneView = self.view as! SCNView
// set the scene to the view
sceneView.scene = scene
// allows the user to manipulate the camera
sceneView.allowsCameraControl = true
// show statistics such as fps and timing information
sceneView.showsStatistics = true
// configure the view
sceneView.backgroundColor = UIColor.black
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
sceneView.addGestureRecognizer(tapGesture)
}</span></pre>
That's it! Run the code and you can rotate, tilt and pan your 3D model.<br />
<br />
<h3 style="text-align: left;">
Selecting the Material which Responds to a Tap</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh45LPhnW-mLBl_HUa91oKLIOetaj0QmyxcMwGriQ-anjyAI3TgLKloV6q2f5E76ZVm5Xcg4G_I2q9aG2uiGeSJTyLIcIdlH42B_65Rcm-Ikb9B_3VXAQTzm8kaBBAC30Q3bXg4DMbw8iTc/s1600/Screen+Shot+2020-03-19+at+5.58.06+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1226" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh45LPhnW-mLBl_HUa91oKLIOetaj0QmyxcMwGriQ-anjyAI3TgLKloV6q2f5E76ZVm5Xcg4G_I2q9aG2uiGeSJTyLIcIdlH42B_65Rcm-Ikb9B_3VXAQTzm8kaBBAC30Q3bXg4DMbw8iTc/s400/Screen+Shot+2020-03-19+at+5.58.06+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 2. Xcode SceneKit Editor</div>
<br />
<br />
In our setupSceneView() function we assign a tap gesture which turns the first material in our model red whenever we tap the screen. How do you know what the first material is?<br />
<br />
Well, Xcode includes a SceneKit Editor. If you click on your 3D Model file (.dae) in the aert.scnassets folder, then it will appear in the SceneKit editor (Figure 2). Click on the image of the model and then click on the material inspector icon (top right of the editor), and you will see a list of materials available in the model. Mine includes four materials labelled default, red, green and blue. So in my case the first material is "default" which is a light grey colour in my model.<br />
<br />
If we want one of the other materials to glow red when the screen is tapped then instead of the firstMaterial property, we can use its name. For example if I wanted the green material to glow red, then I would change this line in the handleTap() function as shown:<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); color: #333333; font-family: monospace, courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">let material = result.node.geometry!.material(named: "green")!</pre>
<br />
<br />
<br /></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-37933226790852251622020-03-09T00:14:00.001-07:002020-03-09T00:14:13.290-07:00Multiprotocol ESC/Servo Tester using the Altronics MegaBox<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="margin-left: 1em; margin-right: 1em;">
</div>
<br />
<h3 style="text-align: left;">
Introduction</h3>
<br />
My interests include robotics and drones. These inevitably involve using servos and ESC's (Electronic Speed Controllers) which I would like to be able to test before I attach the Flight Controller or microprocessor which is running the show. Hence my interest in developing an ESC/Servo Tester.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwoxMdmDa-RnqKJ5f5za_s2m8ER7js5G4O5scKuI7b9mr8e6LF4GxIxkaHcCgQ3eg-0crKiVZIw5BrR47ZXm57APv9Ra66LsEHPGyULekHo9IFyX0JKu6DraGYq4M6hGor5biOplp5hyphenhyphenLD/s1600/images.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="425" data-original-width="425" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwoxMdmDa-RnqKJ5f5za_s2m8ER7js5G4O5scKuI7b9mr8e6LF4GxIxkaHcCgQ3eg-0crKiVZIw5BrR47ZXm57APv9Ra66LsEHPGyULekHo9IFyX0JKu6DraGYq4M6hGor5biOplp5hyphenhyphenLD/s400/images.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. HJ Servo Tester</div>
<br />
You can buy ESC/Servo Testers (e.g. Figure 1) but they are pretty basic with most only supplying PWM to drive your ESC or Servo. The HJ Servo Consistency Tester shown above allows you to change the PWM pulse width (800 ~ 2200 µs @ 50 Hz) and for digital servos, the frequency [50 Hz (20 ms), 125 Hz (8 ms) or 250 Hz (4 ms)]. Note that pulse width is determined by the product of the duty cycle and frequency (freq = 1 / period).<br />
<br />
The connections to the HJ tester are not particularly obvious. The left hand column is for power (S at top if required, 5V and GND) and then the next 4 columns are for the servo or ESC following the same order (signal, 5V and GND at the bottom).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgarN8CNuip3M9FbWTFYxih6ml4De3PyoGjBjoJ07J50JYlYigUPJkXqCcO7TjSwg05d0oM8ilMA8an_anAVFC6Ay5HOQ98FgpCNso8Vpjj1Y98abWP5Ghp-OL1OWRH5z8o7PeA6BSCvDdM/s1600/Screen+Shot+2020-03-03+at+5.58.34+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="992" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgarN8CNuip3M9FbWTFYxih6ml4De3PyoGjBjoJ07J50JYlYigUPJkXqCcO7TjSwg05d0oM8ilMA8an_anAVFC6Ay5HOQ98FgpCNso8Vpjj1Y98abWP5Ghp-OL1OWRH5z8o7PeA6BSCvDdM/s400/Screen+Shot+2020-03-03+at+5.58.34+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 2. HJ Connected to Saleae Protocol Analyser</div>
<br />
I connected the HJ Tester to my Saleae Protocol Analyser, with the pulse width set to 800 µs. The results are shown in Figures 2 and 3. Our measurements show that the HJ Tester is pretty accurate, pulse width is 0.7991 ms and the frequency is 50.09 Hz.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdrxcG_jO7-J2uimCxs1DsMuxJ9urk6rttKBDmODTKnObqGKAXO8tbTEpckYQ0jOjsXOtaXpyRMhh9l16prX5AqimGTiLHPvDFX9tII4R3B96ixrwx3qyfNWCLeZM8-Gc0clSga2-Pt1o4/s1600/Screen+Shot+2020-03-03+at+5.58.52+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="992" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdrxcG_jO7-J2uimCxs1DsMuxJ9urk6rttKBDmODTKnObqGKAXO8tbTEpckYQ0jOjsXOtaXpyRMhh9l16prX5AqimGTiLHPvDFX9tII4R3B96ixrwx3qyfNWCLeZM8-Gc0clSga2-Pt1o4/s400/Screen+Shot+2020-03-03+at+5.58.52+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 3. Single pulse for HJ Tester at 800 <span style="text-align: left;">µs</span></div>
<br />
<br />
The select button toggles between three test modes:<br />
<br />
<ol style="text-align: left;">
<li><b>Manual</b> - pulse width is changed by the potentiometer on the right from 800 to 2200 µs</li>
<li><b>Centre</b> - pulse width set to 1.5 ms (i.e. servo centred)</li>
<li><b>Sweep</b> - pulse width sweeps automatically from 800 to 2200 µs. The potentiometer adjusts sweep speed in this mode.</li>
</ol>
<br />
The pulse width button toggles between the three frequencies 50 Hz, 125 Hz and 250 Hz.<br />
<br />
This functionality is ok but for ESC's in particular, most of these are now controlled with some fancy digital protocol, and it would be nice to test them using this. In addition to the different varieties of PWM, ESC's can use oneshot, multishot and Dshot protocols (amongst others). The aim is to develop a Servo/ESC tester with these protocols available. In Part 1 we will put together our own version of the HJ Tester, then in subsequent parts we will add some common digital ESC protocols.<br />
<ul style="text-align: left;">
</ul>
<br />
<h3 style="text-align: left;">
The Arduino MegaBox</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.altronics.com.au/prod_new/k/K9670.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="K9670 Mega box for Arduino" border="0" height="188" src="https://images.altronics.com.au/prod_new/k/K9670.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 4. Altronics MegaBox for Arduino</div>
<br />
<br />
As I happen to have an Altronics MegaBox (Figure 4) available, I will use this for my initial prototype. It has most of what I need including a LCD, 4 switches and a rotary encoder. There is an Arduino Mega 2560 clone plugged into this box to provide the smarts. The encoder will be used to select modes and adjust the PWM duty cycle / motor speed.<br />
<br />
<h3 style="text-align: left;">
Servo Tester Specification</h3>
<br />
We will start off with the code for a servo tester as this is the most straight forward. Most servos will move a set number of degrees based on the pulse width of the signal on the control line. Our test servo will be the common SG90.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhAqpV6m7Mjw0KihyphenhyphenhQjsLHmJ29y2SkRpWSbIkEFKM5soyllkkooc0sxsQaF9obNZ02-b0A0yjgKiZ48bbL83V506mU6NoxM9oj7dKO0zlJHVWrtrzOq5ua-WXJtkjDfaPgnPTvBchJsHE/s1600/9g-micro-servo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhAqpV6m7Mjw0KihyphenhyphenhQjsLHmJ29y2SkRpWSbIkEFKM5soyllkkooc0sxsQaF9obNZ02-b0A0yjgKiZ48bbL83V506mU6NoxM9oj7dKO0zlJHVWrtrzOq5ua-WXJtkjDfaPgnPTvBchJsHE/s1600/9g-micro-servo.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 5. SG90 Servo</div>
<br />
<br />
The <a href="https://www.jaycar.com.au/medias/sys_master/images/8910951809054/YM2758-dataSheetMain.pdf" target="_blank">Jaycar SG90 Data Sheet</a> only helps with the wiring details. We need the pulse width's required to drive the servo. We found a more useful <a href="http://www.micropik.com/PDF/SG90Servo.pdf" target="_blank">Data Sheet at MicoPik</a>. From this we can determine the following characteristics:<br />
<ul style="text-align: left;">
<li>Weight: 9 g</li>
<li>Dimension: 22.2 x 11.8 x 31 mm approx.</li>
<li>Stall torque: 1.8 kgf·cm</li>
<li>Operating speed: 0.1 s/60 degree</li>
<li>Operating voltage: 4.8 V (~5V)</li>
<li>Dead band width: 10 µs</li>
<li>Temperature range: 0 ºC – 55 ºC </li>
<li>Running current with 5V supply (no mechanical load)<span class="Apple-tab-span" style="white-space: pre;"> </span>220 ±50mA</li>
<li>Stall current with 5V supply (horn locked)<span class="Apple-tab-span" style="white-space: pre;"> </span> 650 ±80mA</li>
<li>Idle current with 5V supply<span class="Apple-tab-span" style="white-space: pre;"> </span> 6 ±10mA</li>
</ul>
<br />
The SG90 expects a frequency of 50 Hz on the control line and the position it moves to depends on the pulse width of the signal. the servo will move to:<br />
<ul style="text-align: left;">
<li>0 degrees - the centre position with a 1.5 ms pulse;</li>
<li>+ 90 degrees with a ~2 ms pulse; and</li>
<li>- 90 degrees with a ~1 ms pulse.</li>
</ul>
<br />
Whether + or - 90 degrees is left or right will depend on how you mounted the servo. There is no point changing the frequency of the control pulses, unless the servo you are testing expects something different to 50 Hz. The servo moves at a set speed (0.1 s/60 degrees for the SG90), regardless of how quickly you change the pulses.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXzyKKIzph22WgEliRAomUxr_UyYazQMIWZO-iyWk8yktVUmi51xHfNBaGJvzn912E60MviKuMIQDXrJPvaJ95KpQ_4kDUasCTM5y8_wK99B8s8i20X-Jo2pP5CEqwOSY22saGQz29z12q/s1600/SG90-Datasheet.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXzyKKIzph22WgEliRAomUxr_UyYazQMIWZO-iyWk8yktVUmi51xHfNBaGJvzn912E60MviKuMIQDXrJPvaJ95KpQ_4kDUasCTM5y8_wK99B8s8i20X-Jo2pP5CEqwOSY22saGQz29z12q/s1600/SG90-Datasheet.gif" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 6. SG90 Wiring Details</div>
<br />
For this version of the code, we will use the rotary encoder to adjust the pulse width and the four buttons will funcion as follows:<br />
<br />
Button 1 - min pulse width (default 1000 µs @ 50 Hz)<br />
Button 2 - max pulse width (default 2000 µs @ 50 Hz)<br />
Button 3 - start auto sweep<br />
Button 4 - stop auto sweep and centre (1500 µs @ 50 Hz)<br />
<br />
<h3 style="text-align: left;">
Servo Tester PWM Approaches</h3>
<br />
The Arduino Mega 2560 has 15 pins which can be used for PWM output. The simplest way to output PWM on these pins is to use the analogWrite(pin, dutyCycle) command. The PWM default frequency is 490 Hz for all pins, with the exception of pin 13 and 4, whose frequency is 980 Hz.<br />
<br />
We tested this using our protocol analyser and found that a 50% duty cycle [analogWrite(11, 127)] provides PWM with a 1.016 ms pulse width and a frequency of 490 Hz.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGTpfahyphenhyphenw-jJlnZp_ydtL0JmE1xQLv5AHTqOBPk6YmDbOhZDBIV2YhaW6l0OtDJte2X2wCequt9rC3p7Tr1oFq5KQrtyBa7R7QcB8rcz9ftkVEpMqtjFEO1lj9cYuhCdtBI6DkThkGhEJE/s1600/Screen+Shot+2020-03-03+at+6.35.46+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="992" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGTpfahyphenhyphenw-jJlnZp_ydtL0JmE1xQLv5AHTqOBPk6YmDbOhZDBIV2YhaW6l0OtDJte2X2wCequt9rC3p7Tr1oFq5KQrtyBa7R7QcB8rcz9ftkVEpMqtjFEO1lj9cYuhCdtBI6DkThkGhEJE/s400/Screen+Shot+2020-03-03+at+6.35.46+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 7. Default analogWrite PWM</div>
<br />
Another option is to use the Arduino Servo library. In this library you select a value between 0 and 180 degrees to set the position of the servo. So at 90 degrees (centred) you would expect a pulse width of 1500 µs. Figure 8 shows what we measured using the Servo libray with the servo set to 90 degrees, a 1.475 ms pulse width and a frequency of 49.96 Hz. So again pretty close to what is expected.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDpr-Ep4GmRVpdVtw0z_H8YdqsNzrLPzLcslR0tJmaXIA6qvdALbTWOWOixJaoNkyyTILsaIx_wLMBKFYQF2T2d9tG8KiKnQEvznIeumydwf_Ee86waTLEdxuPHBGY43IqgSwUSfiWbSOR/s1600/Screen+Shot+2020-03-03+at+6.51.07+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="992" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDpr-Ep4GmRVpdVtw0z_H8YdqsNzrLPzLcslR0tJmaXIA6qvdALbTWOWOixJaoNkyyTILsaIx_wLMBKFYQF2T2d9tG8KiKnQEvznIeumydwf_Ee86waTLEdxuPHBGY43IqgSwUSfiWbSOR/s400/Screen+Shot+2020-03-03+at+6.51.07+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 8. Servo Library PWM set to 90 degrees</div>
<br />
<br />
Alternatively, you can access the Atmel registers directly for finer control, this allows you to change the type, range and frequency of the pulse width modulation (PWM). It isn't possible to change the frequency using either of the two previous methods.<br />
<br />
<h3 style="text-align: left;">
Changing Pulse Width / Duty Cycle Using Registers</h3>
<br />
We will use pin D11 (ATmega2560 physical pin 24, Port B bit 5) as this will work for an UNO or MEGA and is our next free pin. To set D11 as an output we can use:<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); font-family: monospace, Courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">DDRB |= 1 << DDB5;</pre>
<br />
This line of code sets the 5th bit of the DDRB register to 1 and is equivalent to pinMode(11, OUTPUT). DDRB is the data direction register for Port B.<br />
<br />
Most of the register based PWM examples available are for the ATmega328P and our version of the MEGA uses the ATmega2560, so you need to make sure that you are using the correct registers and timers for your microprocessor.<br />
<br />
The ATmega2560 has 15 pins which can be used for PWM output. Instead of using analogWrite(), we can manipulate the Output Compare Registers (OCR) directly to adjust the duty cycle. The OCR is a 16 bit register. So for example, to get a 50% duty cycle, you set the OCR to half of the top counter value - referred to as "TOP" in the datasheet. The TOP value can be assigned to be one of the fixed values: 0xFFFF, 0x00FF, 0x01FF, or 0x03FF, or to the value stored in the OCRnA or ICRn Register. The assignment is dependent on the mode of operation (Figure 10).<br />
<br />
In the data sheet the Output Compare Registers are labelled OCRxA, OCRxB or OCRxC (where x is the timer number 0..5). The association between OCR's and pins for the 2560 is shown in Figure 9.<br />
<br />
<b>Pin<span style="white-space: pre;"> </span>Register (2560) Pin Register (328P)</b><br />
2<span style="white-space: pre;"> </span>OCR3B<br />
3<span style="white-space: pre;"> </span>OCR3C 3 OCR2B<br />
4<span style="white-space: pre;"> </span>OCR4C<br />
5<span style="white-space: pre;"> </span>OCR3A 5 OCR0B<br />
6<span style="white-space: pre;"> </span>OCR4A 6 OCR0A<br />
7<span style="white-space: pre;"> </span>OCR4B<br />
8<span style="white-space: pre;"> </span>OCR4C<br />
9<span style="white-space: pre;"> </span>OCR2B 9 OCR1A<br />
10<span style="white-space: pre;"> </span>OCR2A 10 OCR1B<br />
11<span style="white-space: pre;"> </span>OCR1A 11 OCR2A<br />
12<span style="white-space: pre;"> </span>OCR1B<br />
13<span style="white-space: pre;"> </span>OCR0A<br />
44<span style="white-space: pre;"> </span>OCR5C<br />
45<span style="white-space: pre;"> </span>OCR5B<br />
46<span style="white-space: pre;"> </span>OCR5A<br />
<br />
<div style="text-align: center;">
Figure 9. Arduino pins and associated Output Compare Register.</div>
<br />
To adjust the PWM duty cycle, we can modify the appropriate Output Compare Register. For D11on the ATmega2560 the register is OCR1A.<br />
<br />
<pre style="background-color: #f9f9f9; border: 1px solid rgb(221, 221, 221); font-family: monospace, courier; font-size: 12.7px; line-height: 1.1em; padding: 1em;">OCR1A = 32767;</pre>
<br />
What happens next will be determined by the current mode of operation, which is set by a combination of the Waveform Generation mode and Compare Output mode bits. This is defined in Table 17-2 of the ATmega2560 data sheet (Figure 10).<br />
<br />
The main PWM modes are "Fast PWM" and "Phase-correct PWM".<br />
<br />
Assuming we haven't changed anything and we are in "Normal" mode, then TOP = 0xFFFF = 65535, and setting 0CR1A to 32767, should deliver PWM with a 50% duty cycle. Note that the data sheet states that "<i>using the Output Compare to generate waveforms in Normal mode is not recommended, since this will occupy too much of the CPU time.</i>"<br />
<br />
Testing this shows no PWM output. This is because you need to both enable the pin for output and set the PWM mode (i.e. set the COM bits) on that pin in order to get a result. So let's do that using Fast PWM.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK3xKPIBy-tUd5FuKQN_donZVxzzw477hVu28jjk-xyW3qLfimwfHIksw7M8c027EyAhBz0Dq278ZrMHW9oti-rD1HkwBT3dRaugosF1HN8jAzNwEtG8VpHor_BcsA4_qLJXJsBjfqwdRz/s1600/Screen+Shot+2020-03-04+at+10.30.59+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="458" data-original-width="736" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK3xKPIBy-tUd5FuKQN_donZVxzzw477hVu28jjk-xyW3qLfimwfHIksw7M8c027EyAhBz0Dq278ZrMHW9oti-rD1HkwBT3dRaugosF1HN8jAzNwEtG8VpHor_BcsA4_qLJXJsBjfqwdRz/s400/Screen+Shot+2020-03-04+at+10.30.59+am.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 10. ATmega2560 Modes of Operation</div>
<br />
<h3 style="text-align: left;">
Fast PWM using Registers</h3>
<br />
In Fast PWM mode, the timer repeatedly counts from 0 to 255. The output turns on when the timer is at 0, and turns off when the timer matches the output compare register. The higher the value in the output compare register, the higher the duty cycle. To set the mode we want, we use the Timer / Counter Control Registers, TCCRnA and TCCRnB (where n = the timer number).<br />
<br />
For D11 we need Timer 1 (this is explained in the next section). So we need to set the relevant bits in TCCR1A and TCCR1B. Note that this will effect pin D12 as well.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG9K5G7IEa4VPkZ6hDehzsDy0YV-pgyB_IAIfLV1d3BUFiucITiN8pNbf2ci3LmKihKNcX_NBYdnJ-ylQG3zHt3cUUiVhvxWWIbOC6wLGDta5pohRIbpoXnioYp358yRNAorrBVyQI0HpH/s1600/Screen+Shot+2020-03-04+at+12.02.14+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="73" data-original-width="661" height="43" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG9K5G7IEa4VPkZ6hDehzsDy0YV-pgyB_IAIfLV1d3BUFiucITiN8pNbf2ci3LmKihKNcX_NBYdnJ-ylQG3zHt3cUUiVhvxWWIbOC6wLGDta5pohRIbpoXnioYp358yRNAorrBVyQI0HpH/s400/Screen+Shot+2020-03-04+at+12.02.14+pm.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7GKaZiseU0RRMG9z3N2wDKM4HRIEFXJuaI3xch2SupoiA9W8qpQBCj8Nfe3_jYq6OqsAEAVpCfSmDWMw3aOh33ADR5h-G34ZBcHlm5SnWnpRxWqUUbuQAOdVYNm6LdR46tGcfDeYHgqIG/s1600/Screen+Shot+2020-03-04+at+12.02.40+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="69" data-original-width="661" height="41" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7GKaZiseU0RRMG9z3N2wDKM4HRIEFXJuaI3xch2SupoiA9W8qpQBCj8Nfe3_jYq6OqsAEAVpCfSmDWMw3aOh33ADR5h-G34ZBcHlm5SnWnpRxWqUUbuQAOdVYNm6LdR46tGcfDeYHgqIG/s400/Screen+Shot+2020-03-04+at+12.02.40+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 11. <span style="text-align: left;">Timer 1 Counter Control Register Bits</span></div>
<br />
<br />
We will use mode 5 (Fast PWM, 8 bit) which has a TOP = 0x00FF = 255. To get mode 5, we need to set the following bits within the TCCR's:<br />
<br />
WGM1<span style="font-size: xx-small;">0:3</span> = 0101<br />
<br />
We will also set the Clock Select (CS) Bits to set the prescaler to 1. The appropriate value for this is:<br />
<br />
CS1<span style="font-size: xx-small;">0:2</span> = 001<br />
<br />
The PWM frequency for the output can be calculated by the following equation (from the data sheet):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2B5XObpnuXCTtKH5OVN8O4c83EBPlVIPKqSbwLqTeH5427VXzvYf-5pwXRp7RMrZ5ar2MDTQ41jyqkxB2Bddpt286-Ci5j6AUuinZ1DGyrJhdy21nENTrjTRzeHDfp_H63ALq4IJG_5qF/s1600/Screen+Shot+2020-03-05+at+5.05.11+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="54" data-original-width="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2B5XObpnuXCTtKH5OVN8O4c83EBPlVIPKqSbwLqTeH5427VXzvYf-5pwXRp7RMrZ5ar2MDTQ41jyqkxB2Bddpt286-Ci5j6AUuinZ1DGyrJhdy21nENTrjTRzeHDfp_H63ALq4IJG_5qF/s1600/Screen+Shot+2020-03-05+at+5.05.11+pm.png" /></a></div>
Where the N variable represents the prescaler divider (1, 8, 64, 256, or 1024).<br />
<br />
For our settings: f<span style="font-size: xx-small;">PWM</span> = 16 Mhz / (1 * (1 + 255) = 16000000 / 256 = 62.5 kHz.<br />
<br />
The various Clock Select modes are shown in Table 17-6 of the data sheet (Figure 12).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgneMv5yLvtvkFb7BoFDtSaKKLSZ_DAw3W0fcXuW5b04uodTcu0l1v_YC3P8EVPX7e_Ovfdvgljip8-ZUEYDxHyOcNvAlPHu314ZrXKg32omKemGBvlg7NWzp2SG9jeJxfzDa7JKLUWanCY/s1600/Screen+Shot+2020-03-04+at+11.49.39+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="234" data-original-width="689" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgneMv5yLvtvkFb7BoFDtSaKKLSZ_DAw3W0fcXuW5b04uodTcu0l1v_YC3P8EVPX7e_Ovfdvgljip8-ZUEYDxHyOcNvAlPHu314ZrXKg32omKemGBvlg7NWzp2SG9jeJxfzDa7JKLUWanCY/s400/Screen+Shot+2020-03-04+at+11.49.39+am.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 12. Clock Select Bit Options</div>
<br />
The final part of the puzzle is setting the Compare Output Mode for the relevant type of PWM. We need Table 17-4 from the data sheet for this (Figure 13). We want non-inverting mode and will set:<br />
<br />
COM1A<span style="font-size: xx-small;">0:1</span> = 01<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirWTKRzftpXbyNGlDida4E6XbKA2CjMeEOHWulv41n451qVmSOm1lERcekb4CnqhK_-I8P3Q-ADfhfWNTlwwsZkyCDc_LvXbXefCONQx42KWMkLHoBy41ioFOeTReXEpRefSsLa1GaBo8h/s1600/Screen+Shot+2020-03-04+at+12.21.34+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="212" data-original-width="689" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirWTKRzftpXbyNGlDida4E6XbKA2CjMeEOHWulv41n451qVmSOm1lERcekb4CnqhK_-I8P3Q-ADfhfWNTlwwsZkyCDc_LvXbXefCONQx42KWMkLHoBy41ioFOeTReXEpRefSsLa1GaBo8h/s400/Screen+Shot+2020-03-04+at+12.21.34+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 13. Compare Output Mode for Fast PWM</div>
<br />
<br />
The register code to achieve this is as follows.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;">DDRB |= 1 << DDB5; // Set D11 as an output pin<span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>
</b></span></span><span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>TCCR1A = 0;</b></span><b style="font-size: 12px;"> // Clear TCCR A & B bits</b><b style="font-size: 12px;">
TCCR1B = 0;</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1A = (1 << COM1A1) | (1 << WGM10);</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1B = (1 << WGM12) | (1 << CS10); </b><span style="font-size: 12px;">
<b>OCR1A = 127; // 50% Duty Cycle (i.e. 127/255)</b></span></span></pre>
<div style="text-align: center;">
Figure 14. Fast PWM using Registers</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
In the code above (Figure 14) you will notice that we clear the bits in the Timer / Counter Control Registers (TCCR1A and TCCR1B). This is required because if you are using the Arduino IDE, there is a hidden main function which calls setup() and loop(). More importantly from our perspective is the init() function which it calls first. The init() is defined in hardware/arduino/avr/cores/arduino/wiring.c. If you have a look at this file, you will see that amongst other things it sets up the TCCR's for Timers 0, 1 and 2. Thus unless we clear these registers we may get an unexpected result when we assign our bits.</div>
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;">int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
</pre>
<div style="text-align: center;">
Figure 15. Arduino Main() Function</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Measuring the results on our protocol analyser provides the expected outcome (Figure 16), 50% duty cycle, pulse width 8 µs and frequency 62.5 kHz. The pulse width is a product of the duty cycle and the frequency (as period is the inverse of frequency).</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSPnOhAhfhmsy0hXBMzRGi-UkYhh7POVnVV0nBXBJaU_651zUz5TS_Ndor4DBTfwNN1KVYnQhY9QVY_Sx9gRbcaNkOoQU_dcW26wrqboVCFZ4mU5tU06n-XhxnD61F7LcFrtwl3XPogqhyphenhyphen/s1600/Screen+Shot+2020-03-05+at+5.58.16+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="110" data-original-width="510" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSPnOhAhfhmsy0hXBMzRGi-UkYhh7POVnVV0nBXBJaU_651zUz5TS_Ndor4DBTfwNN1KVYnQhY9QVY_Sx9gRbcaNkOoQU_dcW26wrqboVCFZ4mU5tU06n-XhxnD61F7LcFrtwl3XPogqhyphenhyphen/s400/Screen+Shot+2020-03-05+at+5.58.16+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 16. Fast PWM Output on D11.</div>
<div style="text-align: left;">
<br /></div>
<h3 style="text-align: left;">
Changing PWM Frequency using Registers</h3>
<br />
The ATmega328P has three timers known as Timer 0, Timer 1, and Timer 2. Timer 0 and Timer 2 are 8 bit timers, while Timer 1 is a 16 bit timer. Each timer has two output compare registers that control the PWM width for the timer's two outputs: when the timer reaches the compare register value, the corresponding output is toggled.<br />
<br />
For comparison, the ATmega2560 has 2 x 8 bit and 4 x 16 bit timers. Although the registers and timers may change, the process of setting up PWM is similar for both the 328P and the 2560.<br />
<br />
The difference between 8 bit and 16 bit timers is the resolution. 8 bits can represent 256 values (2^8) whereas 16 bits can represent 65536 values (2^16). The timer situation for the UNO's and MEGA's is summarised in Figure 17. These timer setups are done in the init() function mentioned earlier (Figure 15).<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;"><span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>Timer 0:</b>
Timer0 is a 8 bit timer.
For Arduino's, Timer0 is used for timer functions, delay(), millis() and micros().
<b>Timer 1:</b>
Timer1 is a 16 bit timer.
For Arduino's, the Servo library uses Timer1 in Uno's and Timer5 on Mega's.
<b>Timer 2:</b>
Timer2 is an 8 bit timer like Timer0.
In the Arduino work the tone() function uses Timer2.
<b>Timer 3, Timer 4, and Timer 5:</b>
Timers 3,4, & 5 are only available on Mega's. These timers are all 16 bit.</span></span></pre>
<div style="text-align: center;">
Figure 17. Arduino UNO and Mega Timer Summary</div>
<br />
Each of the timers has a prescaler that generates the timer clock by dividing the system clock by a prescale factor such as 1, 8, 64, 256, or 1024. The UNO and the MEGA both have a system clock speeds of 16MHz and the timer clock frequency will be the system clock frequency divided by the prescale factor.<br />
<br />
The ATmega328P has 6 PWM capable outputs and three timers. The relation between timers and PWM outputs is:<br />
<br />
<ul style="text-align: left;">
<li><b>Timer 0</b> controls Pins 5 and 6;</li>
<li><b>Timer 1</b> controls Pins 9 and 10; and</li>
<li><b>Timer 2</b> controls Pins 11 and 3.</li>
</ul>
<br />
Similarly for the ATmega2560:<br />
<br />
<ul style="text-align: left;">
<li><b>Timer 0</b> controls Pins 4 and 13;</li>
<li><b>Timer 1</b> controls Pins 11 and 12;</li>
<li><b>Timer 2</b> controls Pins 9 and 10;</li>
<li><b>Timer 3</b> controls Pin 2, 3 and 5;</li>
<li><b>Timer 4</b> controls Pin 6, 7 and 8; and</li>
<li><b>Timer 5</b> controls Pin 46, 45 and 44.</li>
</ul>
<br />
As the two processors use different timers for different pins, our register code will not be the same for the UNO and MEGA. It would have been nice if they could have kept the first three timer pin allocations the same between chips. The allocation above is how we know that we need to use Timer 1 for pin D11 on the ATmega2560.<br />
<br />
<pre class="chroma" style="background-color: #e7f0f5; font-weight: 700; margin: 1em;"><code class="language-arduino" data-lang="arduino"><span class="c1" style="color: #95a5a6;"> </span><span class="c1">// timers 1 and 2 are used for phase-correct hardware pwm
</span><span class="c1"></span> <span class="c1">// this is better for motors as it ensures an even waveform
</span><span class="c1"></span> <span class="c1">// note, however, that fast pwm mode can achieve a frequency of up
</span><span class="c1"></span> <span class="c1">// 8 MHz (with a 16 MHz clock) at 50% duty cycle</span></code></pre>
<div style="text-align: center;">
Figure 18. Comment from Arduino init()</div>
<br />
Refering to the comment in the Arduino init() function (Figure 18) we note that phase-correct hardware pwm is better for motors (this is also mentioned in the data sheet), so lets use that. The dual-slope phase-correct operation gives a lower maximum operation frequency compared to the single-slope modes, but it is high enough for our purposes.<br />
<br />
The default PWM mode set by init() for Timer 1 is mode 1 and we want mode 8 (PWM, Phase and Frequency Correct) - see Figure 10. In mode 8 we can adjust the PWM frequency using register ICR1. To get mode 8 we just set the WGM13 bit. We will use a non-inverting output as before so set the COM1A1 bit in TCCR1A.<br />
<br />
For reasons that will become apparent below, we set the prescaler (N) to 8, to do this, the CS11 bit in TCCR1B needs to be set.<br />
<br />
The trusty data sheet provides us with the frequency formula for phase and frequency correct PWM.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidPeIRv4-m3DVueuhWcITBqYMsw4retNOWjFlSvSyROd0NhfPRGenU9iaJKVllr1PZNhyphenhyphenqabIpOiPhzFtOOqpmg64wvX1QCBqYA69Y2BaZmKRxEYB13VqCMFGucFVfZHNyTGvLyhLBpvTq/s1600/Screen+Shot+2020-03-06+at+8.49.11+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="42" data-original-width="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidPeIRv4-m3DVueuhWcITBqYMsw4retNOWjFlSvSyROd0NhfPRGenU9iaJKVllr1PZNhyphenhyphenqabIpOiPhzFtOOqpmg64wvX1QCBqYA69Y2BaZmKRxEYB13VqCMFGucFVfZHNyTGvLyhLBpvTq/s1600/Screen+Shot+2020-03-06+at+8.49.11+am.png" /></a></div>
<br />
Where the N variable again represents the prescaler divider (1, 8, 64, 256, or 1024). For our settings, the calculation is:<br />
<br />
f<span style="font-size: xx-small;">PWM</span> = 16 MHz / (2 * 8 * ICR1) = 16000000 / (2 * 8 * 20000) = 50 Hz<br />
<br />
From this formula, it is apparent that we can adjust the PWM frequency by adjusting the value in register ICR1. It also explains why we use a prescaler of 8. The system clock is 16 MHz and to get the PWM frequency we divide by 2N. If we make 2N = 16 then the relationship between f<span style="font-size: xx-small;">PWM</span> and ICR1 (i.e. TOP) is straight forward. Rearranging the formula:<br />
<br />
ICR1 = 1MHz / f<span style="font-size: xx-small;">PWM</span><br />
<br />
For a f<span style="font-size: xx-small;">PWM</span> of 50 Hz, ICR1 = 1,000,000 / 50 = 20,000.<br />
<pre style="background: rgb(237, 237, 237); border: 1px solid silver; line-height: 1.7; margin-bottom: 1.7rem; margin-top: 1.7rem; overflow: auto; padding: 1.7rem; vertical-align: baseline;">DDRB |= 1 << DDB5; // Set D11 as an output pin<span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>
</b></span></span><span style="color: #666666; font-family: "consolas" , "monaco" , "lucida console" , monospace;"><span style="font-size: 12px;"><b>TCCR1A = 0;</b></span><b style="font-size: 12px;"> // Clear TCCR A & B bits</b><b style="font-size: 12px;">
TCCR1B = 0;</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1A = (1 << COM1A1); // Non-inverting output</b><span style="font-size: 12px;">
</span><b style="font-size: 12px;">TCCR1B = (1 << WGM13) | (1 << CS11); // Phase & Freq correct PWM, prescaler N = 8</b><span style="font-size: 12px;">
<b>ICR1 = 20000; // Freq = 50 Hz
OCR1A = 1500; // pulse width = 1500 us;</b></span></span></pre>
<div style="text-align: center;">
Figure 19. Register Code Phase & Frequency Correct PWM at 50 Hz.</div>
<br />
The results of the code in Figure 19 is shown in Figure 20. So for our tester we can adjust the pulse width using the value of register OCR1A and we can adjust the PWM frequency using ICR1A.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjalTLESHfVQiRoI-y8x-CyWxSvLHX-RogOxrAf6xo5SGTKAMTZmTwZ1HRURSU2_SJcdZaszM4Iit5-xA3_e3NUa6Xso-XV24XQ29Y7iXF2N0IaLmT4CBUvzoKNlLpQEIPn3NcFjnezJ4GB/s1600/Screen+Shot+2020-03-07+at+12.18.04+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="434" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjalTLESHfVQiRoI-y8x-CyWxSvLHX-RogOxrAf6xo5SGTKAMTZmTwZ1HRURSU2_SJcdZaszM4Iit5-xA3_e3NUa6Xso-XV24XQ29Y7iXF2N0IaLmT4CBUvzoKNlLpQEIPn3NcFjnezJ4GB/s1600/Screen+Shot+2020-03-07+at+12.18.04+pm.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 20. Phase & Frequency Correct PWM waveform at 50 Hz.</div>
<br />
We implemented this functionality on the Mega and were able to select the required frequency and pulse width using the rotary encoder (Figures 21 and 22).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs1JCZ3yo9aOmaPgsZUltEOKU82WsL3Nbu9ucY21mN2F7Us6u8E9zjJ_S4-Rc6L_d0FuEEz7BGWBBNWhl7wxsmgs5x6Zmn_9_buaLYpCYGq63-Y-qI4VI9aXFpybY_Z-bBQImjKh4Esd9F/s1600/IMG_0690.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs1JCZ3yo9aOmaPgsZUltEOKU82WsL3Nbu9ucY21mN2F7Us6u8E9zjJ_S4-Rc6L_d0FuEEz7BGWBBNWhl7wxsmgs5x6Zmn_9_buaLYpCYGq63-Y-qI4VI9aXFpybY_Z-bBQImjKh4Esd9F/s400/IMG_0690.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 21. PWM 50 Hz and Pulse Width of 1755 <span style="text-align: left;">µs</span> </div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX-LpMxPzVkUFYLLaKpqISZgT44Ja70TiLYHYht_gb9zZEhZr9kRpCv_k_2gBXOtcnwYIyRLQHVhDgj0AnafqnDD60J_WP002BorRp5eSomO6Vxdn_o65jKEDvDlNDUI2alVw-2NZht-rA/s1600/Screen+Shot+2020-03-09+at+5.42.39+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="505" height="101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX-LpMxPzVkUFYLLaKpqISZgT44Ja70TiLYHYht_gb9zZEhZr9kRpCv_k_2gBXOtcnwYIyRLQHVhDgj0AnafqnDD60J_WP002BorRp5eSomO6Vxdn_o65jKEDvDlNDUI2alVw-2NZht-rA/s400/Screen+Shot+2020-03-09+at+5.42.39+pm.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 22. Measured PWM waveform (setting 1755 <span style="text-align: left;">µs @ 50 Hz)</span></div>
<br />
<br />
The code for this partial implementation is available from the <a href="https://gist.github.com/reefwing/8025825f0ce9f0296737ff18de9cd70a" target="_blank">Reefwing Gist</a> repository. In Part 2 of this series we will develop a custom Arduino shield to implement the servo testing functionality. In Part 3 we will add some common ESC digital protocols (e.g. oneshot).</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-5890614006976221132019-09-24T23:42:00.003-07:002019-09-24T23:42:58.480-07:00Programming the ATmega328P ADC Registers<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Programming the ATmega328P Registers</h3>
<div>
<br /></div>
<div style="text-align: left;">
<span style="font-size: small; font-weight: 400;">This is the second article that I have written regarding programming the ATmega328P registers. In the first article we looked at how we could blink an LED using the hardware registers and interrupts. Now we will examine the ADC and how we can use it to measure voltage on one of the Analogue Inputs (AI's) of the Arduino UNO. </span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The Arduino IDE libraries make it trivial to read the voltage on an AI: </div>
<div style="text-align: left;">
<span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div>
<div style="text-align: left;">
<span style="color: blue; font-size: small;"><span style="font-weight: 400;">int value = analogRead(A0); </span></span></div>
<div style="text-align: left;">
<span style="font-size: small;"><span style="font-weight: 400;"><br /></span></span></div>
<div style="text-align: left;">
Using default settings, a return value of 0 would represent 0V, and a return value of 1023 (the maximum) would represent approximately 5V. By understanding what is going on behind the scenes you can go beyond this basic implementation and do things like:</div>
<ul style="text-align: left;">
<li>Change the conversion speed via the pre-scaler;</li>
<li>Use different reference voltages;</li>
<li>Make ADC reading non-blocking;</li>
<li>Use an interrupt which returns when the value is read;</li>
<li>Read other things such as the internal chip temperature, GND and VCC;</li>
</ul>
<br />
<br />
<h3 style="text-align: left;">
ATmega328P Analogue to Digital Converter (ADC)</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg576p0ahd56mUyZHpBFcFSSdRK2zXCrYw0We51qgQghR1f5YRxgcO4gdekzMgVJREMD80prEcitM2sI4rrqUAFldLoAPJhRM5IxAAYp1u_zkh-UsNCk_dxtSNGVPzUpDQDAj1B-nMv1Pmk/s1600/ADC.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="935" data-original-width="1600" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg576p0ahd56mUyZHpBFcFSSdRK2zXCrYw0We51qgQghR1f5YRxgcO4gdekzMgVJREMD80prEcitM2sI4rrqUAFldLoAPJhRM5IxAAYp1u_zkh-UsNCk_dxtSNGVPzUpDQDAj1B-nMv1Pmk/s400/ADC.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 1. ATmega328P ADC Simplified Block Diagram.</span></div>
<br />
The Arduino ATmega328P has a 10-bit ADC which means it can return 2^10 (i.e. 0 – 1023) values. This is where the 1024 comes from in the equation from the data sheet:<br />
<br />
ADC = (Vin*1024)/Vref<br />
<br />
If you want to convert the ADC value to a voltage use the following formula (as the hardware rounds down):<br />
<br />
<span style="color: blue;">float voltage = ((float) rawADC + 0.5 ) / 1024.0 * Vref;</span><br />
<br />
<h3 style="text-align: left;">
Select the ADC Voltage Range</h3>
<br />
In order to convert an analog voltage to a digital value on any ADC, the converter has to be provided with the range of voltages. The lower limit is always GND on the Arduino (i.e. 0V) but you can select one of three sources to serve as the high reference:<br />
<div style="text-align: left;">
</div>
<ul style="text-align: left;">
<li><b>AREF</b> - This is a separate pin on the microcontroller that can be used to provide any high reference voltage you wish to use as long as it’s in the range of 1.0V to VCC. On the Uno it’s wired to one of the black headers. </li>
<li><b>AVCC </b>- This pin on the microcontroller provides power to the ADC circuitry on the chip. On the Uno it is connected to VCC. This is the simplest option to use provided AVCC is connected to VCC. </li>
<li><b>1.1V</b> - The microcontroller has an internal 1.1V reference voltage that can be used</li>
</ul>
Regardless of the source selected, the data sheet advises putting a capacitor between AREF and ground to smooth out the voltage on that pin. Table 24-3 (data sheet) is used to select which voltage reference you want to use. Note that if you use either of the internal voltages references (AVCC or 1.1V) then that voltage is connected to the AREF pin internally. In this situation, do not connect any other voltage sources to that pin or it will be shorted to the internal reference (and probably let out the magic smoke).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhysHTCXTqCu0db8E8ELbpx3naZcxclm36EEeBD959gWau30qwBEilBJ478C2kXmYiinzv2DT9hSfqsQvKZ-udiWpJglo0D9fiOsa4vxLtcFgjj2tfiD1QvQ-5VOZRXioMwrXCnIRPLfG0C/s1600/Screen+Shot+2019-09-21+at+7.49.33+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="183" data-original-width="749" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhysHTCXTqCu0db8E8ELbpx3naZcxclm36EEeBD959gWau30qwBEilBJ478C2kXmYiinzv2DT9hSfqsQvKZ-udiWpJglo0D9fiOsa4vxLtcFgjj2tfiD1QvQ-5VOZRXioMwrXCnIRPLfG0C/s400/Screen+Shot+2019-09-21+at+7.49.33+pm.png" width="400" /></a></div>
<br />
I would default to AVCC unless you had a reason to do otherwise. This will give you a nominal 0 - 5V range.<br />
<br />
Note that all 8 AI’s on the UNO are connected to the same ADC (see Figure 1). So you can only sample one input at a time. That’s what table 24-4 (data sheet) and the ADMUX register is used for.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh__ywKJre5cz1LdFZQpyLxgpnFcc7pCsQzRLJMUzeO3cAcDrPrhDpaMVljifp-hE8ZvFaQVtDJGph6mswfWNw_2WXZTv32i0iIiED2cy-V-1jRQGZ9QPySzXjCEb7qwnozBn6xE9WiOe06/s1600/Screen+Shot+2019-09-21+at+7.49.26+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="554" data-original-width="749" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh__ywKJre5cz1LdFZQpyLxgpnFcc7pCsQzRLJMUzeO3cAcDrPrhDpaMVljifp-hE8ZvFaQVtDJGph6mswfWNw_2WXZTv32i0iIiED2cy-V-1jRQGZ9QPySzXjCEb7qwnozBn6xE9WiOe06/s400/Screen+Shot+2019-09-21+at+7.49.26+pm.png" width="400" /></a></div>
<br />
<h3 style="text-align: left;">
ADC Control Registers (ADCSRA and ADCSRB)</h3>
<br />
The ADC module of the ATmega328P has two control and status registers, ADCSRA and ADCSRB. For basic ADC operations only the bits in the ADMUX and ADCSRA register have to be modified.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcOmrluViYDcOXfca6HA100tVIMp-zSj6i_8hsORRfVbebO83AHQ1y2s5_G8Xi7Ihqjw4q9-so5X2y3olcrxFjW6q16dCU2VpYgyEOZlCuTVbhBLlWXwJQHO9rqwoTrpRgdzNjhgOiliAX/s1600/PastedGraphic-11.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="208" data-original-width="1600" height="52" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcOmrluViYDcOXfca6HA100tVIMp-zSj6i_8hsORRfVbebO83AHQ1y2s5_G8Xi7Ihqjw4q9-so5X2y3olcrxFjW6q16dCU2VpYgyEOZlCuTVbhBLlWXwJQHO9rqwoTrpRgdzNjhgOiliAX/s400/PastedGraphic-11.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 2. ADMUX Register</span></div>
<br />
Assuming we are using AVCC, from Table 24-3 we need REFS1 = 0 and REFS0 = 1. To get a 10 bit result, ADLAR = 1, and if we are using A0 as our input then from Table 24-4, MUX3-0 = 0000. Thus<br />
<br />
ADMUX = 0b01000000<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji-VhUS6At4E-9VkDTbhTyWcmbUM3BEQ4Fdit1QSZIL_8hlhyQS7izZFYGPZdxXkoSZxT-Gp5vPPthFEvOt1OXEsmApMOPRFtth6lFe-jxDF0Rl9uHIptSjXcymcyyYakjYumLGPCAh9Rq/s1600/PastedGraphic-8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="1600" height="57" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEji-VhUS6At4E-9VkDTbhTyWcmbUM3BEQ4Fdit1QSZIL_8hlhyQS7izZFYGPZdxXkoSZxT-Gp5vPPthFEvOt1OXEsmApMOPRFtth6lFe-jxDF0Rl9uHIptSjXcymcyyYakjYumLGPCAh9Rq/s400/PastedGraphic-8.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 3. ADCSRA Register</span></div>
<br />
The things we need to worry about for ADCSRA are:<br />
<br />
<b>Bit 7 - </b>The ADEN bit enables the ADC module. Must be set to 1 to do any ADC operations.<br />
<br />
<b>Bit 6 - </b>Setting the ADSC bit to a 1 initiates a single conversion. This bit will remain a 1 until the conversion is complete. If your program using the polling method to determine when the conversion is compete, it can test the state of this bit to determine when it can read the result of the conversion from the data registers. As long as this bit is a one, the data registers do not yet contain a valid result.<br />
<br />
<b>Bit 5 -</b> ADATE: ADC Auto Trigger Enable. When this bit is written to one, Auto Triggering of the ADC is enabled. The ADC will start a conversion on a positive edge of the selected trigger signal. The trigger source is selected by setting the ADC Trigger Select bits, ADTS in ADCSRB. We don't want auto triggering so select 0 for this bit.<br />
<br />
<b>Bit 4 - </b>ADIF: ADC Interrupt Flag. This bit is set when an ADC conversion completes and the Data Registers are updated. The ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set. ADIF is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt can be disabled. This also<br />
applies if the SBI and CBI instructions are used. Set ADIF to 0.<br />
<br />
<b>Bit 3 -</b> Setting the ADIE bit to a 1 enables interrupts. An interrupt will be generated on the completion of a conversion. The interrupt vector name is “ADC_vect”.<br />
<br />
<b>Bits 2:0 -</b> The ADPS2, ADPS1 and ADPS0 bits selects the pre-scaler divisor value. Those available are:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjji92dSj8zFQb36KmTQp9UvzgG90uZzJFA_t1Qxv6gtbR-mxtHY23J2CWC6ADcfOKHMtYfZ93JPUhqfWsSkvvSO7IfJ_AGnGUojqk1SZh2vXedgSHpun1Fyg458nMvGzKZHUbRA9VVeOiq/s1600/PastedGraphic-9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="908" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjji92dSj8zFQb36KmTQp9UvzgG90uZzJFA_t1Qxv6gtbR-mxtHY23J2CWC6ADcfOKHMtYfZ93JPUhqfWsSkvvSO7IfJ_AGnGUojqk1SZh2vXedgSHpun1Fyg458nMvGzKZHUbRA9VVeOiq/s400/PastedGraphic-9.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 4. ADC Pre-Scaler Table</span></div>
<br />
The ADC circuitry needs to have a clock signal provided to it in the range of 50kHz to 200kHz. The ATmega328P clock is too fast (16MHz on the Uno) so the chip includes an adjustable pre-scaler to divide the processor clock down to something usable. The processor clock speed is divided by the pre-scaler value to give an ADC clock speed. Using a lower pre-scaler will make the conversion faster but at the cost of accuracy.<br />
<br />
The lowest usable value is a pre-scaler of 16 for the UNO. The analogRead library uses a pre-scaler of 128 in order to get maximum resolution. Unless you understand the consequences, stick with 128.<br />
<br />
The value for ADCSRA is going to depend on what conversion approach you use (see below).<br />
<br />
<h3 style="text-align: left;">
ADC Data Register (ADCH and ADCL - high and low bytes)</h3>
<br />
The results of the conversion are stored in the two bytes of the Data Register. The most significant bits of the result are stored in ADCH and the least significant bits are in ADCL. For 10-bit conversion, the ADLAR bit in the ADMUX register should be zero.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD7hsrIFxOUj4C-v6gPvgGedqjHc0PqwYUj-05tJzBKdH5cCZf68KC4zHgygjdwkcoEyTe1eTqne1ocFLtlJKbDy0qezR4HJtLDfcp-j0yJHNTAP-8FPIGRz_ktRk3_x1eBL_eZG0O0V1D/s1600/PastedGraphic-10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="385" data-original-width="1600" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD7hsrIFxOUj4C-v6gPvgGedqjHc0PqwYUj-05tJzBKdH5cCZf68KC4zHgygjdwkcoEyTe1eTqne1ocFLtlJKbDy0qezR4HJtLDfcp-j0yJHNTAP-8FPIGRz_ktRk3_x1eBL_eZG0O0V1D/s400/PastedGraphic-10.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 5. ADC Data Registers</span></div>
<br />
When using the 10-bit results (ADLAR=0), the results can be read into your program with:<br />
<br />
<span style="color: blue;">int value = ADC; </span><br />
<br />
The ADC measures voltage by charging an internal 14 pF capacitor and then measures that voltage with successive approximations. The ADC takes 13 ADC clock cycles to perform a conversion, except the first time the ADC is enabled, at which point it takes 25 ADC cycles, due to the initialisation overhead. The ADC Sample and Hold takes approximately 12μs and the entire conversion process can take up to 260 μs (depending on the pre-scaler selected). So there are at least 3 ways you can approach this:<br />
<ol style="text-align: left;">
<li>Put a long enough delay in your while loop so you know the conversion is done. This is the least elegant method!</li>
<li>Set the ADSC bit in ADCSRA to a one. This starts the first conversion. Then poll the ADSC bit in ADCSRA until it becomes zero and read the ADC value.</li>
<li>Use the ADC interrupt and handle the reading in the associated ISR - ADC_vect()</li>
</ol>
I suggest using approaches 2 or 3.<br />
<br />
Don’t forget that you need to set the ADSC bit in ADCSRA to one, every time you want to do a conversion.<br />
<br />
<h3 style="text-align: left;">
Sample ADC Register Polling Code</h3>
<br />
To cement the information above, I will provide some sample code to read the ADC using registers. The first example uses the polling technique (approach 2 above).<br />
<br />
<script src="https://gist.github.com/reefwing/5c53d689fce0cb802cc074960605daec.js"></script><br />
A few notes about this code:<br />
<ul style="text-align: left;">
<li>We need to use the standard Arduino loop() to allow serial events to be handled (i.e. the printing out of the result to the serial monitor).</li>
<li>C5:: The delay(500) is just there to enable us to see the printed result. It is not functionally required, it is the job of the polling (i.e. checking the ADSC bit) to ensure the result is ready.</li>
<li>With nothing connected to A0, the pin is floating and I was reading values of around 650 (but this could be anything due to electrical noise from the environment, or capacitively coupling with a nearby pin.). Connect A0 to GND and you should see 0, while connecting it to 5V should show 1023.</li>
</ul>
<br />
<br />
<h3 style="text-align: left;">
Sample ADC Register Interrupt Code</h3>
<br />
For our final example we will measure the ADC using interrupts.<br />
<br />
<script src="https://gist.github.com/reefwing/2640f868664f7561425378c4f93c7c6f.js"></script><br />
Regarding the interrupt version of the code:<br />
<ul style="text-align: left;">
<li>We have to enable interrupts by setting the ADIE bit of the ADCSRA register.</li>
<li>The sei() command is optional, setting ADIE is sufficient to enable this interrupt.</li>
<li>Note we try to do as little as possible in the ISR.</li>
<li>It is a little bit more complicated than the polling version, but not much.</li>
<li>As with the polling example if nothing is connected to A0, then the pin is floating and you will get a random result. Connect A0 to GND and you should see 0, while connecting it to 5V should show 1023.</li>
</ul>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com8tag:blogger.com,1999:blog-1323683415527527391.post-67785449269104808962019-09-21T01:17:00.003-07:002019-09-21T01:20:42.203-07:00Programming the ATmega328P Registers and Interrupts<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Why Use Register Programming?</h3>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-yTVWppoBbF-mSBydMtheNRAWoFJi8RQb0p8VK3WBMJ76afU11YtoDL_uDTghTVufbXsuyfyInlzVdbA7_EnzidBycONMGekODGDVdkYcQjZ2y84Hy3rFuFOvT6ZUgrIDI5yI4kvXTcLb/s1600/image-19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="765" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-yTVWppoBbF-mSBydMtheNRAWoFJi8RQb0p8VK3WBMJ76afU11YtoDL_uDTghTVufbXsuyfyInlzVdbA7_EnzidBycONMGekODGDVdkYcQjZ2y84Hy3rFuFOvT6ZUgrIDI5yI4kvXTcLb/s400/image-19.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 1. The registers of interest</div>
<br />
Normally you wouldn't bother to use register programming for the Arduino family. The libraries provided with the Arduino IDE do all the heavy lifting and make it easy to program the microprocessor without knowing exactly how it works. This convenience and readability is not without a cost though and sometimes for reasons of speed, code size or power consumption you will need to get closer to the metal. An example of this is writing a flight controller for a drone. For a realtime application like this (depending on the Arduino model) you are probably going to need to directly access the I/O registers and interrupts.<br />
<br />
I’m afraid this is a fairly tedious way to code! I will try to explain why we are selecting the values in the code, otherwise it looks like gibberish! The comment numbers (e.g. C1) are referenced in the explanation below.<br />
<br />
<h3 style="text-align: left;">
Hello World AKA Blink</h3>
<br />
The hardware equivalent of Hello World is to blink a LED. To demonstrate what you can do with registers and interrupts we will start with that example. There are many different ways to write this code. The complete listing is shown below.<br />
<br />
<script src="https://gist.github.com/reefwing/e12c709087a0d028b2d19456974bd9f0.js"></script><br />
<b>C1:: </b>We are using Timer 0 which is an 8 bit timer with two independent Output Compare Units, and PWM support (see Figure 1). The PWM outputs are mapped to D5 and D6 but we don’t need these here. We want to detect when the counter reaches the value stored in the OCR0A Register. The Output Compare Registers (OCR0A and OCR0B) are compared with the Timer/Counter value and can be used to generate an Output Compare interrupt request. We can use this to toggle our LED.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzgkYSKSO3ttZoqaTo7Pd60fF-by6ZfKXy4A8JcPbRzaWmbUKVbr2pzabA64sKZMoSdUwfi7nIrGRMsKcAha0yunnEI0WTJZ0U4LE2qVyX974rlbk13eX5wOXHAlC0S1IGl3ReC3bm-T_y/s1600/PastedGraphic-3.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="74" data-original-width="584" height="50" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzgkYSKSO3ttZoqaTo7Pd60fF-by6ZfKXy4A8JcPbRzaWmbUKVbr2pzabA64sKZMoSdUwfi7nIrGRMsKcAha0yunnEI0WTJZ0U4LE2qVyX974rlbk13eX5wOXHAlC0S1IGl3ReC3bm-T_y/s400/PastedGraphic-3.tiff" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVqd8vlGEYkA5RynLUEUGMZu0aO0n9yaSpKwvlZNGJXuxbMIVXDG-Om8n9kyGPLAzC-sQb-JUeVR45d30AYqReATH4yBsHSpzJEi_Vr5peRXHYrBiv_YV6pg8WrVTmVX-25pTGnWfp2jPQ/s1600/PastedGraphic-4.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="49" data-original-width="588" height="32" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVqd8vlGEYkA5RynLUEUGMZu0aO0n9yaSpKwvlZNGJXuxbMIVXDG-Om8n9kyGPLAzC-sQb-JUeVR45d30AYqReATH4yBsHSpzJEi_Vr5peRXHYrBiv_YV6pg8WrVTmVX-25pTGnWfp2jPQ/s400/PastedGraphic-4.tiff" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 2. TCCR0A & TCCR0B Registers </div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
The meaning of the TCCR0A & TCCR0B register bits are shown in Figure 2. You turn on the bits required in these registers to get a certain behaviour. To work out what does what, have a look at Figure 3.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFWQ1VXBwrRCQj4xFR7OJ5IwYA0nD5LJpihm5uSV6kdsaHajMFgoxSKDiHY3hjBNUxztTxRLQPHJ2o4wO-j3_hDxHKArUlXHwCaOOuU2LQ2GA2pVzaEB0UmWmgovzvBotDatxOxtMY80pG/s1600/PastedGraphic-5.tiff" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="385" data-original-width="563" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFWQ1VXBwrRCQj4xFR7OJ5IwYA0nD5LJpihm5uSV6kdsaHajMFgoxSKDiHY3hjBNUxztTxRLQPHJ2o4wO-j3_hDxHKArUlXHwCaOOuU2LQ2GA2pVzaEB0UmWmgovzvBotDatxOxtMY80pG/s400/PastedGraphic-5.tiff" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 3. Explanation of Register Bits</div>
<br />
We want CTC mode 2. So the Waveform Generator Mode (WGM01) bit needs to be 1. That is:<br />
<br />
TCCR0A = 0b00000010;<br />
<br />
another way to write this is:<br />
<br />
TCCR0A = (1 << WGM01);<br />
<br />
<b>C2:: </b>The Timer/Counter can be clocked internally, via the pre-scaler, or by an external clock source on the T0 pin. We will use the pre-scaler set to 256. The clock source is selected by the Clock Select logic which is controlled by the Clock Select (CS) bits located in the Timer/Counter Control Register (TCCR0B). For TCCR0B to get a pre-scaler of 256, CS02 needs to be 1 (see Figure 3).<br />
<br />
TCCR0B = 0b00000100;<br />
<br />
or<br />
<br />
TCCR0B = (1 << CS02);<br />
<br />
<b>C3:: </b>Next we set the Output Compare Register. The number of ticks for a delay of 4ms is 250, so let's run with that.<br />
<br />
OCR0A = 250;<br />
<br />
<b>C4:: </b>When the timer/counter reaches the OCR0A number, an interrupt will be triggered by setting the OCIE1A flag in TIMSK1. We can do that by:<br />
<br />
TIMSK0 = 0b00000010;<br />
<br />
or<br />
<br />
TIMSK1 = (1 << OCIE1A);<br />
<br />
The specific interrupt vector that will be called for this CTC event is:<br />
<br />
<span class="pl-en" style="background-color: white; color: #6f42c1; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 12px; white-space: pre;">ISR</span><span style="background-color: white; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 12px; white-space: pre;">(TIMER0_COMPA_vect)</span><br />
<br />
As an aside, a list of the available AVR interrupt vectors can be found at: <a href="http://ee-classes.usc.edu/ee459/library/documents/avr_intr_vectors/">http://ee-classes.usc.edu/ee459/library/documents/avr_intr_vectors/</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirg9KZ5kxYExMd784tmQp9hx0j83KviJVDlc92j5A0Guv4VzyckSfq6lYzhnPN1vGRqoOGah_xiz4d7D5yPE47SqSP3l00uAaB3TaSTldVUExKoAQm1OhpoJ5UfWb3vlm-M18L3qD6mdrH/s1600/portb-bites.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="407" data-original-width="789" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirg9KZ5kxYExMd784tmQp9hx0j83KviJVDlc92j5A0Guv4VzyckSfq6lYzhnPN1vGRqoOGah_xiz4d7D5yPE47SqSP3l00uAaB3TaSTldVUExKoAQm1OhpoJ5UfWb3vlm-M18L3qD6mdrH/s400/portb-bites.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Figure 4. Port B Registers</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<b>C5:: </b>I used digital output D13 since it is attached to the onboard LED and saves me wiring one up, but obviously you can use any output pin. Here we are using the Data Direction Register (DDR) to set D13 as an output (see Figure 4).<br />
<br />
DDRB = 0b00100000;<br />
<br />
<b>C6:: </b>We need to set the global interrupt flag to enable interrupts:<br />
<br />
sei();<br />
<br />
<b>C7:: </b>Finally, we need the Interrupt Service Routine which is called when an interrupt occurs. All we do here is toggle D13 which turns the LED on and off (very quickly)! With a LED toggling every 4ms, it just looks on all the time albeit a bit dimmer. We are effectively using PWM to dim the LED, but we want to be able to see the blinks so we use the extraTime variable to slow things down.<br />
<div>
<br /></div>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-83463265931183973042019-08-19T00:51:00.001-07:002019-08-19T01:05:07.992-07:00Tello Drone, Swift and State Machines (Part 2)<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Stop Rolling Your Own State Machine Code</h3>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguTwGtMj9YIYQtYEzgmDd8UtGDhyjgyq8CXtltXzKCGm7_hOD8hhUuni36nzoiH2dT94GS4W9IC_YZnyqIfoC0NQ647Upr5A8a8_YBk1xRbpLeWWsCOCqt4vcZUhOhQUO-JhINPR9xPbmU/s1600/IMG_2187.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguTwGtMj9YIYQtYEzgmDd8UtGDhyjgyq8CXtltXzKCGm7_hOD8hhUuni36nzoiH2dT94GS4W9IC_YZnyqIfoC0NQ647Upr5A8a8_YBk1xRbpLeWWsCOCqt4vcZUhOhQUO-JhINPR9xPbmU/s400/IMG_2187.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">FIGURE 1. The Flight Plan iOS App</span></div>
<br />
<br />
This sub heading is aimed at me to serve as a reminder to stop reinventing the wheel! A lot of the apps that I write benefit from having a <a href="https://en.wikipedia.org/wiki/Finite-state_machine">Finite State Machine</a> computational model. In an earlier article I wrote about <a href="https://reefwingrobotics.blogspot.com/2019/06/programming-tello-drone-using-swift.html">controlling the Tello drone remotely using Swift</a>. If you have a look at this code you will see that I have implemented a simple state machine to track the state of the drone. You need this because you can't send the drone a command unless WiFi is connected and the drone is in command mode (activated by sending it the "command" string via UDP). Thus our app responds differently depending on what state the drone is in.<br />
<br />
I felt justified in writing my own state machine code because the initial application was relatively simple. If I was writing a game then I would always use GKStateMachine, the state machine class provided by Apple as part of game kit, but because this is a utility and I was in the UIKit headspace as opposed to the SceneKit/GameplayKit space I didn't think about it. But there is no reason you can't use GameplayKit classes in your UIKit app and in retrospect that is what I should have done (and just spent a day refactoring my code to do). Insert face palm emoji here!<br />
<br />
I have continued to add functionality to my drone control app and as the complexity increased my home grown state machine started to become part of the problem and not the solution. Due to the organic development process (i.e. unstructured), I ended up with two state machines which were not scaling well. More importantly the app was acting weird and ending up in undefined states. Of course I could have fixed this in time, but I realised that Apple have already spent a lot of time putting together a robust state machine class and I should be using that!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCsDSRziRsFblA6vx6pnPwuJ34eqaJFxp7bRzGzoyLtBPkPpz4RSq1NGHESKC-qdGbgngfmee5uZpfzkHVsMe32Rwn1w8XDim0e6Rfth4KMCGYOwIS7BGcQy-hhW0lVlOLLaVbz52w9NV7/s1600/Falcon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCsDSRziRsFblA6vx6pnPwuJ34eqaJFxp7bRzGzoyLtBPkPpz4RSq1NGHESKC-qdGbgngfmee5uZpfzkHVsMe32Rwn1w8XDim0e6Rfth4KMCGYOwIS7BGcQy-hhW0lVlOLLaVbz52w9NV7/s400/Falcon.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">FIGURE 2. Drone State Machine Diagram</span></div>
<br />
The collateral benefit of having to refactor my code using GKStateMachine was that it made me sit down and plan out what states I needed and what would cause a transition. In other words I needed to develop a state transition table or diagram (Figure 2). After doing this exercise it became apparent that I didn't need two state machines, I just needed to add two states to the original machine. In addition, being forced to come up with the table made me think about some states and/or transitions that I wasn't handling.<br />
<br />
<b><span style="color: blue;">TL;DR - Use GKStateMachine even for simple applications!</span></b><br />
<br />
To demonstrate how easy it is, I will include the boiler plate code for my drone app.<br />
<br />
<h3 style="text-align: left;">
STEP 1 - Create the state classes</h3>
<br />
For every state in your FSM you need a class to handle transitions, etc. Typically you will need to override the functions shown. I have included the outline for the disconnected state class below. The other state classes have exactly the same format but with different names.<br />
<br />
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>DisconnectedState.swift</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>FlightPlan</span></div>
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>Created by David Such on 18/8/19.</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>Copyright © 2019 Kintarla Pty Ltd. All rights reserved.</span></div>
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p2">
<br /></div>
<div class="p3">
<span class="s1">import</span> Foundation</div>
<div class="p3">
<span class="s1">import</span> GameplayKit</div>
<div class="p2">
<br /></div>
<div class="p3">
<span class="s1">class</span> DisconnectedState: <span class="s2">GKState</span> {</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">unowned</span> <span class="s1">let</span> viewController: <span class="s3">ViewController</span></div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">init</span>(viewController: <span class="s3">ViewController</span>) {</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">self</span>.<span class="s3">viewController</span> = viewController</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">super</span>.<span class="s2">init</span>()</div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">override</span> <span class="s1">func</span> didEnter(from previousState: <span class="s2">GKState</span>?) {</div>
<div class="p4">
<span class="s4"><span class="Apple-converted-space"> </span></span>viewController<span class="s4">.</span>statusLabel<span class="s4">.</span><span class="s5">text</span><span class="s4"> = </span><span class="s6">"DISC"</span></div>
<div class="p4">
<span class="s4"><span class="Apple-converted-space"> </span></span>viewController<span class="s4">.</span>WiFiImageView<span class="s4">.</span><span class="s5">image</span><span class="s4"> = </span><span class="s2">UIImage</span><span class="s4">(named: </span><span class="s6">"WiFiDisconnected"</span><span class="s4">)</span></div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">if</span> !<span class="s2">UserDefaults</span>.<span class="s5">standard</span>.<span class="s3">warningShown</span> {</div>
<div class="p5">
<span class="s4"><span class="Apple-converted-space"> </span></span><span class="s3">viewController</span><span class="s4">.</span><span class="s8">showAlert</span><span class="s4">(title: </span>"Not Connected to Tello WiFi"<span class="s4">, msg: </span>"In order to control the Tello you must be connected to its WiFi network. Turn on the Tello and then go to Settings -> WiFi to connect."<span class="s4">)</span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s2">UserDefaults</span>.<span class="s5">standard</span>.<span class="s3">warningShown</span> = <span class="s1">true</span></div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">override</span> <span class="s1">func</span> willExit(to nextState: <span class="s2">GKState</span>) {</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">override</span> <span class="s1">func</span> isValidNextState(<span class="s1">_</span> stateClass: <span class="s5">AnyClass</span>) -> <span class="s5">Bool</span> {</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">return</span> (stateClass == <span class="s3">WiFiUpState</span>.<span class="s1">self</span>) || (stateClass == <span class="s3">PlanningState</span>.<span class="s1">self</span>)</div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">override</span> <span class="s1">func</span> update(deltaTime seconds: <span class="s5">TimeInterval</span>) {</div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span>}</div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #007400; background-color: #ffffff}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff; min-height: 13.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #3f6e74; background-color: #ffffff}
p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #c41a16; background-color: #ffffff}
span.s1 {color: #aa0d91}
span.s2 {color: #0000ff}
span.s3 {color: #3f6e74}
span.s4 {color: #000000}
span.s5 {color: #5c2699}
span.s6 {color: #c41a16}
span.s7 {color: #1c00cf}
span.s8 {color: #26474b}
span.s9 {color: #2e0d6e}
</style>
<br />
<div class="p3">
}</div>
<br />
A couple of points. Firstly, make sure that you import GameplayKit. Second, note the constant definition:<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
span.s1 {color: #aa0d91}
span.s2 {color: #3f6e74}
</style>
<br />
<div class="p1">
<span class="s1">unowned</span> <span class="s1">let</span> viewController: <span class="s2">ViewController</span></div>
<br />
In my app this is the main view controller which contains the UI and will never be NIL. To prevent a retain cycle we use unowned (and not weak since that view controller can never be NIL).<br />
<br />
This constant is used to update the UI based on state changes (alternatively you could use a delegate).<br />
<br />
<h3 style="text-align: left;">
STEP 2 - Define the State Machine</h3>
<br />
Next, within the view controller referred to in step 1, you need to define your state machine.<br />
<br />
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>ViewController.swift</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>FlightPlan</span></div>
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>Created by David Such on 3/6/19.</span></div>
<div class="p1">
<span style="color: #38761d;">//<span class="Apple-converted-space"> </span>Copyright © 2019 Kintarla Pty Ltd. All rights reserved.</span></div>
<div class="p1">
<span style="color: #38761d;">//</span></div>
<div class="p2">
<br /></div>
<div class="p3">
<span class="s1">import</span> UIKit</div>
<div class="p3">
<span class="s1">import</span> GameplayKit</div>
<div class="p2">
<br /></div>
<div class="p4">
<span class="s1">class</span><span class="s2"> ViewController: </span><span class="s3">UIViewController</span><span class="s2"> {</span></div>
<div class="p2">
<span class="Apple-converted-space"> </span></div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s1">lazy</span> <span class="s1">var</span> stateMachine: <span class="s3">GKStateMachine</span> = <span class="s3">GKStateMachine</span>(states: [</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">DisconnectedState</span>(viewController: <span class="s1">self</span>),</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">WiFiUpState</span>(viewController: <span class="s1">self</span>),</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">CommandState</span>(viewController: <span class="s1">self</span>),</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">PlanningState</span>(viewController: <span class="s1">self</span>),</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">ManualState</span>(viewController: <span class="s1">self</span>),</div>
<div class="p3">
<span class="Apple-converted-space"> </span><span class="s4">AutoPilotState</span>(viewController: <span class="s1">self</span>)</div>
<div class="p1">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #007400; background-color: #ffffff}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff; min-height: 13.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #5c2699; background-color: #ffffff}
span.s1 {color: #aa0d91}
span.s2 {color: #000000}
span.s3 {color: #0000ff}
span.s4 {color: #3f6e74}
span.s5 {color: #c41a16}
span.s6 {color: #5c2699}
</style>
</div>
<div class="p3">
<span class="Apple-converted-space"> </span>])</div>
<br />
As shown above, this is very straight forward. A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration. We need this so that we can assign a pointer to the class containing our state machine (i.e. viewController which is an instance of ViewController) after it has been initialised.<br />
<br />
<h3 style="text-align: left;">
STEP 3 - Use the State Machine</h3>
<br />
Now we can use our new state machine to keep track of the drone state and handle transitions between states. The first thing you will want to do is to set the initial state. For our drone this is the disconnected state.<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #3f6e74; background-color: #ffffff}
span.s1 {color: #000000}
span.s2 {color: #2e0d6e}
span.s3 {color: #aa0d91}
</style>
<br />
<div class="p1">
stateMachine<span class="s1">.</span><span class="s2">enter</span><span class="s1">(</span>DisconnectedState<span class="s1">.</span><span class="s3">self</span><span class="s1">)</span></div>
<br />
You will probably do this in the viewDidLoad method of viewController. Then you can change states when the appropriate event is triggered. For example, the following method is called when the take off button is tapped.<br />
<br />
<div class="p1">
<span class="s1">@IBAction</span> <span class="s1">func</span> takeOffTapped(<span class="s1">_</span> sender: <span class="s2">UIButton</span>) {</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">switch</span> <span class="s3">stateMachine</span>.<span class="s4">currentState</span> {</div>
<div class="p2">
<span class="s5"><span class="Apple-converted-space"> </span></span><span class="s1">case</span><span class="s5"> </span><span class="s1">is</span><span class="s5"> </span>DisconnectedState<span class="s5">:</span></div>
<div class="p3">
<span class="s5"><span class="Apple-converted-space"> </span></span><span class="s6">showAlert</span><span class="s5">(title: </span>"Not Connected to Tello WiFi"<span class="s5">, msg: </span>"In order to control the Tello you must be connected to its WiFi network. Turn on the Tello and then go to Settings -> WiFi to connect."<span class="s5">)</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">case</span> <span class="s1">is</span> <span class="s3">WiFiUpState</span>:</div>
<div class="p3">
<span class="s5"><span class="Apple-converted-space"> </span></span><span class="s6">showAlert</span><span class="s5">(title: </span>"Awaiting CMD Response"<span class="s5">, msg: </span>"We haven't received a valid response to our initialisation command. Try sending again from Setup."<span class="s5">)</span></div>
<div class="p2">
<span class="s5"><span class="Apple-converted-space"> </span></span><span class="s1">case</span><span class="s5"> </span><span class="s1">is</span><span class="s5"> </span>CommandState<span class="s5">:</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s3">tello</span>.<span class="s6">takeOff</span>()</div>
<div class="p2">
<span class="s5"><span class="Apple-converted-space"> </span></span>stateMachine<span class="s5">.</span><span class="s7">enter</span><span class="s5">(</span>ManualState<span class="s5">.</span><span class="s1">self</span><span class="s5">)</span></div>
<div class="p2">
<span class="s5"><span class="Apple-converted-space"> </span></span><span class="s1">case</span><span class="s5"> </span><span class="s1">is</span><span class="s5"> </span>PlanningState<span class="s5">:</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">if</span> <span class="s3">tello</span>.<span class="s3">flightPlan</span>.<span class="s4">count</span> == <span class="s8">0</span> {</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">let</span> zoom = <span class="s3">scrollView</span>.<span class="s4">zoomScale</span> - <span class="s8">0.25</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">let</span> pitch = <span class="s3">dronePointer</span>.<span class="s4">frame</span>.<span class="s4">size</span>.<span class="s4">height</span></div>
<div class="p4">
<span class="Apple-converted-space"> </span></div>
<div class="p2">
<span class="s5"><span class="Apple-converted-space"> </span></span>tello<span class="s5">.</span>flightPlan<span class="s5">.</span><span class="s7">append</span><span class="s5">(</span>CMD<span class="s5">.</span>takeOff<span class="s5">)</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s3">dronePointerCenter</span>.<span class="s4">y</span> -= pitch</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s2">UIView</span>.<span class="s7">animate</span>(withDuration: <span class="s8">0.5</span>, delay: <span class="s8">0</span>, options: .<span class="s4">curveEaseInOut</span>, animations: {<span class="s1">self</span>.<span class="s3">dronePointer</span>.<span class="s4">center</span> = <span class="s1">self</span>.<span class="s3">dronePointerCenter</span>}, completion: <span class="s1">nil</span>)</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s3">scrollView</span>.<span class="s7">setZoomScale</span>(zoom, animated: <span class="s1">true</span>)</div>
<div class="p1">
<span class="Apple-converted-space"> </span>}</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">default</span>:</div>
<div class="p1">
<span class="Apple-converted-space"> </span><span class="s1">break</span></div>
<div class="p1">
<span class="Apple-converted-space"> </span>}</div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #3f6e74; background-color: #ffffff}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #c41a16; background-color: #ffffff}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff; min-height: 13.0px}
span.s1 {color: #aa0d91}
span.s2 {color: #0000ff}
span.s3 {color: #3f6e74}
span.s4 {color: #5c2699}
span.s5 {color: #000000}
span.s6 {color: #26474b}
span.s7 {color: #2e0d6e}
span.s8 {color: #1c00cf}
</style>
<br />
<div class="p1">
<span class="Apple-converted-space"> </span>}</div>
<br />
Depending on the current drone state (<span class="s3" style="font-family: "menlo"; font-size: 11px;">stateMachine</span><span style="background-color: white; color: #007400; font-family: "menlo"; font-size: 11px;">.</span><span class="s4" style="font-family: "menlo"; font-size: 11px;">currentState</span>) we want to perform different actions. To take off manually, we need to be in the command state. In the planning state, we add the take off command to our flight plan, and animate the action on our viewController.<br />
<br />
One last tip. In the example above we are using switch for program control to handle the various states. If you want to check the current state against only one state don't use "==". It wont compile. You need to use "is" instead. For example, to check if the current state is Auto Pilot, you would use:<br />
<br />
<div class="p1">
<span class="s1">if</span><span class="s2"> </span><span class="s3">stateMachine</span><span class="s2">.</span><span class="s4">currentState</span><span class="s2"> </span><span class="s1">is</span><span class="s2"> </span>AutoPilotState<span class="s2"> {</span></div>
<div class="p2">
<span class="Apple-converted-space"> </span><span class="s3">tello</span>.<span class="s5">stopAutoPilot</span>()<br />
}</div>
<br />
That's it. Next time you need a state machine, don't write your own! Hop on over to GameplayKit and grab GKStateMachine.<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #007400; background-color: #ffffff}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff; min-height: 13.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff}
p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #5c2699; background-color: #ffffff}
span.s1 {color: #aa0d91}
span.s2 {color: #000000}
span.s3 {color: #0000ff}
span.s4 {color: #3f6e74}
span.s5 {color: #c41a16}
span.s6 {color: #5c2699}
</style></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-25469106726062724272019-06-25T18:32:00.002-07:002019-06-26T19:00:48.469-07:00Mesh Security System (Argon Hub, OLED and MP3 Shields) - Part 2<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
OLED Display</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibNe7XZr8ohyphenhyphen_EYwjBXSVm4T2VEZRs_8_w1CFQqZ0IyTgL-Da6YZnBLXy5nYp8MiSrVEL92Aav-b4FfmQ57vgeF2AbAocu6XmsStiukITmA6JhYBjp0Z4qFfFp2mHdeVQ7F9ziCj0CGdXT/s1600/IMG_2155.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibNe7XZr8ohyphenhyphen_EYwjBXSVm4T2VEZRs_8_w1CFQqZ0IyTgL-Da6YZnBLXy5nYp8MiSrVEL92Aav-b4FfmQ57vgeF2AbAocu6XmsStiukITmA6JhYBjp0Z4qFfFp2mHdeVQ7F9ziCj0CGdXT/s400/IMG_2155.jpeg" width="300" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 5. Argon mounted on Tripler with OLED.</span></div>
<br />
<br />
Having demonstrated that we can blink a LED on the Argon, we now want to move onto something a bit more useful. The Argon will form the hub of the Mesh Security System and will connect to an OLED and MP3 shield to indicate system status. In Part 2 we will get the OLED and MP3 shields working.<br />
<br />
As shown in Figure 5, connection is simple using the Featherwing Tripler. By mounting the shields horizontally rather than stacking them you can still easily see all the indication LEDs. You will have to solder the headers on the tripler and shields. Do the tripler first. I solder one pin and then check that the header is correctly positioned before soldering the rest. It is a lot easier to rectify an issue with only one pin soldered in place. Once you have completed soldering the headers on the tripler you can use this as a jig to hold the pins in place when soldering them to the shields. This will ensure that the shield pins line up with the headers on the tripler.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Gebm8hyphenhyphenrZI7QZ1U3nPO8SWxATBXRnNLkfmUC8nV9iU2lo4rvQu_l7DLg8astMBe8r8QU0X2pBZLjxkCJd-xmfN-h6wxkdEseMrnsuuyxMlfcw_OI1NWODCHOALWngporZSLcFJNQTKzT/s1600/IMG_2157.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Gebm8hyphenhyphenrZI7QZ1U3nPO8SWxATBXRnNLkfmUC8nV9iU2lo4rvQu_l7DLg8astMBe8r8QU0X2pBZLjxkCJd-xmfN-h6wxkdEseMrnsuuyxMlfcw_OI1NWODCHOALWngporZSLcFJNQTKzT/s400/IMG_2157.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 6. OLED Operational</span></div>
<br />
<br />
The display board is 128x32 monochrome OLED which has 3 user buttons plus reset. This screen is made of 128x32 individual white OLED pixels and because the display makes its own light, no backlight is required. This reduces the power required to run the OLED and is why the display has such high contrast. The board uses a SSD1306 and connects via I2C (pins D0 and D1), so it is very pin frugal. As I2C is a shared bus you can have other shields which utilise I2C connected at the same time (as long as they have different I2C addresses). The three buttons use:<br />
<table style="-webkit-tap-highlight-color: transparent; background-color: white; border-spacing: 0px; border: 0px; color: #4a4a4a; font-family: AvenirNext, sans-serif; font-size: 16px; margin: 40px auto; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: middle;"><thead style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;">
<tr style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;"><th style="-webkit-tap-highlight-color: transparent; border-bottom-color: rgb(217, 216, 214); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 2px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-align: left; text-size-adjust: none; vertical-align: bottom;">Button</th><th style="-webkit-tap-highlight-color: transparent; border-bottom-color: rgb(217, 216, 214); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 2px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-align: left; text-size-adjust: none; vertical-align: bottom;">Pin</th><th style="-webkit-tap-highlight-color: transparent; border-bottom-color: rgb(217, 216, 214); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 2px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-align: left; text-size-adjust: none; vertical-align: bottom;">Notes</th></tr>
</thead><tbody style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;">
<tr style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;"><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">A</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">D4</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">No pull-up. Can't be used with Ethernet.</td></tr>
<tr style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;"><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">B</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">D3</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">100K pull-up. Can't be used with Ethernet.</td></tr>
<tr style="-webkit-tap-highlight-color: transparent; border: 0px; font-family: inherit; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; text-size-adjust: none; vertical-align: baseline;"><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">C</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">D2</td><td style="-webkit-tap-highlight-color: transparent; border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(217, 216, 214); border-top-style: solid; border-width: 1px 0px 0px; font-family: inherit; font-size: 11px; font-style: inherit; line-height: 1.42857; margin: 0px; outline: 0px; padding: 5px; text-size-adjust: none; vertical-align: top;">No pull-up.</td></tr>
</tbody></table>
So all up this shield uses 5 pins (D0 - D4).<br />
<br />
The library is available in the Web IDE as <a href="https://build.particle.io/libs/oled-wing-adafruit/0.0.4/tab/oled-wing-adafruit.cpp">oled-wing-adafruit</a> and using the display from the Argon is easy. The library takes care of setting the appropriate input modes and debouncing the buttons for you.<br />
<br />
I've reproduced my test code stub below. I always like to get each element of a project working before adding the next. This makes debugging much easier.<br />
<br />
<script src="https://gist.github.com/reefwing/ca81a5455fe29b3e342b1aa19d9aa70d.js"></script><br />
<br />
<h3 style="text-align: left;">
MP3 Shield</h3>
<br />
The MP3 Shield is shown in Figure 5 above. This is before the through hole headers have been soldered onto the shield. The shield version that we are using is the Adafruit Music Maker FeatherWing. This shield uses the the VS1053, an encoding/decoding (codec) chip that can decode a wide variety of audio formats such as MP3, AAC, Ogg Vorbis, WMA, MIDI, FLAC, WAV (PCM and ADPCM). This chip also allows you to adjust bass, treble, and volume digitally.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOiR4oq1cPit6T27dkMxcSvmBkwe8zCR0kxXcWxiCzP4tm2JfPBCSbpiK5xY6Kv9sFZbVlF5PD1PAo2z5LpfQfp5aotNt0OLfbLmKyCJoxUId0PCrz234zQwhmjgOMYpfTC5w_DO3FIPVr/s1600/argon-block-diagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1140" data-original-width="1600" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOiR4oq1cPit6T27dkMxcSvmBkwe8zCR0kxXcWxiCzP4tm2JfPBCSbpiK5xY6Kv9sFZbVlF5PD1PAo2z5LpfQfp5aotNt0OLfbLmKyCJoxUId0PCrz234zQwhmjgOMYpfTC5w_DO3FIPVr/s400/argon-block-diagram.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 7. Argon Block Diagram (showing I/O).</span></div>
<br />
<br />
Communication is via a SPI interface which allows audio to be played from an SD card. There's also a special MIDI mode that you can boot the chip into that will read 'classic' 31250 Kbaud MIDI data from the UART TX pin. The hardware SPI pins are needed whenever you are transmitting data from the SD card to the decoder chip. If you are using the wing in the special MIDI mode, they're not used.<br />
<br />
D11: <b>SPI MISO</b> - connected to MISO - used by both the SD card and VS1053<br />
D12: <b>SPI MOSI</b> - connected to MOSI - used by both the SD card and VS1053<br />
D13: <b>SPI SCK</b> - connected to SCK - used by both the SD card and VS1053<br />
<br />
The Adafruit VS1053 Library does include a constructor to define the SPI pins you want to use, but this doesn't help us because:<br />
<br />
<ol style="text-align: left;">
<li>The hardware SPI pins are already connected by the tripler; and</li>
<li>The alternative SPI pins on the Argon are D2, D3 and D4 - which seem to be very popular with shield designers!</li>
</ol>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrAp9x74UFpyMMNBB9XO0TzaOpB1n9TY51Mv84oLmKGH3ohtIli8c6gy5Wv9qHLawDbGp1pdMnlxDVIdUsn5csPdEWay_JtXjz0OOI7fHKWYeeFkJaunp1O3etnKrCbtZ0Ai5hzmPJ3H8H/s1600/feather_pinout.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="640" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrAp9x74UFpyMMNBB9XO0TzaOpB1n9TY51Mv84oLmKGH3ohtIli8c6gy5Wv9qHLawDbGp1pdMnlxDVIdUsn5csPdEWay_JtXjz0OOI7fHKWYeeFkJaunp1O3etnKrCbtZ0Ai5hzmPJ3H8H/s400/feather_pinout.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 8. Adafruit Music Maker FeatherWing Shield.</span></div>
<br />
<br />
Next are the control pins required to play music. From left to right, in Figure 9 below, they are:<br />
<br />
<b>MP3_DCS</b> - this is the VS1053 data select pin<br />
<b>DREQ</b> - this is the VS1053 data request interrupt pin<br />
<b>MP3_CS</b> - this is the VS1053 chip select pin<br />
<b>SD_CS</b> - this is the SD Card chip select pin<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQnvd7WitK-Py4_SdpACtJPdR2wyGFgnN8bgRnjGoT7EDFWha1W_uF2HVq5rOv3rVIOsD00G_9BXcJVssggcoG7RRXD2QL200xpRqmB2E-yfUYqeSYG-BEnSqb8eH_0uK3dH38_cAAya4v/s1600/feather_controlpins.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="640" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQnvd7WitK-Py4_SdpACtJPdR2wyGFgnN8bgRnjGoT7EDFWha1W_uF2HVq5rOv3rVIOsD00G_9BXcJVssggcoG7RRXD2QL200xpRqmB2E-yfUYqeSYG-BEnSqb8eH_0uK3dH38_cAAya4v/s400/feather_controlpins.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 9. MP3 Control Pins.</span></div>
<br />
<br />
Unfortunately the MP3 control pins connected (via the tripler) to the Argon conflict with the A, B and C buttons connected to D2, D3 and D4 from the OLED shield. Thankfully there is no conflict on pins D0 or D1, so we can still control the OLED with the MP3 shield in place. Obviously the designers of the two shields at Adafruit didn't talk to each other!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqGCC_ma5l3Zk8iyCz4QFEZdOXK7Q9kjOixJx46DVgPU6lFZL3ZyppYbCcW0lT0YYVU32poxL8IEICtxGeC84S0W0syOS8rkWIosDEG699gVNYS2iVeX91fE1hBLT33y6su4CKuyEkJziY/s1600/IMG_2161.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqGCC_ma5l3Zk8iyCz4QFEZdOXK7Q9kjOixJx46DVgPU6lFZL3ZyppYbCcW0lT0YYVU32poxL8IEICtxGeC84S0W0syOS8rkWIosDEG699gVNYS2iVeX91fE1hBLT33y6su4CKuyEkJziY/s400/IMG_2161.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 10. MP3 Shield Installed.</span></div>
<br />
<br />
To summarise, the Argon pins used to control the MP3 shield are:<br />
<br />
SD_CS = D2; // SD Card chip select pin<br />
MP3_CS = D3; // VS1053 chip select pin (output)<br />
DREQ = D4; // VS1053 Data request, ideally an Interrupt pin<br />
MP3_DCS = D5; // VS1053 Data/command select pin (output)<br />
SPI MISO = D11; // used by both the SD card and VS1053<br />
SPI MOSI = D12; // used by both the SD card and VS1053<br />
SPI SCK = D13; // used by both the SD card and VS1053<br />
<br />
Figure 10 shows the MP3 shield in place on the tripler adjacent to the OLED shield. To give myself a bit more room, I removed the OLED shield while soldering the header pins to the MP3 shield. I again inserted the header pins into the tripler before soldering to make sure that everything lined up.<br />
<br />
There are two versions of the Adafruit Music Maker, one includes an amplifier and the other just has a 3.5mm connection for headphones or powered speakers. In retrospect I should have got the one with the amplifier built in. Nevertheless I happen to have a Duinotech 2 x 3W amplifier, so I might as well use that. This is the red PCB shown in Figure 10. Before dealing with this, you will want to make sure that the MP3 shield is working.<br />
<br />
Thankfully ScruffR has done the hard work of porting the <a href="https://github.com/ScruffR/Adafruit_VS1053_Library">Adafruit VS1053 Arduino library</a> to work with Particle mesh boards. You will need to import this library and the SDFat library in order to get the shield working. This is easy, just search for the libraries in the Web IDE and then add them. Plug in some headphones (assuming you have the same version shield as I do) and you can use the code below to test the operation of your shield. You will obviously need to copy some mp3 files to SD card before you can play them. Make sure that the names of the files are in the 8.3 format or they wont be able to be played.<br />
<br />
<script src="https://gist.github.com/reefwing/b39a2df616d17cb5cb8aae4ed7786c38.js"></script><br />
<br />
<h3 style="text-align: left;">
Duinotech 2 x 3W Amplifier</h3>
<br />
Rather than use the 3.5mm jack on the MP3 shield, we will connect directly to the Ground, Right and Left pins next to the headphone jack (Figure 11). They are line level, AC coupled outputs which are suitable for connection to an amplifier.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgheXnNM51nqVlcx6IHm7tCW6N8BOoy2UOYui3Zc3vVHnheWghb21e0dWBH6jJqfK5wf0vsfN9BshTteOrbo7xW2zE2qjD9LjWUfYRH8IkahJNsmqtG0BudMlxI4IHsPnMsZHBXdwzxs0c5/s1600/feather_audioout.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="640" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgheXnNM51nqVlcx6IHm7tCW6N8BOoy2UOYui3Zc3vVHnheWghb21e0dWBH6jJqfK5wf0vsfN9BshTteOrbo7xW2zE2qjD9LjWUfYRH8IkahJNsmqtG0BudMlxI4IHsPnMsZHBXdwzxs0c5/s400/feather_audioout.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 11. MP3 Shield Audio Out Pins.</span></div>
<br />
<br />
The Duinotech 2 x 3W Class D Amplifier (Figure 12) has greater than 90% efficiency and typically delivers 3W into 4 ohm speakers (or 1.5W into 8 ohms). Its operating voltage range is 2.5 to 5.5 VDC.<br />
<br />
The amplifier board uses the <a href="https://www.diodes.com/assets/Datasheets/PAM8403.pdf">PAM8403</a> chip and power output will be determined by a combination of the input voltage supplied and output impedance. As we are using the regulated 3.3V from the Argon and 8 ohm speakers our expected power output from the amplifier is around 0.5W.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcH_TczBwR1ncyHJjWiwOhgCdu71nj1ycdTEzEr88YPNl1wrszDvEakaC3QQ3bfCJxHjNygUHrRWAjLerzGeT0TAw8OzLerJfZY2PfiePXbuFKd7-duVur_jI4nTTh768wF0sIBK7UzeoJ/s1600/2-x-3w-amplifier.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="185" data-original-width="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcH_TczBwR1ncyHJjWiwOhgCdu71nj1ycdTEzEr88YPNl1wrszDvEakaC3QQ3bfCJxHjNygUHrRWAjLerzGeT0TAw8OzLerJfZY2PfiePXbuFKd7-duVur_jI4nTTh768wF0sIBK7UzeoJ/s1600/2-x-3w-amplifier.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 12. Duinotech 2 x 3W Amplifier.</span></div>
<br />
The amplifier pin out description is provided in the table below.<br />
<br />
<div class="page" title="Page 1">
<table style="border-collapse: collapse; text-align: center;"><colgroup><col style="width: 32.127298%;"></col><col style="width: 67.872702%;"></col>
</colgroup><tbody>
<tr>
<td colspan="2" rowspan="1" style="background-color: rgb(76.500000%, 0.000000%, 9.000000%); border-bottom-color: rgb(10.050251%, 9.547739%, 9.547739%); border-bottom-width: 0.500000pt; border-left-color: rgb(66.666667%, 13.924051%, 18.565401%); border-left-width: 0.500000pt; border-right-color: rgb(66.666667%, 13.924051%, 18.565401%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(66.834171%, 13.567839%, 18.592965%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="color: white; font-family: "helveticaltstd";">Amplifier Pinout
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(9.787234%, 9.787234%, 9.787234%); border-left-width: 0.500000pt; border-right-color: rgb(9.787234%, 9.787234%, 9.787234%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Module
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(9.787234%, 9.787234%, 9.787234%); border-left-width: 0.500000pt; border-right-color: rgb(9.787234%, 9.787234%, 9.787234%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Function
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(9.787234%, 9.787234%, 9.787234%); border-left-width: 0.500000pt; border-right-color: rgb(9.787234%, 9.787234%, 9.787234%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">R+/R-
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(9.787234%, 9.787234%, 9.787234%); border-left-width: 0.500000pt; border-right-color: rgb(9.787234%, 9.787234%, 9.787234%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Right Speaker
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.289256%, 19.834711%, 21.487603%); border-left-width: 0.500000pt; border-right-color: rgb(15.189873%, 19.831224%, 21.518987%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">L-/L+
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.189873%, 19.831224%, 21.518987%); border-left-width: 0.500000pt; border-right-color: rgb(15.289256%, 19.834711%, 21.487603%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Left Speaker
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">GND
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Ground Connection
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">+5V
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Power Supply
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">5W
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Shutdown Control
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">GND
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Ground Connection
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">LIN
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Left Audio In
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(9.842520%, 9.448819%, 9.448819%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.102041%, 20.000000%, 21.224490%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">GND
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(100.000000%, 100.000000%, 100.000000%); border-bottom-color: rgb(10.196078%, 9.803922%, 9.803922%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.102041%, 20.000000%, 21.224490%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Ground for Audio
</span></div>
</div>
</div>
</td>
</tr>
<tr>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(15.294118%, 20.000000%, 21.568627%); border-bottom-width: 0.500000pt; border-left-color: rgb(15.000000%, 20.000000%, 21.250000%); border-left-width: 0.500000pt; border-right-color: rgb(14.893617%, 20.000000%, 21.276596%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(9.842520%, 9.448819%, 9.448819%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">RIN
</span></div>
</div>
</div>
</td>
<td style="background-color: rgb(92.625000%, 95.062500%, 95.062500%); border-bottom-color: rgb(15.294118%, 20.000000%, 21.568627%); border-bottom-width: 0.500000pt; border-left-color: rgb(14.893617%, 20.000000%, 21.276596%); border-left-width: 0.500000pt; border-right-color: rgb(15.000000%, 20.000000%, 21.250000%); border-right-width: 0.500000pt; border-style: solid; border-top-color: rgb(10.196078%, 9.803922%, 9.803922%); border-top-width: 0.500000pt;"><div class="layoutArea">
<div class="column">
<div style="text-align: center;">
<span style="font-family: "helveticaltstd"; font-weight: 700;">Right Audio In
</span></div>
</div>
</div>
</td>
</tr>
</tbody></table>
</div>
<br />
Connection between the MP3 shield and amplifier is straight forward.<br />
<ol style="text-align: left;">
<li>MP3 Shield L and G connect to LIN and Audio GND on the amplifier.</li>
<li>MP3 Shield R and G connect to RIN and Audio GND on the amplifier.</li>
<li>R+/R- on the amplifier connect to the right speaker.</li>
<li>L+/L- on the amplifier connect to the left speaker.</li>
<li>+5V and GND on the amplifier connect to the 3.3V and GND pins on the Argon.</li>
</ol>
<div>
In Part 3 we will complete construction of the Argon Hub and 3D print an enclosure for it. We will then move onto configuring the Xenon's.</div>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-62312628602646516842019-06-18T19:27:00.002-07:002019-06-21T18:42:10.818-07:00Mesh Security System using the Particle Argon and Xenon - Part 1<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
Introduction</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8ma6XB67s3A5UQ95tL-2HbRdkSoYpMhINK54dLqkCbgMkMI8hdVtTJ0Akpx6C8xgHpUzIFFMxXfzG1BP8pdNh1ZJD8iY8XmKbSw8R-tuyMxE8lrmFjAnIubgDO2Pult_hzyJttuT01jy7/s1600/IMG_2153.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8ma6XB67s3A5UQ95tL-2HbRdkSoYpMhINK54dLqkCbgMkMI8hdVtTJ0Akpx6C8xgHpUzIFFMxXfzG1BP8pdNh1ZJD8iY8XmKbSw8R-tuyMxE8lrmFjAnIubgDO2Pult_hzyJttuT01jy7/s400/IMG_2153.jpeg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 1. Argon Board plus some other bits and pieces.</span></div>
<br />
I wanted to learn about the (relatively) new mesh capable boards from Particle, and decided a good project for this would be a mesh security system for our two garages and carport. These are some distance from the house and so should provide a good test of the mesh network range.<br />
<br />
The system design will look something like Figure 2. The three Xenon's will communicate via the RF mesh to each other and to the Argon Hub. The Argon will monitor the state of the Xenon's and indicate the system status using an OLED and MP3 shield. The Argon will also connect to our LAN using WiFi and provide more detailed security status via a web page. If you were building a for real security system it probably wouldn't be a good idea to publish the details on the internet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrxtXKXa5IpdQGI7PTks19jpKWQsRGCdNjsJCDF34Bmn0-_KKBUDTdwkt50Bhi8QQlZElsiueUmMrCgtMqRRGA8leeXbAYyoW42x4xLHcR36xzn85afwYZdUAxCeN-MHk2kuc83c5yRnZo/s1600/Slide1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrxtXKXa5IpdQGI7PTks19jpKWQsRGCdNjsJCDF34Bmn0-_KKBUDTdwkt50Bhi8QQlZElsiueUmMrCgtMqRRGA8leeXbAYyoW42x4xLHcR36xzn85afwYZdUAxCeN-MHk2kuc83c5yRnZo/s400/Slide1.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 2. Mesh Security Block Diagram.</span></div>
<br />
For this first article we will focus on getting the Argon up and configured. Subsequent articles will focus on the Xenon's.<br />
<br />
<h3 style="text-align: left;">
Particle Xenon and Argon Boards</h3>
<br />
The Xenon is a low cost mesh-enabled development kit that can act as either an endpoint or repeater within a Particle Mesh network.<br />
<br />
The boards are based on the Nordic nRF52840 SoC (System on a Chip), and communicate using the IEEE 802.15.4-2006 standard to create a PAN (Personal Area Network). Bluetooth and active Near Field Communication (NFC) is also available. They have built-in battery charging circuitry which makes it possible to connect and recharge an appropriately sized Li-Po battery. The Xenon has 20 mixed signal (6 x Analog, 8 x PWM) GPIOs to interface with sensors, actuators, and other electronics. Programming it is very similar to an Arduino. The board is compatible with the Adafruit FeatherWing layout and shields can be connected to the base board using a FeatherWing doubler or tripler.<br />
<br />
The Particle Argon is similar but includes Wi-Fi. It can be used as a standalone Wi-Fi device or as a Wi-Fi enabled gateway, repeater, or endpoint for Particle Mesh networks. We will be using it in the second configuration for our network.<br />
<br />
The Argon has both the Nordic nRF52840 and the Espressif ESP32 processors on board. As with the Xenon it has battery charging circuitry and 20 mixed signal (6 x Analog, 8 x PWM) GPIOs. Other interfaces include UART, I2C, and SPI.<br />
<br />
Programming the boards can be done via an extension to Visual Studio Code or using their online IDE. We will try out both methods.<br />
<br />
<h3 style="text-align: left;">
Connecting the Antenna</h3>
<br />
The Argon uses two different MCU's for WiFi and BLE/Mesh. The WiFi is done using the ESP32 capability and the BLE/Mesh via the nRF82540. Each communication method uses the following frequencies:<br />
<br />
<ol style="text-align: left;">
<li>WiFi - 2.412 GHz to 2.484 GHz (14 channels)</li>
<li>Bluetooth - 2.400 to 2.485 GHz</li>
<li>Mesh - 2.4 GHz (uses 6LoWPAN over 802.15.4)</li>
<li>NFC - 13.56 MHz</li>
</ol>
<br />
So there is a lot going on around 2.4 GHz if you are using WiFi, BLE and mesh at the same time. This is probably why an external antenna is provided. I assume there is also some smart deconfliction occurring at the hardware or Device OS level.<br />
<br />
When talking about the Particle Mesh you may see Thread referenced. Thread is an open mesh networking protocol released by the Thread Group. Particle Mesh uses OpenThread, an open source implementation of Thread released by Nest.<br />
<br />
6LoWPAN is an unfortunate acronym that combines the latest version of the Internet Protocol (IPv6) and Low-power Wireless Personal Area Networks (LoWPAN). 6LoWPAN, therefore, allows for the smallest devices with limited processing ability to transmit information wirelessly using an internet protocol. It is a competitor to ZigBee.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsRpgWFXvFPo-m412pJMSWkBWhocTNxagRo6LTA7koTBf5Hnqk2etMX4XpkSyrSVvqqnTLDY5x8r_W4GuVNL1oYIg7qw_DsdaGeRy4xEOOBfPGRse8U8_554YDgMcwEoSLSN8Tu69XdNRs/s1600/wifi_antenna.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1000" data-original-width="1000" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsRpgWFXvFPo-m412pJMSWkBWhocTNxagRo6LTA7koTBf5Hnqk2etMX4XpkSyrSVvqqnTLDY5x8r_W4GuVNL1oYIg7qw_DsdaGeRy4xEOOBfPGRse8U8_554YDgMcwEoSLSN8Tu69XdNRs/s400/wifi_antenna.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 3. Particle 2.4 GHz Antenna</span></div>
<br />
The Argon has 3 antenna connectors (u.FL connector); two on top “BT” (for mesh - nRF52840) and WiFi (for the ESP32), and one on the underside (under the micro-USB connector) for NFC. The Xenon's have 2 antenna connectors; one for “BT” (mesh) and one on the underside for NFC.<br />
<br />
The Antenna provided with the Argon is tuned for 2.4GHz so use it for Mesh or WiFi. If you are using NFC, you will need to <a href="https://store.particle.io/products/nfc-antenna">purchase an antenna tuned for 13.56 MHz</a>. I am going to start out with the external Antenna on WiFi. This is required if you wish to use the WiFi connectivity.<br />
<br />
There are two options for the Mesh antenna on the Argon. It comes with an on-board PCB antenna which is selected by default in the device OS and a u.FL connector if you wish to connect an external antenna. If you wish to use the external antenna, you'll need to buy one and issue an appropriate command in the firmware.<br />
<br />
Connecting the antenna plug to the u.FL socket on the Argon is easiest done using a pair of long nosed pliers.<br />
<br />
<h3 style="text-align: left;">
First Time Setup</h3>
<br />
Particle have put together a <a href="https://youtu.be/54kmDEoQSP0">good video showing how to setup your Argon</a>, so there is no need to reproduce all the steps here. TL;DR - download the iOS or Android app and follow the instructions.<br />
<br />
As part of registering your device you will probably have to update the device OS (which abstracts away some of the complexity of programming the Argon). It is all very straight forward and worked well for me. I like the use of the RGB LED to indicate the various states of the device.<br />
<br />
Once you've completed the setup you will be able to program your device and send over-the-air (OTA) updates to it.<br />
<br />
Flashing the standard blink "hello world" example is a trivial exercise using the Web IDE. I was impressed by how simple this all was. The devs at Microsoft Azure IoT could learn something from this! Next up we will try something a bit more challenging - connecting the OLED and MP3 shields using the FeatherWing Tripler.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyUWGyeuz0Fwt6tz3S64_TBR0hVEiCRe8y56Ne_LVd-KAZ2AGmDh27FN-MOpnD3-EExQQEbfzHT28Lu3GGFDYGMCQWf73avaNalqmA2_zcNLyRtlPFk-v8z_d39fU7g9Lusyt8G1ZMjLUh/s1600/ce06016-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="650" data-original-width="650" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyUWGyeuz0Fwt6tz3S64_TBR0hVEiCRe8y56Ne_LVd-KAZ2AGmDh27FN-MOpnD3-EExQQEbfzHT28Lu3GGFDYGMCQWf73avaNalqmA2_zcNLyRtlPFk-v8z_d39fU7g9Lusyt8G1ZMjLUh/s400/ce06016-1.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-size: x-small;">Figure 4. FeatherWing Tripler</span></div>
<br /></div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com0tag:blogger.com,1999:blog-1323683415527527391.post-62449068031540103212019-06-08T00:15:00.000-07:002019-08-18T17:58:05.702-07:00Programming the Tello Drone using Swift (Part 1)<div dir="ltr" style="text-align: left;" trbidi="on">
<h3 style="text-align: left;">
The Tello Drone</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQWUjjY7T76uJ4XzNvik_xuQ_f6ik2nC5Z5asoV626RgTlVScmXaprN94nvJ5Ykugh2MCcEb1rQxXjyhArkKcXEb7l2IwaThd2e20JKqe6VGFiNnZSquNwHryXeFjQlzkDNP5qOxutlg7a/s1600/tello-imglogo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="696" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQWUjjY7T76uJ4XzNvik_xuQ_f6ik2nC5Z5asoV626RgTlVScmXaprN94nvJ5Ykugh2MCcEb1rQxXjyhArkKcXEb7l2IwaThd2e20JKqe6VGFiNnZSquNwHryXeFjQlzkDNP5qOxutlg7a/s400/tello-imglogo.png" width="400" /></a></div>
<br />
<br />
In this article we will explore how to write a simple iOS app in Swift to allow control of the Tello.<br />
<br />
Tello is a mini drone equipped with a HD camera that is manufactured by <a href="https://www.ryzerobotics.com/tello">Ryze</a> Robotics and includes a flight controller with DJI smarts. It is a great drone to learn to fly on as you can use it indoors and because it is so light (80 grams), crashing is fairly painless if you have the prop guards on. I have crashed mine (a lot) and the worst that has happened is that a propeller came off, which is easy to replace. It is also relatively inexpensive. You can manually control it using either an app (iOS or Android) on your phone, or a combination of the app and a dedicated Bluetooth remote. Either works fine. If you do get the Bluetooth remote be careful of not moving out of Bluetooth range of your phone while you are flying the drone.<br />
<br />
<h3 style="text-align: left;">
Tello Specifications</h3>
<br />
Tello is Powered by a DJIGlobal flight control system and an Intel processor (Movidius MA2x chipset). The MA2x is based on a SARC LEON processor which has two RISC CPUs to run the RTOS, firmware, and runtime scheduler (Ref: <a href="https://github.com/krushikesh/RyzeTelloFirmware">RyzeTelloFirmware)</a>. The other specifications are:<br />
<br />
<ul class="style__specs-list___oazkl" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #1a1a1a; font-family: "Roboto Regular", "PingFang SC", Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; font-size: 14px; list-style: none; margin: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Weight: Approximately 80 g (Propellers and Battery Included)</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Dimensions: 98×92.5×41 mm</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Propeller: 3 inches</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Built-in Functions: Range Finder, Barometer, LED, Vision System, 2.4 GHz 802.11n Wi-Fi, 720p Live View</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Port: Micro USB Charging Port</div>
</li>
</ul>
<ul class="style__specs-list___oazkl" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #1a1a1a; font-family: "Roboto Regular", "PingFang SC", Helvetica, Arial, "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; font-size: 14px; list-style: none; margin: 0px; padding: 0px; vertical-align: baseline;">
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Max Flight Distance: 100m</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Max Speed: 8m/s</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Max Flight Time: 13min</div>
</li>
<li style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: inherit; color: #9b9b9b; font-size: 16px; line-height: 32px; padding: 0px; vertical-align: baseline;">
Max Flight Height: 30m</div>
</li>
</ul>
<br />
<h3 style="text-align: left;">
Programming - Firmware Versions</h3>
<br />
Apart from being a good platform to earn your flying chops, the best thing about the Tello from my perspective is that you can write a script or a program to control the drone remotely. This opens up a lot of possibilities.<br />
<br />
Note that there are three different Tello's that you can buy (the Tello, the newer Tello EDU and the Ironman Edition), and they use slightly different API's. So make sure that you use the appropriate version for your drone.<br />
<br />
You can work out which firmware you have by connecting your mobile to the Tello WiFi, opening the Tello app, tapping on settings (the gear icon), then tap on the More button, and finally tap on the "..." button to the left of the screen. This should bring up the screen shown below which includes the firmware and app version numbers. My Tello is running firmware version 1.03.33.01. You can <a href="https://terra-1-g.djicdn.com/2d4dce68897a46b19fc717f3576b7c6a/Tello%20%E7%BC%96%E7%A8%8B%E7%9B%B8%E5%85%B3/For%20Tello/Tello%20SDK%20Documentation%20EN_1.3_1122.pdf">download the relevant SDK document</a> for this version.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZOwT2b6NH5khanyVbKIriZLqRt5vU9bSzd5naNPBYDzu5d5uMI5pXvzuMGAuDngTKOKH9DBUBrEOpU2vvDq13gFH1XDLEhliWjiWCGPsNj5WDDout4fNAM9fee9y7S5Dyi60px2F_DVYP/s1600/IMG_2146.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZOwT2b6NH5khanyVbKIriZLqRt5vU9bSzd5naNPBYDzu5d5uMI5pXvzuMGAuDngTKOKH9DBUBrEOpU2vvDq13gFH1XDLEhliWjiWCGPsNj5WDDout4fNAM9fee9y7S5Dyi60px2F_DVYP/s400/IMG_2146.png" width="400" /></a></div>
<br />
<br />
The Tello EDU uses version 2.0 of the SDK. You can <a href="https://dl-cdn.ryzerobotics.com/downloads/Tello/Tello%20SDK%202.0%20User%20Guide.pdf">download a PDF of the V2 SDK from here</a>.<br />
<br />
Commands that are available in SDK v1.3 but not v2.0 are:<br />
<br />
<ul style="text-align: left;">
<li>height?</li>
<li>temp?</li>
<li>attitude?</li>
<li>baro?</li>
<li>acceleration?</li>
<li>tof?</li>
</ul>
<br />
Conversely, commands that are available in SDK v2.0 but not v1.3 are:<br />
<br />
<ul style="text-align: left;">
<li>stop (hover)</li>
<li>go x y z speed mid (same as go x y z speed but uses the mission pad)</li>
<li>curve x1 y1 z1 x2 y2 z2 speed mid (same as curve x1 y1 z1 x2 y2 z2 speed but uses the mission pad)</li>
<li>jump x y z speed yaw mid1 mid2 (Fly to coordinates x, y and z of mission pad 1 and recognize coordinates 0, 0 and z of mission pad 2 and rotate to the yaw value)</li>
<li>mon</li>
<li>moff</li>
<li>mdirection</li>
<li>ap ssid pass</li>
<li>sdk?</li>
<li>sn?</li>
</ul>
<br />
The Tello EDU also has a swarm mode if you want to control a bunch of drones.<br />
<br />
<h3 style="text-align: left;">
Programming - Python</h3>
<br />
There are plenty of examples on how to use Python to control your Tello. For drones running v1.3 have a look at the <a href="https://github.com/dbaldwin/DroneBlocks-Tello-Python">DroneBlocks code</a>. For the Tello EDU (i.e. v2.0 SDK), Ryze Robotics provide some <a href="https://dl-cdn.ryzerobotics.com/downloads/tello/20180222/Tello3.py">sample code</a> for you to download and try out.<br />
<br />
I uploaded the DroneBlocks code using my Raspberry Pi connected to the Tello WiFi and it worked a treat. Given that there are lots of Python examples, I thought I would put together something in Swift and work up to an app which provides additional functionality not found in the official Tello app.<br />
<br />
<h3 style="text-align: left;">
Programming - Swift (iOS)</h3>
<br />
We access the Tello API by connecting to the airframe via a WiFi UDP port. Once a connection is in place, the drone is controlled using simple text commands.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC_mk6cMvhMc4LAX6AM7dUGP5QaVsPfhXSde1icSiXBUCbIsb8NcRmdlgqvwqQE8KNYMy4XqxRUWclVO8HC8kRhBAhaAZvJ4-fEA5qtoSHB_BIOJY2yhb61i3dc1apL0PhjfzvkGkouW0B/s1600/WiFi_Settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1115" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC_mk6cMvhMc4LAX6AM7dUGP5QaVsPfhXSde1icSiXBUCbIsb8NcRmdlgqvwqQE8KNYMy4XqxRUWclVO8HC8kRhBAhaAZvJ4-fEA5qtoSHB_BIOJY2yhb61i3dc1apL0PhjfzvkGkouW0B/s320/WiFi_Settings.png" width="223" /></a></div>
<br />
<br />
The first thing we want to determine is whether our device is connected to the Tello WiFi. There are a couple of Swift functions which can assist with establishing this. The Tello SSID name contains the string "TELLO" (see image above), so this is what we will use to determine wether we are connected to the correct WiFi network.<br />
<br />
<script src="https://gist.github.com/reefwing/bf536d41f28a11a84a40b923cbc0048c.js"></script><br />
We can use the code above in our ViewController to ensure that we are hooked up to the Tello, and if not provide an alert. The screenshot below shows this implemented in my proof of concept app.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9zOoU6U4iFbLDepVp3WdY00dsKxlcBfGjrB4c0PQw2XmOqY5qAlKuUCr3PY9-YcO7Y3IwVOvX_fL6kH_0YvuSN6BmJ0WFn7Ynbd1ZKEtwFOYpnhUm4MoiYzMYLRAfcYQ1tL4k8pIevDQh/s1600/IMG_2151.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9zOoU6U4iFbLDepVp3WdY00dsKxlcBfGjrB4c0PQw2XmOqY5qAlKuUCr3PY9-YcO7Y3IwVOvX_fL6kH_0YvuSN6BmJ0WFn7Ynbd1ZKEtwFOYpnhUm4MoiYzMYLRAfcYQ1tL4k8pIevDQh/s400/IMG_2151.png" width="400" /></a></div>
<br />
The code for the ViewController is shown next. It should be fairly self explanatory.<br />
<br />
<script src="https://gist.github.com/reefwing/e113d6f3f0b464a7947c7623bb137c31.js"></script><br />
<br />
<h3 style="text-align: left;">
UDP</h3>
<br />
UDP (User Datagram Protocol) is a communications protocol, similar to Transmission Control Protocol (TCP), but used primarily for establishing low-latency, low-bandwidth and loss-tolerating connections. UDP sends messages, called datagrams, and is considered a best-effort mode of communications. With UDP there is no checking and resending of lost messages (unlike TCP).<br />
<br />
Both UDP and TCP run on top of the Internet Protocol (IP) and are sometimes referred to as UDP/IP or TCP/IP.<br />
<br />
UDP provides two services not provided by the IP layer. It provides port numbers to help distinguish different user requests and, optionally, a checksum capability to verify that the data arrived intact.<br />
<br />
The Tello IP address is <b>192.168.10.1</b>. The UDP Services available are:<br />
<br />
UDP PORT: <b>8889</b> - Send command and receive a response.<br />
UDP SERVER: <b>0.0.0.0</b> UDP PORT: <b>8890</b> - Receive Tello state.<br />
UDP SERVER: <b>0.0.0.0</b> UDP PORT: <b>11111</b> - Receive Tello video stream.<br />
<br />
If you want to send and receive via UDP on iOS then the two main libraries in use appear to be <a href="https://github.com/swiftsocket/SwiftSocket">SwiftSocket</a> and <a href="https://github.com/robbiehanson/CocoaAsyncSocket">GCDAsyncUDPSocket</a>.<br />
<br />
Swift Socket looks to be the simpler of the two libraries, so I used that for my initial attempt. I put together a Tello Swift class to do the heavy lifting. It is reproduced below and works as advertised. You will need to put together your own UI but if you hook up the relevant buttons in the View Controller then you shouldn't have any problem reproducing what I have done.<br />
<br />
I will add a bit more functionality to the app (e.g. video) and then stick it up on the app store for download.<br />
<br />
<script src="https://gist.github.com/reefwing/3b569a29e20febab0eb36fa530ba10fb.js"></script><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwzrQ2v5V_BbYTSBd-1j-D8pdJUWkLfuNQPkOjGzw55L4-rdnJmNx8Vdcue4zA1SZuw4zh7QSNbjHj_jkipUdt42niROOrexXngc33TjdTCYZMwVUbEdwa8GwbQ2OkiuWQ8cbiacA20NhR/s1600/IMG_2150.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="739" data-original-width="1600" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwzrQ2v5V_BbYTSBd-1j-D8pdJUWkLfuNQPkOjGzw55L4-rdnJmNx8Vdcue4zA1SZuw4zh7QSNbjHj_jkipUdt42niROOrexXngc33TjdTCYZMwVUbEdwa8GwbQ2OkiuWQ8cbiacA20NhR/s400/IMG_2150.png" width="400" /></a></div>
</div>
David Suchhttp://www.blogger.com/profile/10502842288604398442noreply@blogger.com2