tag:blogger.com,1999:blog-54167264606971113622024-03-15T18:12:46.676-07:00Dr. Monk's DIY Electronics BlogOpen Source hardware, Arduino, Raspberry Pi, micro:bit, BeagleBone, DIY electronic construction, reviews, projects, how-tos and recipes.Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.comBlogger134125tag:blogger.com,1999:blog-5416726460697111362.post-16056844234291129582024-01-24T04:34:00.000-08:002024-01-26T14:19:35.496-08:00Lies, Damn Lies and Analog Inputs (comparing ADCs on ESP32, Pico and Arduino)<p>After some inconsistent and unreliable results reading an analog input from an ESP32 board, I decided to get all scientific and do some experimenting with an ESP32, a Raspberry Pi Pico and an Arduino Uno R3.</p><h2 style="text-align: left;">Method</h2><p>My test setup was a bench power supply providing the reference voltage to be measured by the test board. The output of the bench PSU had a dummy load of a 470Ω resistor and a 100nF capacitor in parallel (the latter largely for superstitions reasons) as the voltage output looks extremely stable on a DMM voltmeter.</p><p>This output from the bench power supply was then applied directly to an analog input and GND of the board being tested.</p><p>I was particularly interested in three things:</p><p>* finding any dead-zones at each end of the analog input voltage range</p><p>* measuring the reproducibility of the readings</p><p>* linearity through the range</p><p>Another time, I'd like to look at the input impedance of the ADC (analog to digital convertor) and the effects of how rapidly you sample. But I'll leave that for another day.</p><p>To measure the reproducibility of the readings, each time the test voltage was changed, 100 readings would be taken, and the mean and standard deviation of that set recorded. That way, when it came to plotting the readings from the boards, I could add some error bars.</p><p>For the ESP32 and Pico, I used MicroPython and for the Arduino Uno, I used Arduino C. The Arduino readings were scaled up to 16bit unsigned values (max value 65536) to be consistent with the MicroPython version. In all cases, the default ADC settings were used.</p><h2 style="text-align: left;">ESP32</h2><p>For this experiment, I used an ESP32 Lite (sometimes also called LOLIN32 Lite). These are a ubiquitous low-cost ESP32 board, with built-in WiFi and Bluetooth.</p><p>Analog input maximum voltage 1.0V</p><p><br /></p><p><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiIXMunWvyzGszkfviMGOgVb5sHyv4Dmx_0JB27XZeOTPnoQ48BG-wZAPhRcWoQG3-UwefctZQ-BeXlY7PvNVZtFZUH54t032IYnAjlvU95gqNt3gaynf8qAUokVqZ7xzhKtnOABaS8FVs_ZcUYFnLYmzMUfG-JLPieQ-hLDlzna6PoIGDdHKLCP8Nkw7Qx" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="" data-original-height="930" data-original-width="1692" height="176" src="https://blogger.googleusercontent.com/img/a/AVvXsEiIXMunWvyzGszkfviMGOgVb5sHyv4Dmx_0JB27XZeOTPnoQ48BG-wZAPhRcWoQG3-UwefctZQ-BeXlY7PvNVZtFZUH54t032IYnAjlvU95gqNt3gaynf8qAUokVqZ7xzhKtnOABaS8FVs_ZcUYFnLYmzMUfG-JLPieQ-hLDlzna6PoIGDdHKLCP8Nkw7Qx" width="320" /></a></p><p><br /></p><p>Here's the plot</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjnIsJcIBmBSEQz3udywvBD8A13D8sq0HAD4A0KetfNrHItmtU2U-e_zvU9MslIRNUOWKXIa-zWjpUnQWRM_ZDfCi9m1zUPYlfsSlsQXMddjwBBIRWNvuFwUA1Lm7kdlD7g89CFg34e4J596S7Nhm4N2TlMEpCrzSdjaecEaamfEG-oeKLPm2fiUMP-Rz0I" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="901" data-original-width="1396" height="414" src="https://blogger.googleusercontent.com/img/a/AVvXsEjnIsJcIBmBSEQz3udywvBD8A13D8sq0HAD4A0KetfNrHItmtU2U-e_zvU9MslIRNUOWKXIa-zWjpUnQWRM_ZDfCi9m1zUPYlfsSlsQXMddjwBBIRWNvuFwUA1Lm7kdlD7g89CFg34e4J596S7Nhm4N2TlMEpCrzSdjaecEaamfEG-oeKLPm2fiUMP-Rz0I=w640-h414" width="640" /></a></div>The red error bars show +- 3 standard deviations (SDs) from 100 samples. Nearly all of the sample values would fall within 3 SDs and 60% would fall within 1 SD.<p></p><p>There is a sizeable dead zone until the voltage rises to about 0.05V and a lot of noise around the readings, evidenced by the large error bars. But it retains pretty good linearity once you get past that up to the 1V upper limit.</p><h2 style="text-align: left;">Raspberry Pi Pico</h2><p>The Raspberry Pi Pico uses Raspberry Pi's RP2040 chip. It'a another popular, good value board.</p><p>It's maximum analog input voltage is the full 3.3V supply range.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjfy3Q1w0_BwOceSKPfDP4vjhwG0lrTbt08dsupKLSxcO9OQ5GcV5dN5Dfaz_oyzUaoA4Xb-gCbIwed2qBerJoUgcDxdtzBXNCbluVFB2mIblDhK6-EisT7DrKXqMoiGGwK5D9fYvDOAb7Q-y6xnkD79fqYLU3NacDYJjScHza6KlCUXT_cdZpq0DvJ9Ksk" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="948" data-original-width="1200" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjfy3Q1w0_BwOceSKPfDP4vjhwG0lrTbt08dsupKLSxcO9OQ5GcV5dN5Dfaz_oyzUaoA4Xb-gCbIwed2qBerJoUgcDxdtzBXNCbluVFB2mIblDhK6-EisT7DrKXqMoiGGwK5D9fYvDOAb7Q-y6xnkD79fqYLU3NacDYJjScHza6KlCUXT_cdZpq0DvJ9Ksk" width="304" /></a></div><br />Here's the plot for the Pico - <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEi7OVrjgT9DfLqXDz2FRNdZM4P0L5llTq_BseHPe4J31inHIPyGCU-uISQSLMGcrkFQyUVYJnMrHxpMXHpz1N3v3SzY8_0qVe1z554YKaBESnrpE5XKXiAF1mC7o3UellTx1gKpZjQPhDda_cRWsHAr2-mK8m5kgkUGj6ZrN4iCT_xjuajH8o2_zC8pKYj6" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="1194" data-original-width="2188" height="350" src="https://blogger.googleusercontent.com/img/a/AVvXsEi7OVrjgT9DfLqXDz2FRNdZM4P0L5llTq_BseHPe4J31inHIPyGCU-uISQSLMGcrkFQyUVYJnMrHxpMXHpz1N3v3SzY8_0qVe1z554YKaBESnrpE5XKXiAF1mC7o3UellTx1gKpZjQPhDda_cRWsHAr2-mK8m5kgkUGj6ZrN4iCT_xjuajH8o2_zC8pKYj6=w640-h350" width="640" /></a></div><div style="text-align: left;"><br /></div><div style="text-align: left;">This is considerably better than the ESP32, with smaller 3 x SD error bars, a small dead zone at the low voltage end and some slight tail-off in linearity at the 3.3V end.</div><div style="text-align: left;"><br /></div><h2 style="text-align: left;">Arduino Uno R3</h2><div style="text-align: left;">Despite its age, the Arduino Uno R3 (not the fancy new one) is still my go-to board for any experimentation or early stage project work that doesn't need a specific microcontroller. I'll admit, it's partly out of familiarity and inertia on my part.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhK6DhYrnhqEXEqrTF0QmKGGQh4C8n4ghHZ8alJbUNHBhaOY4L8LdS4LFs0sXT60hcSy53EAkdTM4orlnajkbbo7mFZ0KWYRZJt1G-bzGW-H-prqvpyk7HmQRJRIBKgNxi5U0jWgiztpqCxpTg-fP1HRjsnDE2u7VETIIENrVL9oxruJIb7EejwBhAi8wwa" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="952" data-original-width="1200" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEhK6DhYrnhqEXEqrTF0QmKGGQh4C8n4ghHZ8alJbUNHBhaOY4L8LdS4LFs0sXT60hcSy53EAkdTM4orlnajkbbo7mFZ0KWYRZJt1G-bzGW-H-prqvpyk7HmQRJRIBKgNxi5U0jWgiztpqCxpTg-fP1HRjsnDE2u7VETIIENrVL9oxruJIb7EejwBhAi8wwa" width="303" /></a></div><br /><br /></div></div>And here are the results.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjoYoux2t2AcRllE6DYEwDEC5eT6nlXatTqQ7m-G89RBZvPptjxrfk6XpUEltdGGf2WVdMBHEzNGGgVWbrUh5M8FSY1oAv2ZkV0mS0Rd3lP5Qblg6eslb9BilgC-1tCRhcGGVyzOo_OvTBx2rVLQsa6rglJiZS9MuHKh48SffMVdZ33fABEoqI1TIR_O7ER" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="1096" data-original-width="1940" height="362" src="https://blogger.googleusercontent.com/img/a/AVvXsEjoYoux2t2AcRllE6DYEwDEC5eT6nlXatTqQ7m-G89RBZvPptjxrfk6XpUEltdGGf2WVdMBHEzNGGgVWbrUh5M8FSY1oAv2ZkV0mS0Rd3lP5Qblg6eslb9BilgC-1tCRhcGGVyzOo_OvTBx2rVLQsa6rglJiZS9MuHKh48SffMVdZ33fABEoqI1TIR_O7ER=w640-h362" width="640" /></a></div><br />And there we have it. Very little deviation between readings and great linearity across the whole range, right up to 5V. The Uno with it's ancient Atmega328 is streets ahead of the other two boards.<p></p><h2 style="text-align: left;">Conclusion</h2><p>On looking at the documentation in MicroPython and learning that the analog readings for a Pico and ESP32 come at a massive 16 bit precision (a number between 0 and 65536) it's easy think that their analog inputs are much better than the paltry 10 bits of an Arduino (0 to 1023 reading range). But this is to confuse precision with accuracy. It's why pure megapixels is not the best way to judge a camera. So much depends on the lens.</p><p>So, if you are trying to get decent accuracy and reproducibility from your analog readings, then you probably want to take a set of readings and average them -- or use an Arduino Uno R3!</p><h2 style="text-align: left;">Test Programs</h2><h3 style="text-align: left;">ESP32</h3><div><div><span style="font-family: courier;">from machine import ADC, Pin</span></div><div><span style="font-family: courier;">from time import sleep</span></div><div><span style="font-family: courier;">from math import sqrt</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">analog = ADC(12)</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">p = 0.05</span></div><div><span style="font-family: courier;">n = 100</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">while True:</span></div><div><span style="font-family: courier;"> readings = []</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> readings.append(analog.read_u16())</span></div><div><span style="font-family: courier;"> sleep(p)</span></div><div><span style="font-family: courier;"> total = 0</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> total += readings[i]</span></div><div><span style="font-family: courier;"> mean = total / n</span></div><div><span style="font-family: courier;"> dist_tot = 0</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> dist = readings[i] - mean</span></div><div><span style="font-family: courier;"> dist_tot += dist * dist</span></div><div><span style="font-family: courier;"> </span></div><div><span style="font-family: courier;"> print(mean, sqrt(dist_tot / n))</span></div><div><span style="font-family: courier;"> </span></div><div><span style="font-family: courier;"> input('Press enter to read again')</span></div><div><br /></div></div><h3 style="text-align: left;">Pico</h3><div><div><span style="font-family: courier;">from machine import ADC, Pin</span></div><div><span style="font-family: courier;">from time import sleep</span></div><div><span style="font-family: courier;">from math import sqrt</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">analog = ADC(28)</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">p = 0.05</span></div><div><span style="font-family: courier;">n = 100</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">while True:</span></div><div><span style="font-family: courier;"> readings = []</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> readings.append(analog.read_u16())</span></div><div><span style="font-family: courier;"> sleep(p)</span></div><div><span style="font-family: courier;"> total = 0</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> total += readings[i]</span></div><div><span style="font-family: courier;"> mean = total / n</span></div><div><span style="font-family: courier;"> dist_tot = 0</span></div><div><span style="font-family: courier;"> for i in range(0, n):</span></div><div><span style="font-family: courier;"> dist = readings[i] - mean</span></div><div><span style="font-family: courier;"> dist_tot += dist * dist</span></div><div><span style="font-family: courier;"> </span></div><div><span style="font-family: courier;"> print(mean, sqrt(dist_tot / n))</span></div><div><span style="font-family: courier;"> </span></div><div><span style="font-family: courier;"> input('Press enter to read again')</span></div><div><br /></div><h3 style="text-align: left;">Arduino</h3></div><p><span style="font-family: courier;">int p = 50;</span></p><p><span style="font-family: courier;">const int n = 100;</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">unsigned int readings[n];</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">void setup() {</span></p><p><span style="font-family: courier;"> Serial.begin(9600);</span></p><p><span style="font-family: courier;">}</span></p><p><span style="font-family: courier;"><br /></span></p><p><span style="font-family: courier;">void loop() {</span></p><p><span style="font-family: courier;"> if (Serial.available()) {</span></p><p><span style="font-family: courier;"> Serial.read();</span></p><p><span style="font-family: courier;"> Serial.println("measuring");</span></p><p><span style="font-family: courier;"> for (int i = 0; i < n; i++) {</span></p><p><span style="font-family: courier;"> readings[i] = analogRead(A0) * 64; // 16 bit not 10</span></p><p><span style="font-family: courier;"> delay(p);</span></p><p><span style="font-family: courier;"> }</span></p><p><span style="font-family: courier;"> float total = 0.0;</span></p><p><span style="font-family: courier;"> for (int i = 0; i < n; i++) {</span></p><p><span style="font-family: courier;"> total += float(readings[i]);</span></p><p><span style="font-family: courier;"> }</span></p><p><span style="font-family: courier;"> float mean = total / n;</span></p><p><span style="font-family: courier;"> float dist_total = 0.0;</span></p><p><span style="font-family: courier;"> for (int i = 0; i < n; i++) {</span></p><p><span style="font-family: courier;"> float dist = float(readings[i] - mean);</span></p><p><span style="font-family: courier;"> dist_total += (dist * dist);</span></p><p><span style="font-family: courier;"> }</span></p><p><span style="font-family: courier;"> float sd = sqrt(dist_total / n);</span></p><p><span style="font-family: courier;"> Serial.print(mean); Serial.print(' '); Serial.println(sd);</span></p><p><span style="font-family: courier;"> }</span></p><p><span style="font-family: courier;">}</span></p><p><br /></p><p><br /></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com13tag:blogger.com,1999:blog-5416726460697111362.post-34901025892950371962023-09-27T23:00:00.002-07:002023-09-28T13:24:19.617-07:00Raspberry Pi 5 Review<p>I was lucky enough to get hold of a pre-release Raspberry Pi 5. Here are my impressions of this latest incarnation of the Raspberry Pi Single Board Computer.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKFkr4yKEhmLyoZ0B8gEZCyQJYr5x1wfFjbz3YBo3bxU6AHJz1fSCSqSOwlMuVBWa5sbHuHdRHqJRp6gxf6wCN3DnhNge4Yec01TILUDov_2FiNIcBwO5NulTTKR8N4jfx37hVk7tb5dBKduUW1hnTz1orBdm6JG40tHslTO0VVP1ysd-yA72tUPJ5ewh3/s1600/pi_5_bare.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1044" data-original-width="1600" height="418" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKFkr4yKEhmLyoZ0B8gEZCyQJYr5x1wfFjbz3YBo3bxU6AHJz1fSCSqSOwlMuVBWa5sbHuHdRHqJRp6gxf6wCN3DnhNge4Yec01TILUDov_2FiNIcBwO5NulTTKR8N4jfx37hVk7tb5dBKduUW1hnTz1orBdm6JG40tHslTO0VVP1ysd-yA72tUPJ5ewh3/w640-h418/pi_5_bare.jpg" width="640" /></a></div><br /><p><br /></p><h2 style="text-align: left;">First Impressions</h2><p>The first thing to strike me was the almost minimalist PCB layout, the top-side being mostly big chips with a lot of the tiny little capacitors and resistors on the underside of the board.</p><p>Reassuringly, the 40 pin GPIO connector fixing holes and usual great selection of USB and HDMI morts on the Raspberry Pi are all still there.</p><p>My version was supplied with an Active Cooler kit. One criticism of the Pi 4 was that it did tend to get quite hot. The complex self-monitoring of the SoC (system on a chip) meant that the hardware was not in danger, but it's a little disconcerting when the top surface of the chips feel like you could fry an egg on them. (I exaggerate!).</p><p>So a little fan to keep things cool will allow the Pi 5 to run at full speed.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtIY0ELteQBQjzgqXgkp9OPg0HAUWhtztjPuhzDZdAkKU7xWgyTsCpnX0Qh1racayVmisNxpaS54_aQoVdCey1tBRgFv3MX3uk4P-SepUGWSWHud19fvZ925NLq3KFoffZCmznWD9zWY5ch5RV2khFHjETL9yzNCCzzshmVfVIIIbi6CoizX24jowQ5mz4/s1600/active_cooler.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1588" data-original-width="1600" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtIY0ELteQBQjzgqXgkp9OPg0HAUWhtztjPuhzDZdAkKU7xWgyTsCpnX0Qh1racayVmisNxpaS54_aQoVdCey1tBRgFv3MX3uk4P-SepUGWSWHud19fvZ925NLq3KFoffZCmznWD9zWY5ch5RV2khFHjETL9yzNCCzzshmVfVIIIbi6CoizX24jowQ5mz4/s320/active_cooler.jpg" width="320" /></a></div><br /><p><br /></p><p>The 'Active Cooler' is simplicity itself to fit. You just peel off the backing paper from the heatsink pads and push two sprung-loaded plastic pegs through holes on the board for that purpose. It makes the Pi 5 look pretty badass!</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirwkO_JWe3DVpWfiaPcXISO7Oyik58ILUhyKz9jSURZSNWLn3U_SLrlkQOKnisQEKkDl1SE3c8SbgXv8HrsVvY7yhFiXrDFshsJ2Ckwb2-U64UMH_mnZlAtFmWutY_fQC8y3xF1Ez9HB8SeXCQ-o5gO1QXlWOCv5Hpg6vpB2yvdspvK2tgsVorbHMuWJtp/s1600/with%20heatsink.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1012" data-original-width="1600" height="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirwkO_JWe3DVpWfiaPcXISO7Oyik58ILUhyKz9jSURZSNWLn3U_SLrlkQOKnisQEKkDl1SE3c8SbgXv8HrsVvY7yhFiXrDFshsJ2Ckwb2-U64UMH_mnZlAtFmWutY_fQC8y3xF1Ez9HB8SeXCQ-o5gO1QXlWOCv5Hpg6vpB2yvdspvK2tgsVorbHMuWJtp/w640-h404/with%20heatsink.jpg" width="640" /></a></div><br /><p>However, with the Active Cooler attached, there is very little room between the edge of the heatsink and the GPIO pins. This means that GPIO templates like the Raspberry Leaf are not going to fit. So anyone wanting to use the GPIO is going to be back to counting pin positions. </p><h2 style="text-align: left;">Specifications</h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 10pt;"><span face="Arial, sans-serif" style="background-color: transparent; color: black; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;">The Pi 5 is between two and three times faster than Raspberry Pi 4 (itself no slouch). It has a 64-bit quad-</span>core Arm Cortex-A76 processor clocked at 2.4GHz. This time using a SoC designed by the Raspberry Pi team themselves.<br /><br />Raspberry Pi 5 also offers significantly improved graphics performance and camera support, and some neat little extras:<br /></p><ul style="text-align: left;"><li>A connector for a fan.</li><li>A connector for a backup battery, allowing time to be kept on the Real-time clock. (In most situations, this isn't really very useful as the Pi will set its clock from the internet. However for offline applications, this could come in handy.</li><li>A connector for UART (serial interface) </li><li>a PCIe 2.0 connector (for attaching SSDs etc)</li><li>A Reset switch</li></ul>The Pi 5 is available with either 4 or 8 GB of RAM.<br /><br /><p></p><h2 style="text-align: left;">Who's it for?</h2><p>The Raspberry Pi 4 was already a very worthy desktop/laptop replacement. At MonkMakes, we use the closely related (to Pi 4) Pi400 as a very capable office machine. With the increase in performance of the Pi 5 and with the edition of a PCIe SSD and a sturdy little case, then this device can replace a laptop or desktop computer in many situations. I sincerely hope that a Pi 500 built into a keyboard will be coming along soon.</p><p>This Pi is much more about being a proper computer, and I wouldn't be surprised to see the GPIO pins to eventually disappear altogether in some future version. </p><h2 style="text-align: left;">Verdict</h2><div><p>Top marks as a desktop replacement at a very competitive price. As a Single Board Computer (SBC), the huge community and availability of resources and add-ons make this (IMHO) the best SBC option.</p><p>However, if you don't need the performance, and are more interested in doing things with GPIO pins than you are browsing the internet or watching videos, then stick with a Pi 3. They use much less power and are perfectly adequate for most embedded applications, and you can attach a GPIO template so you know which pin is which.</p><p>For more information, see t<a href="https://www.raspberrypi.com/news/introducing-raspberry-pi-5/" target="_blank">he official Raspberry Pi announcement</a>.</p></div>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-81423914605446053812023-08-19T03:10:00.001-07:002023-08-19T04:57:31.467-07:00Disposable e-cigarette - Part 4 (Making batteries safe)<p> <span style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;">In the fourth part of this series of posts, we'll take a look at making a battery extracted from an e-cig safe to use in your products. </span></p><h2 style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 22px; margin: 0px; position: relative;"><span style="background-color: red; font-weight: normal;"><span style="color: white;">DANGER: </span></span></h2><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;">There is a really good chance that the battery of a discarded e-cig is still holding quite a lot of energy. The fluid runs out first. So if, during disassembly, the unit triggers (quite likely), then a big current will flow and the heating element will get hot. Similarly any accidental short between the leads to the battery could easily cause a fire.</span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;"><br /></span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;">Cut the leads to the element (one at a time) and to the battery (again one at a time) as soon as you can access them. </span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;"><br /></span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;">Also have a contingency plan such as fire blanket (not a bucket of water) or open window through which the flaming device can safely be thrown in the event of it catching fire.</span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;"><br /></span></div><div style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"><span style="background-color: red; color: white;">If in any doubt that you can do this safely, then don't do it.</span></div><p style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;">The e-cig batteries generally lack the 'protection circuit' found ready soldered across the terminals of the LiPo cell that carry out the following functions:</p><p style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px;"></p><ul style="text-align: left;"><li>Preventing overcharging (can cause the battery to get hot and catch fire)</li><li>Preventing over discharging (rendering the battery incapable of holding charge)</li><li>Over-current protection, safeguarding against short-circuit of battery terminals. (can cause the battery to get hot and catch fire)</li></ul><div>Fortunately these protection chips are, well, cheap as chips, because they are used in the billions. You can buy a small panel like this for a few dollars:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzSQN0-oGUJVi23OvaztqAJH9F5_VDuGJRTrPVwbw7WtqglU5cXfks7yrf10RTJ-epEJ2IqK28N8ufaOrufKEhZpADY0XARLGB0SufHnLN6CWBq1aAWLiYOe_mglBhdQIXh7STPKDoCklELiUZkozFnqdKztX1kztskPIvKu0Y_Tafr1UZEMr0THbO504J/s2192/IMG20230817122949.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1803" data-original-width="2192" height="526" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzSQN0-oGUJVi23OvaztqAJH9F5_VDuGJRTrPVwbw7WtqglU5cXfks7yrf10RTJ-epEJ2IqK28N8ufaOrufKEhZpADY0XARLGB0SufHnLN6CWBq1aAWLiYOe_mglBhdQIXh7STPKDoCklELiUZkozFnqdKztX1kztskPIvKu0Y_Tafr1UZEMr0THbO504J/w640-h526/IMG20230817122949.jpg" width="640" /></a></div><br /><div>Here's the link for the one I bought.</div><div><a href="https://www.aliexpress.com/item/32807056032.html">https://www.aliexpress.com/item/32807056032.html</a><br /></div><div>That's right 10 for $1.30!</div><div><br /></div><div>The idea is that the LiPo cell terminals are soldered to one pair of terminals on the protection PCB and then another pair of terminals are then used to connect to the battery that add the protections.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUMjrTyPyCUEeItvETejUDSXnYR6EiHnt6xR3fFWZZGbBzLCe78ZVL-oojBjD2LUHJA4hwnx_5lPThb7IhnZ6_pn20qdQMmpwqhKlKfNnOwm3XpdSFwVuTLBXQdc9BDrpCeKqQ-YoIg2bmG8-j_k4J2gOgB04MupChEbgskb9IH4n_GX3LKDbg1FAZoNEI/s2364/IMG20230817123330.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1528" data-original-width="2364" height="414" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUMjrTyPyCUEeItvETejUDSXnYR6EiHnt6xR3fFWZZGbBzLCe78ZVL-oojBjD2LUHJA4hwnx_5lPThb7IhnZ6_pn20qdQMmpwqhKlKfNnOwm3XpdSFwVuTLBXQdc9BDrpCeKqQ-YoIg2bmG8-j_k4J2gOgB04MupChEbgskb9IH4n_GX3LKDbg1FAZoNEI/w640-h414/IMG20230817123330.jpg" width="640" /></a></div><br /><div>The terminals B+ and B- are for the LiPo cell and P+ and P-. The protection PCB is more likely to stay attached to the cell, if it's soldered close to the terminals, like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglovpzw0wM-1sHfASiUorsbUbn1dK9QjYdmbMgpJh2NfgV_qexpNvcA_Q4lDIdlTR9efJoEPwA2npZ392w8Vn606WfyFU_1kuae5plOgvWCnLNz72DnGGiFtNmcgKNcS8-i0_E5RY1XsQYAGWykl9ZE_npPHYMTQza6-PDLwV4ZKuyTmwyEevEecb8KoHH/s2031/IMG20230817150617.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1103" data-original-width="2031" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglovpzw0wM-1sHfASiUorsbUbn1dK9QjYdmbMgpJh2NfgV_qexpNvcA_Q4lDIdlTR9efJoEPwA2npZ392w8Vn606WfyFU_1kuae5plOgvWCnLNz72DnGGiFtNmcgKNcS8-i0_E5RY1XsQYAGWykl9ZE_npPHYMTQza6-PDLwV4ZKuyTmwyEevEecb8KoHH/w640-h348/IMG20230817150617.jpg" width="640" /></a></div><br /><div>Notice I have also attached flying leads to protection PCB. It's a good idea not to strip the far ends of these leads until you need to, to prevent accidental short-circuits.</div><div><br /></div><div>From now on, you should only connect to these leads and not directly to the cell. This will in most cases work exactly the same, except that there is now minimal risk of starting a fire with it.</div><div><br /></div><div><b>Note that the protection PCB is not a charging circuit. It makes the LiPo cell safe, but that doesn't mean that you can just connect it to a voltage source and charge it. You will need a LiPo charging circuit to do that properly.</b></div><div><br /></div><div>If you have a bench power supply, where you can set both the voltage and the current limit, then a safe way to charge the cell is to:</div><div><ol style="text-align: left;"><li>To be ultra-safe, set the bench power supply's current limit to 1/10 of the cells capacity. For example, for 360mAh like the one shown, set the current limit to 36mA. </li><li>Set the voltage to 4.2V</li><li>Connect the battery terminals (the connection PCB terminals - NOT the LiPo cell) and wait until the current drops to 0mA after about 10 hours.</li></ol><div>At your own risk, you might like to charge the battery a lot faster - say at 500mA by setting that as the maximum current and still using 4.2V. Because the cells in e-cigs are designed for quite high-current use (several Amps) they should be fine for charging at this sort of current. But keep and eye on it, and stop immediately if the battery starts to get hot.</div></div><p></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-33573001434827763782023-08-14T05:22:00.005-07:002023-08-14T05:22:36.551-07:00New Book: Coding: The 21st Century's Most Valuable Skill<p>MonkMakes Press Publishes Getting Started Guide to the Software Industry</p><p>August 10, 2023. Preston, UK.</p><p><br /></p><h2 style="text-align: left;">Press Release</h2><p><i>Coding: The 21st Century’s Most Valuable Skill</i> is the latest book by best-selling non-fiction author Simon Monk. </p><p>Aimed squarely at anyone contemplating a career in the software industry, this book gives the reader a taste of coding, as well as a guide to the real-life experiences of working in software. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPpZbsfWkJN7E65RsODxweSteuiNWImUGWqTbrRGbDmeYOzObRXrljeM62tBEA8ZNmN311FLLR3gznqigr5kTtUD1xldVZdEdT2T1HrMmj48WR9Y9ioi0qEDmDrtVe3kPvfv_TjNBE9MSEgOVfuJ4PzVUYC7LTp6ij9qkqsiZRI8fdTCAfrDeWTds73X3P/s2560/Ebook%20Cover.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="2560" data-original-width="1600" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPpZbsfWkJN7E65RsODxweSteuiNWImUGWqTbrRGbDmeYOzObRXrljeM62tBEA8ZNmN311FLLR3gznqigr5kTtUD1xldVZdEdT2T1HrMmj48WR9Y9ioi0qEDmDrtVe3kPvfv_TjNBE9MSEgOVfuJ4PzVUYC7LTp6ij9qkqsiZRI8fdTCAfrDeWTds73X3P/s320/Ebook%20Cover.jpg" width="200" /></a></div><p><i>[Author Quote] Drawing on my 30 year career in software, as well as interviews with coders from the very biggest and smallest of software companies in the USA and UK, I hope I have shone a light on this industry that is so often hidden from outsiders.</i></p><p>The book is not afraid to pull the reader into the world of coding, with some real world practice. No prior coding experience is required and the reader is led step-by-step through installing the necessary software on their Mac or PC and taking some first tentative steps.</p><p>The paperback and eBook editions are both in full color and are illustrated with comic-strips that make for an amusing and easy read.</p><p>If you are interested in a career in software, or just want to learn a bit more about what makes coders tick, then this book will provide you with valuable insights. Released in August 2023, the book is available from Amazon and Barnes and Noble.</p><p>Simon Monk, is best known for his books on programming the Raspberry Pi computer and the Arduino. He has sold over 750,000 books in 10 languages. Simon has a doctorate in Software Engineering and worked in the software industry for many years before switching from writing code to writing books. He has published over 20 titles on software and electronics.</p><p>Contact (author): simon@monkmakes.com </p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-69272615003667572612023-08-08T13:47:00.004-07:002023-08-08T13:47:54.594-07:00Disposable e-cigarette Teardown - Part 3<h2><span style="background-color: red; font-weight: normal;"><span style="color: white;">DANGER: </span></span></h2><div><span style="background-color: red; color: white;">There is a really good chance that the battery is still holding quite a lot of energy. The fluid runs out first. So if, during disassembly, the unit triggers (quite likely), then a big current will flow and the heating element will get hot. Similarly any accidental short between the leads to the battery could easily cause a fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Cut the leads to the element (one at a time) and to the battery (again one at a time) as soon as you can access them. </span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Also have a contingency plan such as fire blanket (not a bucket of water) or open window through which the flaming device can safely be thrown in the event of it catching fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">If in any doubt that you can do this safely, then don't do it.</span></div><p>In the third part of this series of posts, we'll take a look at exactly what's going on in one of the minimal disposable e-cogs -- the type that appears to jus have 3 components: a battery, a heating element and something that looks like an electret microphone.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAfktTKLbOszpe4ObvNNqy1PuOln3U7APN19j2bvbC6rRGoWVroMY4ffNmbJZ5urcpI8yALk9RBb6E3M2BVwDI-6jrr6lMz1yyXGEL4TmX7gPhtJrAZ_90bSt3XRhMPCmg0tv4c1GFYnU1WRNwywNa8MHZHmxj-RFYAjVSvAgc-y_sCOMhhd7IqehGSTod/s1600/IMG20230808141003.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="682" data-original-width="1600" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAfktTKLbOszpe4ObvNNqy1PuOln3U7APN19j2bvbC6rRGoWVroMY4ffNmbJZ5urcpI8yALk9RBb6E3M2BVwDI-6jrr6lMz1yyXGEL4TmX7gPhtJrAZ_90bSt3XRhMPCmg0tv4c1GFYnU1WRNwywNa8MHZHmxj-RFYAjVSvAgc-y_sCOMhhd7IqehGSTod/w640-h272/IMG20230808141003.jpg" width="640" /></a></div><br /><p>The 'mic' turns out to be a lot more than just a microphone. For a start it has a blue LED on it that lights for a few seconds when it detects a strong pressure difference. I got this to work by attaching a short length of tubing to it and then blowing into it. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbJojSSjE_MtRglp5mXssWDcRusb4U5mOTz0-F8bbu0CY_Sk1vt1UYQhcp9Ynf2pwFhXG7kFJPqK2a81zi-GZk6eqZ0MxIMWUVLWDtCtC8CkjGMKCRQUyIb0TT2oQOrelMGWE48edzlgvikznwDbEMwuhs7ebt4nyfaHtNF22xf-K3bBHHs3Tt3cqqw91U/s1600/IMG20230808150154.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="860" data-original-width="1600" height="344" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbJojSSjE_MtRglp5mXssWDcRusb4U5mOTz0-F8bbu0CY_Sk1vt1UYQhcp9Ynf2pwFhXG7kFJPqK2a81zi-GZk6eqZ0MxIMWUVLWDtCtC8CkjGMKCRQUyIb0TT2oQOrelMGWE48edzlgvikznwDbEMwuhs7ebt4nyfaHtNF22xf-K3bBHHs3Tt3cqqw91U/w640-h344/IMG20230808150154.jpg" width="640" /></a></div><br /><p>I attached a load resistor to the output in order to measure the output voltage when the e-cig is activated. No real surprise here, but it matched the battery voltage closely.</p><p>Here, you can also see wha happens a the output when the e-cig is activated. Here is the wiring diagram for the e-cig.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcGUmDbcVWOgCZc8Z_glRpSSna3UC8qvOtPBKSA3m4fDphNyHqcmsDwGWrFj2VD9m4MMF_Z4BfRj_YV3Fm3aPdQ50Z3CMxV_nA-2r84h5FiAQgBhQOpx_xjbuLlYObAMRIA3PzCcZk9Uelz2M3oUYwgbfrWFEeM3TGl87tfizKxUHlvpXO8D6UVuaMtHdU/s1600/IMG20230808150322.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="988" data-original-width="1600" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcGUmDbcVWOgCZc8Z_glRpSSna3UC8qvOtPBKSA3m4fDphNyHqcmsDwGWrFj2VD9m4MMF_Z4BfRj_YV3Fm3aPdQ50Z3CMxV_nA-2r84h5FiAQgBhQOpx_xjbuLlYObAMRIA3PzCcZk9Uelz2M3oUYwgbfrWFEeM3TGl87tfizKxUHlvpXO8D6UVuaMtHdU/w640-h396/IMG20230808150322.jpg" width="640" /></a></div><br /><p>The mystery 'mic' is acting as a high-side switch. That is. one side of the heater element is connected to the battery negative (GND) and the 'mic' (when activated) connects the other end of the heater to the positive terminal of the battery.</p><p>I think that the 'mic' might actually be a pressure detector plus microcontroller MOSFET and LED all in an electret-insert-style case. The back of the case being a thin PCB with the LED on the outside. The only reason that I think the 'mic' might have a microcontroller in it, is the way that the output is timed and that the LED blinks just before the e-cig deactivates.</p><p>Here's my best guess as to what's in the 'mic' can.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIsJrP0mtnKeHqzrz5K3tPbU0nNzjE_Lkyrn8ZFqnWsgHHZOiF9LWZ1ZUyFn8EjThIjrairXdE4aBnCHQljfsu7QDobao5afjvCrOe4rOKUq6Fs0cowWs9O_jNvZvqV6oMA6FRKgNYgQ_i5eV53-XACU23RBSzrIpSDMxExsVojEfLr4MCwYYPvV93Qba1/s1600/IMG20230808151346.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1309" data-original-width="1600" height="524" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIsJrP0mtnKeHqzrz5K3tPbU0nNzjE_Lkyrn8ZFqnWsgHHZOiF9LWZ1ZUyFn8EjThIjrairXdE4aBnCHQljfsu7QDobao5afjvCrOe4rOKUq6Fs0cowWs9O_jNvZvqV6oMA6FRKgNYgQ_i5eV53-XACU23RBSzrIpSDMxExsVojEfLr4MCwYYPvV93Qba1/w640-h524/IMG20230808151346.jpg" width="640" /></a></div><br /><p>The pressure sensor may actually be a microphone, and the microcontroller does some thresholding and to decide if the air rushing over it constitutes someone drawing on the e-cig and then sets the output low to turn the P-channel MOSFET on. The LED does not seem to be in parallel with the output load, as applying a voltage back to the output when the e-cig is not activated does not light the LED. So, it looks like the LED is either connected to a different GPIO pin to the MOSFET, or its on the gate side.</p><p>Anyway - my collection of handy LiPos, of various sizes, is gradually increasing. There are just so many of these out there discarded on the street.</p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-56348357268799837742023-08-06T10:20:00.002-07:002023-08-06T10:20:24.557-07:00Disposable e-cigarette Teardown - Part 2<p>I seem to be inadvertently gaining a new hobby. A short cycle ride last week yielded 3 more 'disposable' e-cigs.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWa-xy-SCNPNMT1gpdlYK8yONk4olzn5hh-cYGP_DHjUD5siaMX705qEk9pS5uXUaptDdKEon_QTOGkaPoqMSf3018hjzhLgAL-Ijpiw73Yt0tzccsdPVTQww7Aijj3s93B0xyyvUyhlUhBfpPP2sN4KAhZJXUPRUV5vQy0lGuawYe0mymwuBUIPMsgYGr/s3484/IMG20230728110346.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1854" data-original-width="3484" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWa-xy-SCNPNMT1gpdlYK8yONk4olzn5hh-cYGP_DHjUD5siaMX705qEk9pS5uXUaptDdKEon_QTOGkaPoqMSf3018hjzhLgAL-Ijpiw73Yt0tzccsdPVTQww7Aijj3s93B0xyyvUyhlUhBfpPP2sN4KAhZJXUPRUV5vQy0lGuawYe0mymwuBUIPMsgYGr/w400-h213/IMG20230728110346.jpg" width="400" /></a></div><br /><p><br /></p><h2><span style="background-color: red; font-weight: normal;"><span style="color: white;">DANGER: </span></span></h2><div><span style="background-color: red; color: white;">There is a really good chance that the battery is still holding quite a lot of energy. The fluid runs out first. So if, during disassembly, the unit triggers (quite likely), then a big current will flow and the heating element will get hot. Similarly any accidental short between the leads to the battery could easily cause a fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Cut the leads to the element (one at a time) and to the battery (again one at a time) as soon as you can access them. </span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Also have a contingency plan such as fire blanket (not a bucket of water) or open window through which the flaming device can safely be thrown in the event of it catching fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">If in any doubt that you can do this safely, then don't do it.</span></div><p>This time, two ENG Legends and a more substantial R and M Tornado. The latter had a USB-C connector and although I couldn't see a way to refill it with fluid, looked like a reusable model. This turned up some interesting clues, as you will see later.</p><p>First, the ENG model. This is very similar to the models I took apart in my previous post.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQM0g8FP0S0SmRsW-EV7n77L64_c4JWV0Kjeb2x5O6tKbz6EiqTqGxFTT1fT1Sc2v7r1pMFC4iGrukLvAGTgB_gsqceD8CpXlLWkQA1DjcM5t-CFRmkyURf0Awst0iRhWuGQfWmYsI_d4MgNqD7RLPUzVWdwO4vC5RvUeV9XwcJJ5D89t3Hhyl0-WVdT0u/s3867/IMG20230728110916.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1406" data-original-width="3867" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQM0g8FP0S0SmRsW-EV7n77L64_c4JWV0Kjeb2x5O6tKbz6EiqTqGxFTT1fT1Sc2v7r1pMFC4iGrukLvAGTgB_gsqceD8CpXlLWkQA1DjcM5t-CFRmkyURf0Awst0iRhWuGQfWmYsI_d4MgNqD7RLPUzVWdwO4vC5RvUeV9XwcJJ5D89t3Hhyl0-WVdT0u/w640-h232/IMG20230728110916.jpg" width="640" /></a></div><br /><p>Again, it's much the same arrangement with a thing looking for all the world like an electret mic insert switching the battery to the heating element. It has a nice useable 5.5Wh battery -- again without any protection PCB.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7l7fnZJoB6awGMpkC5aRMuy0ioOnZdG3f64SZvMMLDK2P3XByO12jU8fsyujDeaJ8o5O1X0D0LEdMLNmj6VPZBRQkRhNuL5V8_56b1hBJiZaKRhPLSr6R5mKNA_iS5H3EZeM3GsgPQ8xnDew_VMM7WDUJMm2BmhqtLxzZWpwAwAOf8L96ypHUX-Tgkm_m/s2086/IMG20230728111101.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1207" data-original-width="2086" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7l7fnZJoB6awGMpkC5aRMuy0ioOnZdG3f64SZvMMLDK2P3XByO12jU8fsyujDeaJ8o5O1X0D0LEdMLNmj6VPZBRQkRhNuL5V8_56b1hBJiZaKRhPLSr6R5mKNA_iS5H3EZeM3GsgPQ8xnDew_VMM7WDUJMm2BmhqtLxzZWpwAwAOf8L96ypHUX-Tgkm_m/s320/IMG20230728111101.jpg" width="320" /></a></div><p>The insides of the R and M Tornado are altogether much more interesting. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid0iuIw6AE1t2NyR-SnbV0rbL-_U6UnBQBdhkkWv050gdGMo6z7pz1eaCctHhRvl8Pne0Zgy88L7oFZ5ZC5q1a5LPrWMv7NvMD-mv1ujq-eZGZORQHkPTCCFXR8Q4vE-0AbpqBPpf03ccLsQfa9YaxZV0qss1o_x1j-B87n26k3Bzd7eS2kOnxefhaIV3Z/s3811/IMG20230728111918.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1620" data-original-width="3811" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid0iuIw6AE1t2NyR-SnbV0rbL-_U6UnBQBdhkkWv050gdGMo6z7pz1eaCctHhRvl8Pne0Zgy88L7oFZ5ZC5q1a5LPrWMv7NvMD-mv1ujq-eZGZORQHkPTCCFXR8Q4vE-0AbpqBPpf03ccLsQfa9YaxZV0qss1o_x1j-B87n26k3Bzd7eS2kOnxefhaIV3Z/w640-h272/IMG20230728111918.jpg" width="640" /></a></div><br /><p>Not only does this board have a little PCB holding a LiPo charging circuit and USB-C socket, but also the PCB is nicely designed and silkscreen labels for the parts and terminals. A second PCB for the heating element has what I assume to be a SOT-23 MOSFET. The heater PCB receives power from the battery and a control signal from the first PCB,</p><p>This PCB has the USB socket and LiPo charging on one side.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk-U_eFr490fXTLG2NJfftHXZ0aCn6id6sJeuok0ytQaEGi2Br3M95vSLSVwpTFIBpE4xVTYc7KkgKMFb6T0H87snLwO4THMrNdGbubUTVsRLZyFxViL_0O2Qc7DKIlRIuzMNeMNKJYisIrVZto5VKqxvpRCzJ8VK7Wd7F2n9D9CSNip3OKye-EEAw_pAV/s1600/IMG20230728112344.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk-U_eFr490fXTLG2NJfftHXZ0aCn6id6sJeuok0ytQaEGi2Br3M95vSLSVwpTFIBpE4xVTYc7KkgKMFb6T0H87snLwO4THMrNdGbubUTVsRLZyFxViL_0O2Qc7DKIlRIuzMNeMNKJYisIrVZto5VKqxvpRCzJ8VK7Wd7F2n9D9CSNip3OKye-EEAw_pAV/w640-h480/IMG20230728112344.jpg" width="640" /></a></div><br /><p>The other side has a microphone that supplies the control signal to turn the heating element on.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPmldKtOb_l1sizcFj1UvzI4pJVctucgZ8FhOzssgHTlq-AhLc0XBoVdEPwsNiuCuVz2VW6Km7rHMoRx_3EOv4zFMTyaYVG3wre-kq6pFrKm5zipnABxdVfoaD6QIzYzkgKksU83Gt1Df4hMxeUVTCdeQPorglX9XZawpS0ODXbWPXxdou9vOMqQm687vs/s1600/IMG20230728112511.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPmldKtOb_l1sizcFj1UvzI4pJVctucgZ8FhOzssgHTlq-AhLc0XBoVdEPwsNiuCuVz2VW6Km7rHMoRx_3EOv4zFMTyaYVG3wre-kq6pFrKm5zipnABxdVfoaD6QIzYzkgKksU83Gt1Df4hMxeUVTCdeQPorglX9XZawpS0ODXbWPXxdou9vOMqQm687vs/w640-h480/IMG20230728112511.jpg" width="640" /></a></div><br /><p>This PCB is a handy little charging circuit. There is no obligation to use the 'puff sensing' feature. With the addition of a switch and a CREE LED bulb, you could make a great little USB torch. Maybe something for the next blog post.</p><p><br /></p><p><br /></p><p><br /></p><p><br /></p><p><br /></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-60412832961908823022023-07-19T07:46:00.005-07:002023-08-06T10:20:39.094-07:00Disposable e-cigarette Teardown - Part 1<p>I went for a lunch-time walk with the intention to look out for a discarded 'disposable' e-cigarette. I found by the side of the road almost immediately.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKMoXghkgGYTJmLCOw8XE9BroXZ01MvPEZ9KEz5fRdp9LuBddeR-3ACcJeJkZVPYINnVEig962LAHNW7jECvcPjxPmVcXTIA8mEXjmpQ84-QHpF95qWrynanLYhHKFe0AYtIFnGRRwcqBGedN4XEQsK1nv7L_wP3LFiZMeMSNi9vdLtQjxFSsiP-lNLqzQ/s3268/IMG20230719143146.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="858" data-original-width="3268" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKMoXghkgGYTJmLCOw8XE9BroXZ01MvPEZ9KEz5fRdp9LuBddeR-3ACcJeJkZVPYINnVEig962LAHNW7jECvcPjxPmVcXTIA8mEXjmpQ84-QHpF95qWrynanLYhHKFe0AYtIFnGRRwcqBGedN4XEQsK1nv7L_wP3LFiZMeMSNi9vdLtQjxFSsiP-lNLqzQ/w400-h105/IMG20230719143146.jpg" width="400" /></a></div><br /><h2 style="text-align: left;"><span style="background-color: red; font-weight: normal;"><span style="color: white;">DANGER: </span></span></h2><div><span style="background-color: red; color: white;">There is a really good chance that the battery is still holding quite a lot of energy. The fluid runs out first. So if, during disassembly, the unit triggers (quite likely), then a big current will flow and the heating element will get hot. Similarly any accidental short between the leads to the battery could easily cause a fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Cut the leads to the element (one at a time) and to the battery (again one at a time) as soon as you can access them. </span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">Also have a contingency plan such as fire blanket (not a bucket of water) or open window through which the flaming device can safely be thrown in the event of it catching fire.</span></div><div><span style="background-color: red; color: white;"><br /></span></div><div><span style="background-color: red; color: white;">If in any doubt that you can do this safely, then don't do it.</span></div><div><br /></div><p>This was quite a big one, and looking on the Internet sells for about £10 ($12). Far from being a flimsy thing, the case was well made and looked like it was designed to be taken apart. One end was held in place by push clips that opened easily with a screwdriver.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdKdsUhOVJHy6H51oaVectw14UzgWNhz4IaWMPjRTAsxAxPqYZ3BtPjbnIRDj_47HyIdDpweygp2Nsl_uQV2K-711HcTOf_fHZ16miT_Nz-4R4dUXh8FjEo79oOaAO3gMNoLNvp_IwBvID2PXr3Zk0JcP2_EXk8m87QPRpP0WLh5SM9e4HTrQ5Dd6IOcwO/s2265/IMG20230719143212.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1883" data-original-width="2265" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdKdsUhOVJHy6H51oaVectw14UzgWNhz4IaWMPjRTAsxAxPqYZ3BtPjbnIRDj_47HyIdDpweygp2Nsl_uQV2K-711HcTOf_fHZ16miT_Nz-4R4dUXh8FjEo79oOaAO3gMNoLNvp_IwBvID2PXr3Zk0JcP2_EXk8m87QPRpP0WLh5SM9e4HTrQ5Dd6IOcwO/s320/IMG20230719143212.jpg" width="320" /></a></div><br /><p><br /></p><p>So what did I find! Well, a lot less than I was expecting! There are just 3 electronic components:</p><p></p><ul style="text-align: left;"><li>The battery - 5.18Wh cylindrical LiPo. This was still measuring 3.4V</li><li>The heating element - showing a cold resistance of 1Ω</li><li>What looked like an electret mic insert, but I believe from the wiring, detects the cigarette being sucked, and switches power from the battery to the coil</li></ul><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf1mEoG3puL_GGNhOpk_1XG6P6dJyj8Q1chNuNKdSG9rTL81oGarjwI23_DGEGO7dY4GjsYgZajtiHny4tHCVH5kAB7NHNqeLNQEM7varREfkSra3zcgwLJkBOQD28xqhj45AX2wslSqoJO3haWqUY8EpAmEDPp4Rc2umejqihmcmP0AfJ3x8HvDNa0pAu/s3378/IMG20230719143310.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="915" data-original-width="3378" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjf1mEoG3puL_GGNhOpk_1XG6P6dJyj8Q1chNuNKdSG9rTL81oGarjwI23_DGEGO7dY4GjsYgZajtiHny4tHCVH5kAB7NHNqeLNQEM7varREfkSra3zcgwLJkBOQD28xqhj45AX2wslSqoJO3haWqUY8EpAmEDPp4Rc2umejqihmcmP0AfJ3x8HvDNa0pAu/w640-h174/IMG20230719143310.jpg" width="640" /></a></div><br /><div><br /></div><div><br /></div><div>There was no sign of any microcontroller or protection chip for the battery. The wiring is 0.4mm including insulation and not something that looked like it would cope with 3-4A. Hot wires and a heating element next to a LiPo cell - what could possibly go wrong!</div><div><br /></div><div>Anyway, the battery is on charge and I'm pretty sure will come in very handy in some project or other.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXmUp21S9LLzZd3PGLOlwqJFNblbXMhz-dDvoYf1uhwt9hT6pPSt9F1gZ17tRaUQtJQRry3UurCZtmcGgnYFw7mZq8rTCyE19SbtK-GZNhBbh9f7Mf_BNzn7sJRUJnjNDPV2z_W61K3ULFD6pbEmFwIPLl_PRV1b1OBGRQzHOvKMrHS0-Yio9UTgJZZtFq/s2082/IMG20230719143400.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1370" data-original-width="2082" height="422" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXmUp21S9LLzZd3PGLOlwqJFNblbXMhz-dDvoYf1uhwt9hT6pPSt9F1gZ17tRaUQtJQRry3UurCZtmcGgnYFw7mZq8rTCyE19SbtK-GZNhBbh9f7Mf_BNzn7sJRUJnjNDPV2z_W61K3ULFD6pbEmFwIPLl_PRV1b1OBGRQzHOvKMrHS0-Yio9UTgJZZtFq/w640-h422/IMG20230719143400.jpg" width="640" /></a></div><br /><div><br /></div><div><br /></div><div>I think it's a terrible waste of resources that these things are sold as disposable with insincere promises that they will be recycled properly. They aren't - people just drop them in the street.</div><p></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-72829873386566741872022-09-16T04:13:00.004-07:002022-09-16T04:13:24.665-07:00Simple Long Range Radio from Raspberry Pi to raspberry Pi Pico using HC-12 433MHz <p>I have a project in progress that is the third generation of my Hen House Door project. I want to be able to open and close the door from my home automation controller (Raspberry Pi 2 running <a href="https://nodered.org/">NodeRED</a>). Unfortunately, the hen house is at the end of the garden and out of WiFi range. Anyway the door opener is low-power and solar powered, and WiFi uses too much current.</p><p>I've used NRF24 and CC1101 modules before and frankly there are a lot of wires to connect for SPI and generally a mess of libraries to try and get working. Wouldn't it be lovely (I mused) if there was a long range wireless module that talked UART serial and hid all the communication layer stuff. </p><p>With a bit of googling, I was delighted to find the HC-12 modules that do exactly that. They take AT commands to configure them for power mode etc. But aside from that they work just like you had a cable between your two devices and talked serial along it.</p><p>Eventually, my Raspberry Pi 2 will talk to the hen house controller that is based on an ATTiny1616 at 1MHz and using a minimal amount of electricity except when driving the door motor. But as a first test, I thought it would be good to establish a link between a Pico and a regular Raspberry Pi (in this case, my Pi 400).</p><h2 style="text-align: left;">The Pico</h2><p>Here's the Pico end.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAEPOYa5wzh3Amhq3gT2XrqIGdWhwFEPSFaso_rfPkBu4uH4I8YOiQ8XeVdj4pqRVas2iwnM3rnRLVlWEm9pGNJHn0VEyxPeizx1doijqNjA35nvf1mUGPlmgpCvX1SpAszHsX_YXhNkFoBOwlls14sVZWuxF92BEqhYqPVqp9NxtrkMzupAAZ98wjmA/s1600/hc-12-pico.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1121" data-original-width="1600" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAEPOYa5wzh3Amhq3gT2XrqIGdWhwFEPSFaso_rfPkBu4uH4I8YOiQ8XeVdj4pqRVas2iwnM3rnRLVlWEm9pGNJHn0VEyxPeizx1doijqNjA35nvf1mUGPlmgpCvX1SpAszHsX_YXhNkFoBOwlls14sVZWuxF92BEqhYqPVqp9NxtrkMzupAAZ98wjmA/w640-h448/hc-12-pico.jpg" width="640" /></a></div><br /><p>The connections are:</p><p></p><ul style="text-align: left;"><li>GND on the Pico to GND on the HC-12</li><li>3V on the Pico to 3V on the HC-12</li><li>Tx on the Pico to Rx on the HC-12</li><li>Rx on the Pico to Tx on the HC-12</li></ul><div>To test it out, I used the program below - making sure its copied onto the Pico itself (use Save a Copy in Thonny) so I can take it mobile with a battery pack.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVaJpb8xke15rzI8Bmx-KgxMstRABlELf2l6Lb0AG5w4Yn_2Lm4m82dP2rUfNJAkP3kioqKpzBqUUj3ld9Z36Ylmqg4TisbBGMZwxL5SLAJJLvyA8E48kffInDn0dxqf5G34hvP1yyLXom1WlrEUCT5CUEUFUSB4fGLXq4E3jmjeG28wonBmTreAYfTw/s768/pico_program.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="724" data-original-width="768" height="604" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVaJpb8xke15rzI8Bmx-KgxMstRABlELf2l6Lb0AG5w4Yn_2Lm4m82dP2rUfNJAkP3kioqKpzBqUUj3ld9Z36Ylmqg4TisbBGMZwxL5SLAJJLvyA8E48kffInDn0dxqf5G34hvP1yyLXom1WlrEUCT5CUEUFUSB4fGLXq4E3jmjeG28wonBmTreAYfTw/w640-h604/pico_program.png" width="640" /></a></div><br /><div>Here's the code for ease of copying:</div><div><br /></div><div><div><span style="font-family: courier;">from machine import UART</span></div><div><span style="font-family: courier;">import time</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">uart = UART(0, 9600, timeout=400)</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">count = 0</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">while True:</span></div><div><span style="font-family: courier;"> count += 1</span></div><div><span style="font-family: courier;"> print(count)</span></div><div><span style="font-family: courier;"> uart.write(str(count)+"\n")</span></div><div><span style="font-family: courier;"> time.sleep(1)</span></div></div><div><br /></div><div><br /></div><h2 style="text-align: left;">The Raspberry Pi</h2><div>Here's an HC-12 attached to my Pi400 by way of a GPIO adapter and some jumper wires.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIsHg0ZziOimoflGZgM33jvbuOurYdvNgPPsK03zCgAJtmQx-EOF3thkWtbHa6hsqHlz59XWhuzJNneRLjy2vamhE27397M61M5M49Qt3yWRW2yR9tj5NGQPzIsvkLf1j_V3rpF4D4vy-yv_mJ1_9nlWaqExN7ks5Kiq4EIMMio3L7jDLf9wsqMZue1Q/s1876/pi_hc-12.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1876" data-original-width="1600" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIsHg0ZziOimoflGZgM33jvbuOurYdvNgPPsK03zCgAJtmQx-EOF3thkWtbHa6hsqHlz59XWhuzJNneRLjy2vamhE27397M61M5M49Qt3yWRW2yR9tj5NGQPzIsvkLf1j_V3rpF4D4vy-yv_mJ1_9nlWaqExN7ks5Kiq4EIMMio3L7jDLf9wsqMZue1Q/w546-h640/pi_hc-12.jpg" width="546" /></a></div><br /><div><p>The connections are:</p><p></p><ul><li>GND on the Pi to GND on the HC-12</li><li>3V on the Pi to 3V on the HC-12</li><li>Tx on the Pi (14) to Rx on the HC-12</li><li>Rx on the Pi ( 15) to Tx on the HC-12</li></ul></div><div>The receiving code is just:</div><div><br /></div><div><div><span style="font-family: courier;">import serial</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">ser = serial.Serial('/dev/serial0', baudrate=9600)</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;">while True:</span></div><div><span style="font-family: courier;"> line = ser.readline().decode("utf-8")</span></div><div><span style="font-family: courier;"> print(line)</span></div></div><div><br /></div><div>Run the program, and it should start receiving numbers from the Pico. Wander around with the Pico powered from a USB battery pack and see how far you can get before you start loosing data. </div><div><br /></div><div><br /></div><div><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s1" style="color: #2fb41d; font-variant-ligatures: no-common-ligatures;">pi@pi400</span><span class="s2" style="font-variant-ligatures: no-common-ligatures;">:</span><span class="s3" style="color: #400bd9; font-variant-ligatures: no-common-ligatures;">~ $</span><span class="s2" style="font-variant-ligatures: no-common-ligatures;"> nano hc_12.py<span class="Apple-converted-space"> </span></span></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s1" style="color: #2fb41d; font-variant-ligatures: no-common-ligatures;">pi@pi400</span><span class="s2" style="font-variant-ligatures: no-common-ligatures;">:</span><span class="s3" style="color: #400bd9; font-variant-ligatures: no-common-ligatures;">~ $</span><span class="s2" style="font-variant-ligatures: no-common-ligatures;"> python3 hc_12.py<span class="Apple-converted-space"> </span></span></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1553</span></p><p class="p2" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 25px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;"></span><br /></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1554</span></p><p class="p2" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 25px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;"></span><br /></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1555</span></p><p class="p2" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 25px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;"></span><br /></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1556</span></p><p class="p2" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 25px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;"></span><br /></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1557</span></p><p class="p2" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px; min-height: 25px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;"></span><br /></p><p class="p1" style="background-color: black; color: #f2f2f2; font-family: Monaco; font-size: 18px; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; line-height: normal; margin: 0px;"><span class="s2" style="font-variant-ligatures: no-common-ligatures;">1558</span></p></div><div><br /></div><h2 style="text-align: left;">Conclusion</h2><div>Everything worked without a hitch and no need for any tricky SPI programming or dodgy libraries. Pyserial was all that was required. These are now my wireless modules of choice.</div><div><br /></div><div>I'm just using the little coiled-wire antenna that came with the module and I'm getting more than enough range to reach the hen house even through a few walls. The modules have a tiny antenna connector, to which an external antenna can be attached for maximum range. The <a href="https://www.elecrow.com/download/HC-12.pdf">module datasheet</a> claims 1km at maximum power and lowest baud rate. Please check that 433MHz is legal in your area.</div><div><br /></div><div>Next up for me is using the module's AT commands to balance low power with range and change channel, to avoid interference.</div><div><br /></div><p></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-17129227162384462632022-09-12T02:51:00.002-07:002022-09-12T02:51:37.375-07:00A Better Web Server for Raspberry Pi Pico W<p>The Pico W is a fantastic little device, but the examples I have found for serving web pages from it were all too low-level for my taste.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj31ee7-GfBIn-h6gxIZOmHKdvrdW7VRQ2qYbp9rujcK2qcxjdwe1T41JVUSNFd0FHfpbzcelzaKbTCJH6jkxRQp3Le_fm1AmUXOABhvA4bm8adpv52t25JsNLzDvG3IkIkphOVpHi5gsVTH39bLjb_mxEOsBcKzJ4DxB0UuEA0_8SKrJ-q9akGZm1dLg/s2747/fig-ed4-ch18-new-19.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1235" data-original-width="2747" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj31ee7-GfBIn-h6gxIZOmHKdvrdW7VRQ2qYbp9rujcK2qcxjdwe1T41JVUSNFd0FHfpbzcelzaKbTCJH6jkxRQp3Le_fm1AmUXOABhvA4bm8adpv52t25JsNLzDvG3IkIkphOVpHi5gsVTH39bLjb_mxEOsBcKzJ4DxB0UuEA0_8SKrJ-q9akGZm1dLg/s320/fig-ed4-ch18-new-19.jpg" width="320" /></a></div><br /><p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66EP8MhvyOpeotlPtRtsYIwcqFtdWdM1emm_06RnOnMvgeLHzqtLo2bzoLW3jotev9oPkExzCeKrs8FIeNJL5r-T43DaotOTDjVVSVwCjQdrdn9YSJCivlgGx9CaFuM1DVJIxFNgQYja_xqQUPu4dvEQ7eXQRBbAEBQavrOcg6_nZA32-wIQQOzIt1Q/s600/fig-ed4-ch18-new-21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="228" data-original-width="600" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66EP8MhvyOpeotlPtRtsYIwcqFtdWdM1emm_06RnOnMvgeLHzqtLo2bzoLW3jotev9oPkExzCeKrs8FIeNJL5r-T43DaotOTDjVVSVwCjQdrdn9YSJCivlgGx9CaFuM1DVJIxFNgQYja_xqQUPu4dvEQ7eXQRBbAEBQavrOcg6_nZA32-wIQQOzIt1Q/w400-h153/fig-ed4-ch18-new-21.png" width="400" /></a></p><p>I'm big fan of Bottle and Flask as light-weight web frameworks. And was very excited to find the <a href="https://github.com/miguelgrinberg/microdot">microdot</a> project. This looks very much like Flask and Bottle, using the decorator syntax (@) to mark functions that are to respond to particular web requests. This leads to code as simple as this for a minimal web server.</p><pre style="border-radius: 6px; box-sizing: border-box; color: #24292f; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">from</span> <span class="pl-s1" style="box-sizing: border-box;">microdot</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">import</span> <span class="pl-v" style="box-sizing: border-box; color: var(--color-prettylights-syntax-variable);">Microdot</span>
<span class="pl-s1" style="box-sizing: border-box;">app</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">=</span> <span class="pl-v" style="box-sizing: border-box; color: var(--color-prettylights-syntax-variable);">Microdot</span>()
<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">@<span class="pl-s1" style="box-sizing: border-box;">app</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">route</span>(<span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'/'</span>)</span>
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">def</span> <span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">index</span>(<span class="pl-s1" style="box-sizing: border-box;">request</span>):
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span> <span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'Hello, world!'</span>
<span class="pl-s1" style="box-sizing: border-box;">app</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">run</span>()</pre><p>Now thats what I call the right level of abstraction. Not a reference to <i>socket</i> in sight!</p><p>The great news is that microdot works with the Raspberry Pi Pico. Although it takes care of all the web serving for you, it will not initiate your WiFi connection. Connecting to WiFi has a few subtleties such as showing connection progress and handling failure to connect and re-connection. It's definitely a wheel that doesn't need reinventing every time you want to serve a web page. So, I have put together a tiny module to wrap that process up as well. Its available here: <a href="https://github.com/monkmakes/mm_wlan">mm_wlan</a>.</p><p>Once installed, your entire web server code for your Pico will just become this:</p><pre style="border-radius: 6px; box-sizing: border-box; color: #24292f; font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">from</span> <span class="pl-s1" style="box-sizing: border-box;">microdot</span> <span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">import</span> <span class="pl-v" style="box-sizing: border-box; color: var(--color-prettylights-syntax-variable);">Microdot</span>
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">import</span> <span class="pl-s1" style="box-sizing: border-box;">mm_wlan</span>
<span class="pl-s1" style="box-sizing: border-box;">ssid</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">=</span> <span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'my network name'</span>
<span class="pl-s1" style="box-sizing: border-box;">password</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">=</span> <span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'my password'</span>
<span class="pl-s1" style="box-sizing: border-box;">app</span> <span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">=</span> <span class="pl-v" style="box-sizing: border-box; color: var(--color-prettylights-syntax-variable);">Microdot</span>()
<span class="pl-s1" style="box-sizing: border-box;">mm_wlan</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">connect_to_network</span>(<span class="pl-s1" style="box-sizing: border-box;">ssid</span>, <span class="pl-s1" style="box-sizing: border-box;">password</span>)
<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">@<span class="pl-s1" style="box-sizing: border-box;">app</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">route</span>(<span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'/'</span>)</span>
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">def</span> <span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">index</span>(<span class="pl-s1" style="box-sizing: border-box;">request</span>):
<span class="pl-k" style="box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);">return</span> <span class="pl-s" style="box-sizing: border-box; color: var(--color-prettylights-syntax-string);">'Hello, from Pico'</span>
<span class="pl-s1" style="box-sizing: border-box;">app</span>.<span class="pl-en" style="box-sizing: border-box; color: var(--color-prettylights-syntax-entity);">run</span>(<span class="pl-s1" style="box-sizing: border-box;">port</span><span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">=</span><span class="pl-c1" style="box-sizing: border-box; color: var(--color-prettylights-syntax-constant);">80</span>)</pre><h2 style="text-align: left;">Step by Step</h2><div>1. Install microdot and mm_wlan. This involves copying just two files, <a href="https://raw.githubusercontent.com/miguelgrinberg/microdot/main/src/microdot.py">microdot.py</a> and <a href="https://raw.githubusercontent.com/monkmakes/mm_wlan/main/mm_wlan.py">mm_wlan.py</a> onto the file system of your Pico W.</div><div><br /></div><div>You can do this by opening these files in Thonny and, with your Pico W connected to your computer choosing<b> Save copy</b> from the <b>File</b> menu. When prompted select Raspberry Pi Pico as the destination and save the file onto the Pico's file system using its original name.</div><div><br /></div><p>2. Start a <b>new</b> file in Thonny and paste in the code immediately above. Change <b>ssid</b> and <b>password</b> to match your WiFi network and run it. When you do so, you will see the IP address that the server is running on in the Shell area at the bottom of the Thonny window. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQSbRLgXj1_3zvxaFh8xsBd3A-yXjV-hXDvT3ZJBkacG_4yW32jL3OUz3QXN0Ne91JZ7CXhaqKUOHTLWM7L4BbADe6jspQ91b8Rdz_ZkucueaJWHh1pGIQx7JEaASjkCvv-y20GUPm4j4Xh920bhz8PZEIbSYOTp8LZlfoIjigkoDPI9O6EaDfp5Y97w/s820/fig-ed4-ch18-new-20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="767" data-original-width="820" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQSbRLgXj1_3zvxaFh8xsBd3A-yXjV-hXDvT3ZJBkacG_4yW32jL3OUz3QXN0Ne91JZ7CXhaqKUOHTLWM7L4BbADe6jspQ91b8Rdz_ZkucueaJWHh1pGIQx7JEaASjkCvv-y20GUPm4j4Xh920bhz8PZEIbSYOTp8LZlfoIjigkoDPI9O6EaDfp5Y97w/w400-h374/fig-ed4-ch18-new-20.png" width="400" /></a></div><br /><p>Now open a web browser on that IP address:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66EP8MhvyOpeotlPtRtsYIwcqFtdWdM1emm_06RnOnMvgeLHzqtLo2bzoLW3jotev9oPkExzCeKrs8FIeNJL5r-T43DaotOTDjVVSVwCjQdrdn9YSJCivlgGx9CaFuM1DVJIxFNgQYja_xqQUPu4dvEQ7eXQRBbAEBQavrOcg6_nZA32-wIQQOzIt1Q/s600/fig-ed4-ch18-new-21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="600" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi66EP8MhvyOpeotlPtRtsYIwcqFtdWdM1emm_06RnOnMvgeLHzqtLo2bzoLW3jotev9oPkExzCeKrs8FIeNJL5r-T43DaotOTDjVVSVwCjQdrdn9YSJCivlgGx9CaFuM1DVJIxFNgQYja_xqQUPu4dvEQ7eXQRBbAEBQavrOcg6_nZA32-wIQQOzIt1Q/w400-h153/fig-ed4-ch18-new-21.png" width="400" /></a></div>Hurray! Your Pico W is being a web server!<br /><h2 style="text-align: left;">Adding Another Page</h2><p>Let's now add a second page to the web server called <i>memory</i> that reports how much free memory the Pico W has. The previous page returned plain text rather than HTML. The default response type of microdot is <b>text</b>, so even if we had put HTML tags into the response, it is displayed literally and not be interpreted by the browser as HTML.</p><p>For this new page we will need to import the gc (Garbage Collector) package:</p><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><p style="text-align: left;"><span style="font-family: courier;">import gc</span></p></blockquote><p>and then add a handler like this:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-size: x-small;"><span style="font-family: courier;">@app.route('memory')<br /></span><span style="font-family: courier;">def index(request):<br /></span><span style="font-family: courier;"> response = '<h1>Free Memory={} bytes</hi>'.format(gc.mem_free())<br /></span><span style="font-family: courier;"> return response, {'Content-Type': 'text/html'}</span></span></div></blockquote><p>Notice that now, as well as returning the response text, we also return the content type.</p><p>Run the program and, when you point your browser to the page memory, this is what you should see:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_JKi0fY96wk5sL6AMRfg1mlnOpwUvbEw9_8olnVOx-cgNO9tB2xxKmg7BYL-Lgalt-ZONWCUPiiX3iB08h4ZVhqNZvhiU69nlDa7951TViFrTnAZr-ZRnHGbr0TlC53SZ05ogzl70o6GQrJLq6iMk5DlyQMcIHAJj692fpCvDUc_MkxeO8xfTYLytug/s620/Screenshot%202022-09-12%20at%2010.14.27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="178" data-original-width="620" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_JKi0fY96wk5sL6AMRfg1mlnOpwUvbEw9_8olnVOx-cgNO9tB2xxKmg7BYL-Lgalt-ZONWCUPiiX3iB08h4ZVhqNZvhiU69nlDa7951TViFrTnAZr-ZRnHGbr0TlC53SZ05ogzl70o6GQrJLq6iMk5DlyQMcIHAJj692fpCvDUc_MkxeO8xfTYLytug/s320/Screenshot%202022-09-12%20at%2010.14.27.png" width="320" /></a></div><br /><p>Try refreshing the page a few times and you should see the free memory change.</p><p>Here's the whole program:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">from microdot import Microdot</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">import mm_wlan</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">import gc</span> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">sid = 'my network name'</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">password = 'my passord'</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">app = Microdot() </span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">mm_wlan.connect_to_network(ssid, password)</span> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">@app.route('/')</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">def index(request):</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"> return 'Hello, from Pico'</span> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">@app.route('memory')</span><span style="font-family: courier; font-size: x-small;"> </span> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">def index(request):</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"> response = '<h1>Free Memory={} bytes</hi>'.format(gc.mem_free())</span></div><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;"> return response, {'Content-Type': 'text/html'}</span> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"> </div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;"><span style="font-family: courier; font-size: x-small;">app.run(port=80) </span></div></blockquote><h2 style="text-align: left;">Templates</h2><p style="text-align: left;">As your web pages get a bit more complex, then some kind of templating will help you construct the response text. Here's an example of a multi-line example taken from an<a href="https://github.com/monkmakes/pmon"> example project </a>in the <a href="https://monkmakes.com/pmon.html">MonkMakes Plant Monitor</a>.</p><br /><br /><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">from microdot import Microdot<br /></span><span style="font-family: courier;">import mm_wlan<br /></span><span style="font-family: courier;">from pmon import PlantMonitor</span></blockquote><span style="font-family: courier;"><br /></span><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">ssid = 'network name'<br /></span><span style="font-family: courier;">password = 'password'</span></blockquote><span style="font-family: courier;"><br /></span><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">html = """<br /></span><span style="font-family: courier;"> <!DOCTYPE html><br /></span><span style="font-family: courier;"> <meta http-equiv="refresh" content="1" ><br /></span><span style="font-family: courier;"><html><br /></span><span style="font-family: courier;"> <head> <title>My Plant</title> </head><br /></span><span style="font-family: courier;"> <body><br /></span><span style="font-family: courier;"> <h1>Pico W Plant Monitor</h1><br /></span><span style="font-family: courier;"> <h2>Water: {water}</h2><br /></span><span style="font-family: courier;"> <h2>Temp (C): {temp}</h2><br /></span><span style="font-family: courier;"> <h2>Humidity: {humidity}</h2><br /></span><span style="font-family: courier;"> </body><br /></span><span style="font-family: courier;"></html></span></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">"""</span></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">pm = PlantMonitor()<br /></span><span style="font-family: courier;">app = Microdot()<br /></span><span style="font-family: courier;">mm_wlan.connect_to_network(ssid, password)</span></blockquote><span style="font-family: courier;"><br /></span><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">@app.route('/')<br /></span><span style="font-family: courier;">def index(request):<br /></span><span style="font-family: courier;"> w = pm.get_wetness()<br /></span><span style="font-family: courier;"> t = pm.get_temp()<br /></span><span style="font-family: courier;"> h = pm.get_humidity()<br /></span><span style="font-family: courier;"> response = html.format(water=w, temp=t, humidity=h)<br /></span><span style="font-family: courier;"> return response, {'Content-Type': 'text/html'}</span></blockquote><span style="font-family: courier;"><br /></span><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;">app.run(port=80)</span></blockquote><p style="text-align: left;"><br /></p><p>The neat trick here is to use the <b>meta</b> tag to automatically refresh the wen page every second. Perhaps a better way to do this would be to have a microdot page that serves the sensor values of JSON that Javascript then handles on the browser, with the home page including the Javascript to do that. But, that's a lot more work.</p><h2 style="text-align: left;">Summary</h2><p>The microdot framework will take a lot of the effort out of your Pico W projects where web serving is required. It's a really impressive bit of framework code.</p><p>The microdot framework is pretty complete, supporting different request types, request parameters and pretty much anything you could expect from such a compact web server framework.</p><p><br /></p><p><br /></p><p><br /></p><p><br /></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com1tag:blogger.com,1999:blog-5416726460697111362.post-22048414040072515552022-01-14T03:00:00.004-08:002022-01-14T03:00:57.468-08:00Pimping a Toy KitchenWe were given a toy kitchen for our grandchild to use. It had knobs for the hob, but they didn’t do anything except click. So I thought an upgrade might be in order.<div>This isn't a step-by-step writeup - I didn't photograph each step, so you'll have to fill in some of the blanks yourselves if you want to make something like this. You'll also need access to a laser cutter to make the diffusers.</div><div>I thought about using an Arduino or Pico, but decided there was little to be gained, so the design just uses resistors, switches and LEDs.</div><div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg39l616TzFBe5YLCBd0DiGUZGRkyUvNAFXyycF0RhGron_xY2x9fNbeYlhoVDzGniD08Id3Vc77e_xxex6m6IyUfo6UAYaHwMOCm6GpLyP0TlZ-v4RWhyaV2rUya-jqLRE6dh3RMPabZS_iSvN-hxlOVjcRXCs61FrLqpQphW7_QjcmOkvjzB0MygoJQ=s1600" 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/a/AVvXsEg39l616TzFBe5YLCBd0DiGUZGRkyUvNAFXyycF0RhGron_xY2x9fNbeYlhoVDzGniD08Id3Vc77e_xxex6m6IyUfo6UAYaHwMOCm6GpLyP0TlZ-v4RWhyaV2rUya-jqLRE6dh3RMPabZS_iSvN-hxlOVjcRXCs61FrLqpQphW7_QjcmOkvjzB0MygoJQ=w400-h300" width="400" /></a></div><br /><div><br /></div><div>Each ring uses 4 super-bright red LEDs behind a laser-cut arrangement of pearlescent acrylic. This gives a very pleasing and scarily realistic effect.</div><div><br /></div><div>You can also see a video of it in action here. The idea is that the controls are pots with a built-in switch, so that when you turn them a bit, they click on and the hob lights up dimly as if the ring is just on. As you turn the knob more clockwise the brightness increases to a maximum.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/TIbAU9H4z8w" width="320" youtube-src-id="TIbAU9H4z8w"></iframe></div><br /><div>To make this I used:</div><div><ul style="text-align: left;"><li>2 x 1kΩ 1/4W linear pot with SPST switch (from eBay)</li><li>2 x large knobs to fit the above</li><li>2 x 470Ω 1/4W resistors</li><li>8 x high brightness red LEDs (Vf 2.2V If 20mA)</li><li>3xAA 4.5V batter box</li><li>2 x A4 sheets of 3mm pearlescent acrylic</li></ul><div>Here's the schematic for one of the rings. If you find you have a lower Vf for your LEDs then you will need to add a suitable fixed resistor in series with the 4.5V supply and the pot. 100Ω should cover most eventualities. You will need to get the pot the right way around, so that when you first turn the knob a bit and the switch closes, you will effectively have the full 1k of the pot in parallel with the 470Ω resistor. At the far end of the travel, the pot resistance will be close to 0Ω, for maximum brightness.</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg9ZR3AT8QmedM1ut5QCLODCNDqtxWyqLtz53_B3QHRMAzRWNAQMiqP4lkAL6fBlfg0DZKf71YNxayQX9rd9bnURPW4-XEkisPLdkKQdcfZyhJrxjiLqsKC7Es8EpfhjaK5MbUjZQEVIOa58xdvkOQLvPOfxi7PG11N8MBB6Q3GsR94YYVfKgTzfB0y1w=s1067" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="800" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEg9ZR3AT8QmedM1ut5QCLODCNDqtxWyqLtz53_B3QHRMAzRWNAQMiqP4lkAL6fBlfg0DZKf71YNxayQX9rd9bnURPW4-XEkisPLdkKQdcfZyhJrxjiLqsKC7Es8EpfhjaK5MbUjZQEVIOa58xdvkOQLvPOfxi7PG11N8MBB6Q3GsR94YYVfKgTzfB0y1w=w300-h400" width="300" /></a></div><br /><div>And here's a closup of the back of one of the rings showing a healthy amount of hot-glue keeping everything in place.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjHmljOLliSjFXO1x9jhh4aOQr0-OMopileBdzkDeCcVPlvKbIFlpDsN8ZLN9qnGnCmP_mXtW00TCDOu9zcC_gzYXwkPd271si1xKWqrmGAfvvGHUwCg_UI16x4jSMB9X8adG_yq6_MhI4yJpLoEHrAXel6W3GSCBIePGKg3VQt5BShhJS1P2xfhtCAeA=s1200" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="1200" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjHmljOLliSjFXO1x9jhh4aOQr0-OMopileBdzkDeCcVPlvKbIFlpDsN8ZLN9qnGnCmP_mXtW00TCDOu9zcC_gzYXwkPd271si1xKWqrmGAfvvGHUwCg_UI16x4jSMB9X8adG_yq6_MhI4yJpLoEHrAXel6W3GSCBIePGKg3VQt5BShhJS1P2xfhtCAeA=s320" width="320" /></a></div><br /><div><br /></div><div><br /></div><div>Here are the laser cutting files, should you wish to adapt the design to you own kitchen.</div></div><div><br /></div><div>https://github.com/simonmonk/toy_kitchen_upgrade</div><div><br /></div><div>I had fun making this, and grandchild number one love it!</div><div><br /></div>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-63996376668771363552020-08-25T07:21:00.004-07:002020-08-25T07:21:44.839-07:00Testing the micro:bit's Analog Inputs<p>The BBC GPIO connection rings (labelled 0, 1 and 2) of a micro:bit can all be used as analog inputs.</p><p>You might think, that as long as you are careful to to exceed the 3V input voltage limit, then you can measure any low voltage whatever the source. Perhaps a photoresistor in a voltage divider arrangement with a fixed resistor. </p><p>While this is basically true, if the source of the voltage to be measured has a high output impedance, at some point the voltage measured by the micro:bit will diverge from reality as the impedance of the voltage source being measured increases.</p><p>In reality, you can't measure something without altering it. The best we can do is to make the measurement errors small, so that they can be ignored.</p><p>This blog post determines the extent of this measurement error with the micro:bit's analog inputs.</p><h2 style="text-align: left;">Equipment Used</h2><p>Here's a handy test program that reports the voltage at P0 when button A is pressed, that I used in this experiment.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://makecode.microbit.org/_icV0hzFWdX45" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" data-original-height="960" data-original-width="2184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJx0tcxjRDKAgh1iXuHa97OCk3iD6fCmeoFV0gvNNSDWCskDAiGzAfpl0mojBK0B1aGdwL0ayRxE88JgGgBfokXAQNcyfR1VlAHFaZPGRXTYNRuI7wSi6dPiuAAFYc7OC54VQziySLgEP2/s640/microbit-screenshot.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p>Use a multimeter to measure the voltage between the 3V and GND ring connectors on the micro:bit and put this value in for Vanalog. I was powering the micro:bit from USB, so Vanalog was about 3.2V.</p><p>You will also need:</p><p></p><ul style="text-align: left;"><li>A digital multimeter on DC volts range</li><li>Resistors 100Ω, 1kΩ, 10kΩ, 100kΩ, 1MΩ, 10MΩ</li><li>A low-impedance voltage source such as bench power supply (set to 2V) or just an AA battery</li><li>An alligator lead</li></ul><h2 style="text-align: left;">Setup</h2><div>Here's the setup for the experiment.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlcDezAikSkInOIP0EPl-V27UnA0pgh8IejR0-iiwlFtU80cLFIbiTqnnAQP3i7VWLA04HxMJTcE3zf6bvoZwIGSkvpeZLR0DLeIZxmh1r3GuBMmxMuwUEmUE69y0qFqSciLjtTF7zIy7/s576/IMG_0213.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="341" data-original-width="576" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlcDezAikSkInOIP0EPl-V27UnA0pgh8IejR0-iiwlFtU80cLFIbiTqnnAQP3i7VWLA04HxMJTcE3zf6bvoZwIGSkvpeZLR0DLeIZxmh1r3GuBMmxMuwUEmUE69y0qFqSciLjtTF7zIy7/s0/IMG_0213.JPG" /></a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWuO_XhdVYQhQs5uURtF0WawrDAGxlVnJjewBRG1ymcKuOjnkL1biK-dSlL50dWBigsa_sfqc-9C09lslN4EB7zYRrIU_oaXs8xdcqS9CZsewg9nlv7gA7dLLcrYfTM2HeEjShmyrddcj8/s640/IMG_0214.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWuO_XhdVYQhQs5uURtF0WawrDAGxlVnJjewBRG1ymcKuOjnkL1biK-dSlL50dWBigsa_sfqc-9C09lslN4EB7zYRrIU_oaXs8xdcqS9CZsewg9nlv7gA7dLLcrYfTM2HeEjShmyrddcj8/s0/IMG_0214.JPG" /></a></div><div><br /></div><div><br /></div><div>The ground of the micro:bit is connected to the ground of the power supply and the positive lead from the power supply is clipped to one end of the test resistor. The alligator lead is used to connect the other end of the resistor the micro:bit P0 ring. The multimeter measures the voltage at the micro:bit's P0 ring (V1). V2 is the voltage reported on the micro:bit by the test program.</div><div><br /></div><h2 style="text-align: left;">Results</h2><div>Here are the results for a series of resistor values.</div><div><br /></div><div><google-sheets-html-origin><table border="1" cellpadding="0" cellspacing="0" dir="ltr" style="border-collapse: collapse; border: none; font-family: Arial; font-size: 10pt; table-layout: fixed; width: 0px;" xmlns="http://www.w3.org/1999/xhtml"><colgroup><col width="100"></col><col width="100"></col><col width="100"></col></colgroup><tbody><tr style="height: 21px;"><td data-sheets-value="{"1":2,"2":"R (Ω)"}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; vertical-align: bottom;">R (Ω)</td><td data-sheets-value="{"1":2,"2":"V1 (V)"}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; vertical-align: bottom;">V1 (V)</td><td data-sheets-value="{"1":2,"2":"V2 (V)"}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; vertical-align: bottom;">V2 (V)</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":0}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">0</td><td data-sheets-value="{"1":3,"3":1.99}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.99</td><td data-sheets-value="{"1":3,"3":2.05}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">2.05</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":100}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">100</td><td data-sheets-value="{"1":3,"3":1.99}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.99</td><td data-sheets-value="{"1":3,"3":2.05}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">2.05</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":1000}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1,000</td><td data-sheets-value="{"1":3,"3":1.99}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.99</td><td data-sheets-value="{"1":3,"3":2.05}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">2.05</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":10000}" style="border: 1px solid rgb(204, 204, 204); font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">10,000</td><td data-sheets-value="{"1":3,"3":1.99}" style="border: 1px solid rgb(204, 204, 204); font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.99</td><td data-sheets-value="{"1":3,"3":2.02}" style="border: 1px solid rgb(204, 204, 204); font-weight: bold; overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">2.02</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":100000}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">100,000</td><td data-sheets-value="{"1":3,"3":1.99}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.99</td><td data-sheets-value="{"1":3,"3":1.77}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.77</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":1000000}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1,000,000</td><td data-sheets-value="{"1":3,"3":1.93}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.93</td><td data-sheets-value="{"1":3,"3":1.17}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.17</td></tr><tr style="height: 21px;"><td data-sheets-numberformat="{"1":2,"2":"#,##0","3":1}" data-sheets-value="{"1":3,"3":10000000}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">10,000,000</td><td data-sheets-value="{"1":3,"3":1.75}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">1.75</td><td data-sheets-value="{"1":3,"3":0.92}" style="border: 1px solid rgb(204, 204, 204); overflow: hidden; padding: 2px 3px; text-align: right; vertical-align: bottom;">0.92</td></tr></tbody></table></google-sheets-html-origin></div><div><br /></div><div>Even the multimeter starts to give errors when connected to the voltage source via a 10MΩ resistor. The DMM used is specified as having an input impedance of 10MΩ but actually these results imply it's quite a bit better than that.</div><div><br /></div><div>If we plot V1 and V2 against R, this is what we get:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0vNZNQDs52YSp6zOtfHVbxEgLewdNngmOzLvxwY2w-FK5nCAI7nY1BSX_AqG28_9uRdS5BuHYESH3KeaxEHr_vPGrrQ_iiDPcGJaN_ftimGE1H74IjUCm8gNrJh3BHhZTt757qkra-1Yf/s994/Screenshot+2020-08-25+at+15.06.37.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="752" data-original-width="994" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0vNZNQDs52YSp6zOtfHVbxEgLewdNngmOzLvxwY2w-FK5nCAI7nY1BSX_AqG28_9uRdS5BuHYESH3KeaxEHr_vPGrrQ_iiDPcGJaN_ftimGE1H74IjUCm8gNrJh3BHhZTt757qkra-1Yf/s640/Screenshot+2020-08-25+at+15.06.37.png" width="640" /></a></div><div>As you can see, the micro:bit does pretty well up until a value of R of 10kΩ after which it goes down hill pretty rapidly.</div><div><br /></div><h2 style="text-align: left;">Conclusion</h2><div>If you want to use your micro:bit to measure a voltage, try and keep the output impedance of the voltage source lower than <b><span style="font-size: x-large;">10kΩ.</span></b> </div><p></p>Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-8868060387594140312020-07-13T03:44:00.000-07:002020-07-13T03:44:19.333-07:00Unit Testing and Arduino<div dir="ltr" style="text-align: left;" trbidi="on">
When I worked in software, I was an early adopter of agile software development (eXtreme Programming) and so have always loved unit tests and TDD. Like many people from a software background, when I first started programming Arduino, my instinct was to write frameworks, <i>patternize</i> and <i>objectify</i> my code. Then I realised that I have 32k of program space to play with and a really big program might stretch to 100 lines of code (shock horror). So I adjusted my <i>big-software</i> thinking and like everyone else drew the line at functional decomposition and occasional library writing.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgftNzbhHz8ITL88bD5nkW3b0GjweZqXghwkPgVcE7mB-a_0l2wPMjfbBta9dboiWq1uu1n5_LtP206PNHD_zCDp60z5UsgXDjcNNTNIrhAEz5lGPmM15_loqk-rYqjrgJK9yxUXDSeqxBI/s1600/Arduino.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1173" data-original-width="1600" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgftNzbhHz8ITL88bD5nkW3b0GjweZqXghwkPgVcE7mB-a_0l2wPMjfbBta9dboiWq1uu1n5_LtP206PNHD_zCDp60z5UsgXDjcNNTNIrhAEz5lGPmM15_loqk-rYqjrgJK9yxUXDSeqxBI/s320/Arduino.jpg" width="320" /></a></div>
<h2 style="text-align: left;">
Background</h2>
For the fun of it, I recently decided to make a calculator (pocket calculator if you happen to have huge pockets) from the schematic design up.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAK5gnnv6-WeksIES_IhthzL5k4xZGyEeC9k7LBOdVui1DQv63rDtA3D0kBTt3Z_2CFlyd6HGehfJsvhSJBW4OGrjlSQppR7Ukrdv4zib_igIYSJ-llenIvLiZJdptvE0YG15SWaoMpDFs/s1600/IMG_0142.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1422" data-original-width="800" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAK5gnnv6-WeksIES_IhthzL5k4xZGyEeC9k7LBOdVui1DQv63rDtA3D0kBTt3Z_2CFlyd6HGehfJsvhSJBW4OGrjlSQppR7Ukrdv4zib_igIYSJ-llenIvLiZJdptvE0YG15SWaoMpDFs/s400/IMG_0142.JPG" width="225" /></a></div>
<br />
For this project I wanted to use my new favourite low cost microcontroller (the ATTINY816) with Arduino IDE using <a href="https://github.com/SpenceKonde/megaTinyCore">Spence Konde's rather fantasic Arduino core</a>.<br />
<br />
To my surprise, making a calculator that actually does arithmetic well is a lot harder than expected. One obvious hurdle is that float in Arduino C is only 32 bits. So once your numbers get to about 7 or 8 digits they become disconcertingly approximated. So, I thought,<i> I'm (or used to be) a computer scientist, I'll just implement my own floating point representation with more precision than you can shake a stick at</i>. So, I did, as a C++ library (I'll put it on Github when I've got it working and tidied up).<br />
<br />
However, for the first time, since I had first started using Arduino, I felt the need to write unit tests, to make sure that my number class was doing arithmetic and generating an 8 character string plus decimal point position information that I could then easily map onto an 8 digit 7-segment display.<br />
<br />
<h2 style="text-align: left;">
Unit Tests</h2>
If you haven't used unit testing before, then the basic idea is that you write a load of test functions (the more the better) that exercise the code being tested in some way and compare the outcome with the expected outcome. So, for example in a number class, you might want to check that when you add 2 and 2 you get 4, but also you write a test to make sure that when you add -123.45 and 0.01 you get -123.44 and not -123.46.<br />
<br />
Having a unit test suite behind your code means that if you change your code to fix one bug, when you run the tests it will immediately tell you if you have broken something else in doing so. As you build up your suite of tests, you get more and more test coverage for the tricky situations that may uncover bugs.<br />
<br />
<h2 style="text-align: left;">
My Solution for Arduino</h2>
The solution I came up with is very specific to the problem, so, I'll try and include some general principals rather than just the code.<br />
<br />
Firstly, I created a separate <i>test</i> sketch, specifically for the purpose of testing my number class, without any of the other code related to keyboard scanning and display refresh.<br />
<br />
The second thing I did was to get out an Arduino Uno (well actually I used a <a href="http://www.monkmakes.com/monkmakesduino-single.html">MonkMakesDuino</a>) because one of the great things about the Uno, is that compiling and uploading a sketch is MUCH quicker than the likes of an ESP32 or indeed the ATTiny816 programmed using UPDI. So, the round-trip time when adding tests or fixing code is greatly reduced.<br />
<br />
I used the Serial Monitor to view the results of the unit tests, and a test pass would simply marked by a single line giving the name of the test that passed. A test failure, would include as much information as possible to help with debugging.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK9Fvn1HQyTs6RcP1DipeIMdzCvduelLsJLredaaS9eQKXI_UbfFNKZEBhY_YGmfpE5w8ZLclXNkJhBaTfYQZqqvgjHtIyV3UhuPkOPeZVg7FbSpHtNDbEtIXtrrB42UzAMP2kkc90ev9h/s1600/Screenshot+2020-07-13+at+10.56.08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="954" height="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK9Fvn1HQyTs6RcP1DipeIMdzCvduelLsJLredaaS9eQKXI_UbfFNKZEBhY_YGmfpE5w8ZLclXNkJhBaTfYQZqqvgjHtIyV3UhuPkOPeZVg7FbSpHtNDbEtIXtrrB42UzAMP2kkc90ev9h/s640/Screenshot+2020-07-13+at+10.56.08.png" width="640" /></a></div>
<br />
<br />
Here's the start of my test sketch:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">#include "CalcNum.h"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">char digits[] = "........";</span><br />
<span style="font-family: Courier New, Courier, monospace;">const int numDigits = 8;</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">void setup() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.begin(9600);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testNums();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testAdd1();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testAdd2();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testSub1();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testMult1();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testMult2();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testMult3();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testDiv1();</span><br />
<span style="font-family: Courier New, Courier, monospace;"> testDiv2(); </span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">void loop() {}</span><br />
<br />
My number class is CalcNum (imaginative right!).<br />
digits[] is a data structure used by CalcNum in its <i>writeDigits() </i>method that prepares a string for easy mapping onto an 8 digit 7-segment display.<br />
<br />
All the test functions to be called are then listed out in the <i>setup</i> function, as we only need to run them once.<br />
<br />
The first of these (<i>testNums</i>()) tests the representation of numbers themselves rather than arithmetic, so lets skip on to the test function <i>testAdd1</i>():<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void testAdd1() {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> CalcNum x = CalcNum(12, 0);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> CalcNum y = CalcNum(3, 0);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> CalcNum z;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> CalcNum::add(x, y, &z);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> test("testAdd1", z, " 15", 7);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
This function defines two numbers (x and y) using an exponent form (x = 12 x 10^0 = 12).<br />
Adds them together and then calls the general purpose function <i>test</i> to see if the result was as expected.<br />
<br />
As an aside, I haven't used C++ operator overloading in my number class, as this would inevitably lead to the need for dynamic memory allocation, which I avoid like the plague when working on embedded systems.<br />
<br />
So, what are the parameters to <i>test</i>?<br />
<br />
The first is a string, that is the name of the test, the second is the CalcNum to be checked. the third is the expected result string from calling <i>writeDigits</i>() - in this case <i>15</i> with leading spaces. The final parameter is the expected position of the decimal point on the display (zero indexed, left to right).<br />
<br />
Here's what the function test looks like:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void test(char *testName, CalcNum z, char *expected, int expectedDP) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> z.writeDigits(numDigits, digits);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int dp = z.dpPos(numDigits);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if (strcmp(digits, expected) == 0 && dp == expectedDP) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> pass(testName, expected, expectedDP, z);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> fail(testName, expected, expectedDP, z);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
As you can see, the test function compares the calculated and expected 8 digit string and decimal point positions and if the match, calls <i>pass</i> and if they don't calls <i>fail</i>.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void pass(char *testName, char *expected, int expectedDP, CalcNum z) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("PASS: "); Serial.println(testName);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> //report(expected, dp, expectedDP, z);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
The function pass just prints out a message that the test passed, along with the name of the passing test. Note the commented out call to <i>report</i>. Sometimes this gets commented back in to shed light on why one test passed when another didn't.<br />
<br />
The <i>fail</i> function is much the same as <i>pass</i>, but with a different starting message.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void fail(char *testName, char *expected, int expectedDP, CalcNum z) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("**** FAIL: "); Serial.println(testName);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> report(expected, expectedDP, z);</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
The <i>report</i> function just prints out as much useful information about the result as possible, to help me fix the bug.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">void report(char *expected, int expectedDP, CalcNum z) {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("got digits["); Serial.print(digits); Serial.print("]dp="); Serial.print(z.dpPos(numDigits));</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("\t expected ["); </span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print(expected);Serial.print("]dp="); Serial.println(expectedDP);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("float: "); Serial.println(z.toFloat(), 10);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.print("m: "); Serial.print(z.m); Serial.print(" e:"); Serial.println(z.e);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> Serial.println();</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
<h2 style="text-align: left;">
Conclusion</h2>
Once this project is written, I probably won't write any more tests until I meet a similar project for which 'it seems to work ok' is not sufficient.<br />
<br />
However, its really easy just to put together some tests if you need to. For me, it wan't even worth looking to see if anyone had made a framework to do this and then taking the trouble to work out how to use it.<br />
<br />
I hope this write-up will help you if you find yourself needing some Arduino unit tests!<br />
<br />
<br />
<br />
<br />
<br /></div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com1tag:blogger.com,1999:blog-5416726460697111362.post-21400975922530101862020-04-12T05:07:00.000-07:002020-04-12T05:10:24.170-07:00Making Protective Face Shields with a K40 Laser Cutter - Part 3<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.doctormonk.com/2020/04/face-visors-with-k40-part1.html">Part 1</a> <a href="http://www.doctormonk.com/2020/04/face-visors-with-k40-part2.html">Part 2</a><br />
<br />
We finally had a chance for the household to go ahead and make some shields.<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw6ZTEAGOyFRWwp36AE_6fx6migySbwuOGPSJFA4ORsrXw1HhEJHjAV89zQyAvanwo9hvZG_jvD3j-WMEEAx8FXHAH1ICfSz1bNJL0ctkIAy7xJNQgtAw5FcCXObnGfp77MINPuThGzWR_/s1600/batch1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw6ZTEAGOyFRWwp36AE_6fx6migySbwuOGPSJFA4ORsrXw1HhEJHjAV89zQyAvanwo9hvZG_jvD3j-WMEEAx8FXHAH1ICfSz1bNJL0ctkIAy7xJNQgtAw5FcCXObnGfp77MINPuThGzWR_/s640/batch1.jpg" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
Cleanliness</h2>
<div>
This was tricky, I don't have gloves, but do have a face mask each that covers our mouths and noses. So, I would not count these masks as sterile and as such have been careful <b>to pass on that information to recipients</b>.<br />
<br /></div>
<div>
So we had frequent hand washes and (for what its worth) baby wipes to wipe down the plastic that gets a bit of a dirty residue from the smoke produced during cutting. </div>
<div>
<br />
Fortunately the masks are easy to clean.</div>
<h2 style="text-align: left;">
Finding Recipients</h2>
<div>
While waiting for the laser cutter to do its thing (about 8 mins / shield) there was plenty of time to open up Google Maps and search on care homes nearby. I emailed (where there was an email address on the website) or otherwise phoned a total of 5 homes within walking distance. </div>
<div>
One asked for 12 on the phone and was very grateful as they had no face shields at all. Another said the same on email (yesterdays delivery). And already we have two more deliveries to make tomorrow to care homes and GP surgeries. There is clearly a huge demand here in the UK.<br />
<br />
<h2 style="text-align: left;">
What Next?</h2>
The next step is to find a cheaper source of material than eBay! and find out if there is a better way to distribute.<br />
<br />
Although it seems that hospitals are the main focus and care homes and GP surgeries have rather been left to fend for themselves. So I feel that providing them with masks, fits both my small scale of production and a need that if it reduces infections will lighten the hospital load at the front end.<br />
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com1tag:blogger.com,1999:blog-5416726460697111362.post-61848142407673185722020-04-07T02:33:00.001-07:002020-04-10T11:49:54.638-07:00Making Protective Face Shields with a K40 Laser Cutter - Part 2<div dir="ltr" style="text-align: left;" trbidi="on">
In<a href="http://www.doctormonk.com/2020/04/face-visors-with-k40-part1.html"> part 1 of this post</a> I looked at laser-cutting the plastic band. In this post, we can now attach the clear A4 sheet to the shield.<br />
<br />
I used<a href="https://www.ebay.co.uk/itm/A4-Acetate-Sheets-Transparent-Clear-OHP-Craft-Office-Acetate-Film/202188062966"> this from eBay</a> with a thickness of 140 micros for the visor, which seems about right.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG79s8Tcq56hNCyM1_2URFpBn3AIcA7vyUMwBfNkTeJtvoeXCORC_u61y9boWUoUL6xI5Wv_d3WIOeeKwqEMfch0fZ9QL43n4DDMwjHwEGmG3XxIciYbG9k93cbQOg11rCNAFLHrbb4PQ2/s1600/visor_worn_front.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1307" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG79s8Tcq56hNCyM1_2URFpBn3AIcA7vyUMwBfNkTeJtvoeXCORC_u61y9boWUoUL6xI5Wv_d3WIOeeKwqEMfch0fZ9QL43n4DDMwjHwEGmG3XxIciYbG9k93cbQOg11rCNAFLHrbb4PQ2/s400/visor_worn_front.jpg" width="326" /></a></div>
<br />
The A4 clear 'acetate' sheet fits in landscape aspect ratio and is punched with 4 holes. I used one of these:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8wxRfbWLTUQCScxqTE1Wk4ybCPcSslMFpsakuNI-Ic6ZH6vDHGko0g2h5PGM2dRC09SCFu15UXlw8WLcu9wcbldDK0ky9WHyvDThAURjhhkmRLjJudrabX5s7VslRqf3uTuqL8RWVPd_e/s1600/hole_punch.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8wxRfbWLTUQCScxqTE1Wk4ybCPcSslMFpsakuNI-Ic6ZH6vDHGko0g2h5PGM2dRC09SCFu15UXlw8WLcu9wcbldDK0ky9WHyvDThAURjhhkmRLjJudrabX5s7VslRqf3uTuqL8RWVPd_e/s320/hole_punch.jpg" width="320" /></a></div>
<strike>.. and put one pair of holes in the middle, as you would a normal sheet of paper for a ring-binder. I then carefully put the other holes in at the edges by lining up one side of the hole punch puncher with an existing hole. This is fiddly, so </strike><br />
Edit: This works fine, didn't realize that if you push the guide rail on the side most of the way until it says A5 (on ours) punch one set of holes then flip the acetate sheet through 180 degrees and punch again, the holes are in the right places. Try this on paper first to avoid wasting acetate.<br />
<br />
<br />
I have ordered<a href="https://www.ebay.co.uk/itm/A4-Metal-Hole-Paper-Punch-Perforator-16-Sheet-Capacity-Black-Guide-Confetti-Tray/324123711982"> one of these</a>: which should make all the holes in one go.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP2s1HlxgjZ_8WA6vfU-UyGD_kCgEaY_GIUKJmklcd0nkJztZj7wHVQH2Jy2LGipPuyDNEeIrKWo2vqTwYi3EX8tEqgkuJvKtsFHS-nKev-e-Obs4AR3rXTw-Qu9X1AbvG6XX0T3QpUgXy/s1600/hol_punch_4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="500" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP2s1HlxgjZ_8WA6vfU-UyGD_kCgEaY_GIUKJmklcd0nkJztZj7wHVQH2Jy2LGipPuyDNEeIrKWo2vqTwYi3EX8tEqgkuJvKtsFHS-nKev-e-Obs4AR3rXTw-Qu9X1AbvG6XX0T3QpUgXy/s320/hol_punch_4.jpg" width="320" /></a></div>
The little plastic tabs on the strap fit snugly into the holes and hold the 'acetate' sheet in place.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX1MXHOUJo9wlKQQgUPc5CBnFy4uCJSQyxwewoDX24joE9s5t51g899DnHYwpj1SnTjxs-AmtPH8d91w5-RsYtAhptvXzhgo2o6FlUYSbOgHvHj1UK2fBX_cQHymbpuufFyKbmc5sYKMB9/s1600/fitting_acetate.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX1MXHOUJo9wlKQQgUPc5CBnFy4uCJSQyxwewoDX24joE9s5t51g899DnHYwpj1SnTjxs-AmtPH8d91w5-RsYtAhptvXzhgo2o6FlUYSbOgHvHj1UK2fBX_cQHymbpuufFyKbmc5sYKMB9/s640/fitting_acetate.jpg" width="640" /></a></div>
<br />
<br />
<h2 style="text-align: left;">
Review</h2>
The inner band holding the head away from the visor works well and prevents misting up. The whole thing was comfortable even wearing glasses. I'm sure its a way from rigorous professional protection equipment, but I think its a lot better than nothing, or just a face mask on its own.<br />
<br />
It's also entirely plastic and I would have thought washable. I have three of these now, which we are going to send to medical and carer friends of ours who have expressed an interest.<br />
<br />
Now I know its possible on A4, I'm ordering more materials and we'll get cracking. I'll come back with a part 3 on manufacturing cleanly and experiences in donating these.<br />
<br />
<h2 style="text-align: left;">
Other Resources</h2>
This all stems from the work here <a href="https://community.andmirrors.co.uk/t/covid-19-laser-cut-face-shield/168">https://community.andmirrors.co.uk/t/covid-19-laser-cut-face-shield/168</a> and <a href="https://www.kitronik.co.uk/blog/kitronik-make-nhs-frontline-ppe-visors/">https://www.kitronik.co.uk/blog/kitronik-make-nhs-frontline-ppe-visors/</a><br />
<br />
There are lots of other projects and designs out there and Google will stay a lot more up to date than any list I put here.</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-26444741802837313872020-04-06T02:25:00.000-07:002020-04-10T11:50:11.284-07:00Making Protective Face Shields with a K40 Laser Cutter - Part 1<div dir="ltr" style="text-align: left;" trbidi="on">
This blog documents my efforts to make protective face masks using a low cost K40 laser cutter using <a href="https://www.kitronik.co.uk/blog/kitronik-make-nhs-frontline-ppe-visors/">Kitroniks visor design</a>.<br />
<br />
The A4 'acetate' sheets for the transparent shielding bit haven't arrived yet, so consider this post a Part 1 , dealing just with making the strap shown below. The clear visor part will come later.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgds0TjMhgquEJW5rTEAlLEcz6FatzKbhf6nzrgrOlK9mMve2zr-p603x9fhpsWPAbFpVoNop-XIv3NFRMcJv8qpPf3g-6_-xpnZLaFP3xnxz_YAmp8jWMXhYk1m8qwFc6lE5T2C22WZpOX/s1600/12_finished_front.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1158" data-original-width="1600" height="462" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgds0TjMhgquEJW5rTEAlLEcz6FatzKbhf6nzrgrOlK9mMve2zr-p603x9fhpsWPAbFpVoNop-XIv3NFRMcJv8qpPf3g-6_-xpnZLaFP3xnxz_YAmp8jWMXhYk1m8qwFc6lE5T2C22WZpOX/s640/12_finished_front.jpg" width="640" /></a></div>
<br />
<br />
<b>Early indications: Yes, it's feasible - if you have a K40, give it a go.</b><br />
<br />
<h2 style="text-align: left;">
K40</h2>
These laser cutters are very low cost, but only have a small bed (about 330x220mm useable).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKcibPWxa8XSQOgcNl4KR7ZvefuUY2PGkCgatplNR3cnUDmI8jT-t78EfuGuFTIGlUbgxVCZpVcixFYc8FZ3p7nbZf5rZ3u4gx8XFOLjJn6etrT7M2gdfYjXZLqN8_nGc681SGinGkXIv/s1600/k40.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKcibPWxa8XSQOgcNl4KR7ZvefuUY2PGkCgatplNR3cnUDmI8jT-t78EfuGuFTIGlUbgxVCZpVcixFYc8FZ3p7nbZf5rZ3u4gx8XFOLjJn6etrT7M2gdfYjXZLqN8_nGc681SGinGkXIv/s640/k40.jpg" width="640" /></a></div>
<br />
Their bed is much too small to take the files that Kitronik designed for their cutters, but if you have a bigger laser cutter then don't mess around with A4 it will be much more efficient to go to the full-size design <a href="https://github.com/re-innovation/Face_Visor_PPE">here</a>.<br />
<br />
<h2 style="text-align: left;">
Design Files</h2>
<div>
Download the design files for A4 from github <a href="https://github.com/simonmonk/kitroniks_a4_visor">here</a> or direct zip download <a href="https://github.com/simonmonk/kitroniks_a4_visor/archive/master.zip">here</a>. The original DXF file was created by Dave at Kitronik and kindly passed on to me by Loraine Underwood, a fellow K40 owner (hers is in bit ATM)<br />
<br />
The file <a class="js-navigation-open " href="https://github.com/simonmonk/kitroniks_a4_visor/blob/master/A4%20face%20shield%20band.dxf" id="301dd3c7a464e351c79faf327c1b864e-f6f96d03d610bed54e833d60143fc7cfc997ffd7" style="background-color: #f6f8fa; box-sizing: border-box; color: #0366d6; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; text-decoration-line: none; white-space: nowrap;" title="A4 face shield band.dxf">A4 face shield band.dxf</a> is the original file from Dave. I use the open source <a href="https://www.scorchworks.com/K40whisperer/k40whisperer.html">K40 Whisperer</a> to control my K40, and this expects files to be an SVG, with vector cut lines to be in red 0.1mm wide. So the file <a class="js-navigation-open " href="https://github.com/simonmonk/kitroniks_a4_visor/blob/master/A4%20face%20shield%20band%20k40%20whisperer.svg" id="e4cc830a3a1a1fbe8b2377f7b881c353-768a888e9dd0bacf2613f24e2e851d43700f354c" style="background-color: white; box-sizing: border-box; color: #0366d6; font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 14px; text-decoration-line: none; white-space: nowrap;" title="A4 face shield band k40 whisperer.svg">A4 face shield band k40 whisperer.svg</a> is an SVG version of the original with the lines made suitable for K40 Whisperer. I have also spaced things out a bit, because the K40 can be a bit 'melty' and close together lines can cause problems.<br />
<br />
If you make a version of this for the default and highly suspect original K40 software, then please let me know and I'll add it to the repository.<br />
<br />
The really nice thing about this design is that it just uses two materials, 0.5mm Polypropylene for the strap material and standard clear A4 OHP acetates (used full size without the need to cut). Whats more everything just clips together, no need for glue or staples.<br />
<br />
<h2 style="text-align: left;">
Material</h2>
<div>
I bought a few sheets of Polypropylene Plastic Sheets 0.5mm <a href="https://www.ebay.co.uk/itm/2-x-A4-MID-BLUE-Polypropylene-Plastic-Sheets-0-5mm-Model-Making-Art-Craft/183482983322">here</a>. It seems to be quite widely available as A4 to try. I now need to wait for a load more. <a href="https://www.kitronik.co.uk/materials/polypropylene/0-5mm-polypropylene-sheets.html">Kitronic also sell this material</a>, but not as A4. However buying some big sheets and cutting them up may work out cheaper.</div>
<div>
<br /></div>
<div>
Eventually you will need the clear 'acetate' sheets to use as a visor - Kitronic recommend <a href="https://www.amazon.co.uk/gp/product/B000YC2UTS/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1">this</a>. My sheets haven't arrived yet, they will be discussed in part 2 of this blog.</div>
<h2 style="text-align: left;">
Cutting Parameters</h2>
<div style="text-align: left;">
Your parameters will vary so, please cut a small test piece before wasting material. This was what I found worked best for my K40. Speed for vector cut 15mm, power (set by the knob on the k40) about 50%. My beam seems to diverge at higher powers than that, but I probably don't have the focus right.</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/AVvXsEhZ90dXiJkdEKiRRLKNH-Ogk9XZ0BR7NSKg4_rQQEeTedTUcCTMTNJ_ZfAhjoQ1a96W4GYSWxyUBv7g5GQVQLrjKyrS3ud_r11hFz9Urg-0fzjtXgGo7yNCj4Pdk10jfdOECoyMLUC1ZILR/s1600/whisperer.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="694" data-original-width="912" height="486" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZ90dXiJkdEKiRRLKNH-Ogk9XZ0BR7NSKg4_rQQEeTedTUcCTMTNJ_ZfAhjoQ1a96W4GYSWxyUBv7g5GQVQLrjKyrS3ud_r11hFz9Urg-0fzjtXgGo7yNCj4Pdk10jfdOECoyMLUC1ZILR/s640/whisperer.png" width="640" /></a></div>
<div style="text-align: left;">
The material is quite light, and I have seen people use small magnets in this situation to keep the parts flat to the bed. I didn't use magnets and it worked ok for me. But if yours starts flapping about, you know what to do.</div>
<h2 style="text-align: left;">
Assembly</h2>
<div style="text-align: left;">
<span style="color: red;">Please note that what I am describing here is making the first visor so, I am paying no attention to cleanliness at all. When making these for real, I think it would be sensible to be gloved and masked.</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
It took me a while to figure out how the pieces fit together, so here's what I learned. I have put numbers on each piece to make it easier to reference the parts.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b>1. Here's the cut sheet.</b></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/AVvXsEjbcmHzIdz60ejZxjIymMZiJ4pKqeIQ6FgqqR1uaMOCwonAzhMo5s9yQbUCY_BBNyWavZE0m3nwe08TMdIoMYcsOX3FHwlc3zNzQQ7dl7ynb1r6biaoVU3GZ_y16X_DfBNlQUClD9OqNjL7/s1600/01_whole_sheet.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1144" data-original-width="1600" height="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbcmHzIdz60ejZxjIymMZiJ4pKqeIQ6FgqqR1uaMOCwonAzhMo5s9yQbUCY_BBNyWavZE0m3nwe08TMdIoMYcsOX3FHwlc3zNzQQ7dl7ynb1r6biaoVU3GZ_y16X_DfBNlQUClD9OqNjL7/s640/01_whole_sheet.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
There is a bit of singing and in places the plastic had stuck itself together again. But I found it separated from the sheet easily enough.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b>2. The Pieces Labelled</b></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
For your first make, I'd suggest marking each piece like this (a sharpie will do). Or you may just be a lot better at puzzles than me and consider all this unnecessary!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaRQK88tqH9gHk4cq1YHijLTlbZ3ltcYbVQUTEjTpsxuZpwtxu6CjLX5bc7N3013_dvvkig-7qFacz3Dx07vuFxgE5tads3o8jSZkXdoLbYRqTxqYr1vNv0zcyjd5aKVq_45IN_Y3cxzEs/s1600/02_pieces_numbered.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="922" data-original-width="1600" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaRQK88tqH9gHk4cq1YHijLTlbZ3ltcYbVQUTEjTpsxuZpwtxu6CjLX5bc7N3013_dvvkig-7qFacz3Dx07vuFxgE5tads3o8jSZkXdoLbYRqTxqYr1vNv0zcyjd5aKVq_45IN_Y3cxzEs/s640/02_pieces_numbered.jpg" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b>3. Join Pieces 1 and 2</b></div>
<div style="text-align: left;">
Bend the tabs of piece 1 and push them through the horizontal slots in part 2.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSrdBGoCDFm9rZqRi7FgysaLACQH33hKcBJbnJl04R4FTtXoJsKIKrTIZBTHDck3XtFecDtsOHahdRG2vJy1M3MWDxPobEQQxOOVuszyn32-BBdMr3vupr07vETyUhYw9K6CJBzWT4UeQl/s1600/03_joining_1_2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSrdBGoCDFm9rZqRi7FgysaLACQH33hKcBJbnJl04R4FTtXoJsKIKrTIZBTHDck3XtFecDtsOHahdRG2vJy1M3MWDxPobEQQxOOVuszyn32-BBdMr3vupr07vETyUhYw9K6CJBzWT4UeQl/s640/03_joining_1_2.jpg" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b>4. Join Pieces 2 and 3</b></div>
<div style="text-align: left;">
Piece 3 feeds through the two end vertical slots in piece 2 like a belt through a buckle.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgumjjCyiBHmZTgtIqm2lS-KMMPyQ_J8b7zDTJWhk-vIZYdat7QRMDgHlUOW7KMEf_DCF6IXdGLnN7XB5B-Dlh9kokY2YHgUYOgNWkw7B8FnevrGxZ9kP2T_V5HeUeHQeYCRtGP_gf1_lHe/s1600/04_joining_2_3.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="383" data-original-width="1600" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgumjjCyiBHmZTgtIqm2lS-KMMPyQ_J8b7zDTJWhk-vIZYdat7QRMDgHlUOW7KMEf_DCF6IXdGLnN7XB5B-Dlh9kokY2YHgUYOgNWkw7B8FnevrGxZ9kP2T_V5HeUeHQeYCRtGP_gf1_lHe/s640/04_joining_2_3.jpg" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<b>5. Join Pieces 1 and 4</b><br />
Piece 4 fits on to piece 1 in much the same way.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE9f3lQe3xwKe8FXkx4xhE18AlujVQ4nezg8vjDhh6GpOV_A02i-EfeGDDxVJRannt3PpCiHAce6Hs_PzESRxj4sSd2KzQ4NnZwEzwOgZ7h0dm1dZgJ6GrcKiG07f2pOAaQzXx_Co_yv2T/s1600/05_joining_1_4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="389" data-original-width="1600" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE9f3lQe3xwKe8FXkx4xhE18AlujVQ4nezg8vjDhh6GpOV_A02i-EfeGDDxVJRannt3PpCiHAce6Hs_PzESRxj4sSd2KzQ4NnZwEzwOgZ7h0dm1dZgJ6GrcKiG07f2pOAaQzXx_Co_yv2T/s640/05_joining_1_4.jpg" width="640" /></a></div>
<br />
<b>6. Outer Strap</b><br />
You should now have a long strap.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuUyE1fOmADRhtuEGnbf-wdyUTrfCujwFBJxDmCbFqOmtF8fPnJmOv17Qu1Xtzz6huTkR_1xN993V3BSkvNAM6tOxndVHTNztv96XvIfw8bxgxcJ4TYhAcUI_QxOCbv40RMC6AbwLZJuD4/s1600/06_main_strap.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="120" data-original-width="1600" height="46" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuUyE1fOmADRhtuEGnbf-wdyUTrfCujwFBJxDmCbFqOmtF8fPnJmOv17Qu1Xtzz6huTkR_1xN993V3BSkvNAM6tOxndVHTNztv96XvIfw8bxgxcJ4TYhAcUI_QxOCbv40RMC6AbwLZJuD4/s640/06_main_strap.jpg" width="640" /></a></div>
<br />
<b>7. Inner strap</b><br />
The inner strap is required to keep the clear part away from the wearer's face. Piece 5 accomplishes this by making a bow in the main strap.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtzrEK47iQTmfyzIQwJ98LzHFszv0QMz-IgnV1MusZehTACgjBliFaJpJp9vux5uqCwGzcW031-tCIcQTxwJQ3DKlwEq9nekq25lfBQg-UgXanCFxEtQVnC4i2aMocXQzURkL-6CmkJT_n/s1600/07_joining_2_5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="907" data-original-width="1600" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtzrEK47iQTmfyzIQwJ98LzHFszv0QMz-IgnV1MusZehTACgjBliFaJpJp9vux5uqCwGzcW031-tCIcQTxwJQ3DKlwEq9nekq25lfBQg-UgXanCFxEtQVnC4i2aMocXQzURkL-6CmkJT_n/s640/07_joining_2_5.jpg" width="640" /></a></div>
<br />
Start by joining piece 5 to piece 2 and then to piece 1 using the horizontal slots.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4_kHvOYtLMqpWLuSESGtnXi3tzueS4iHN2rJTkwr12bLLbofnrG30mRrpNa0h8j5jZQ3FKiyzCJ9cluTKwHtUskn5GegEoN_BCNL_pVR0yo96G8V50VvMy_LGI1_4Xv08Nya7GkmCx7y-/s1600/08_joining_2_5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="891" data-original-width="1600" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4_kHvOYtLMqpWLuSESGtnXi3tzueS4iHN2rJTkwr12bLLbofnrG30mRrpNa0h8j5jZQ3FKiyzCJ9cluTKwHtUskn5GegEoN_BCNL_pVR0yo96G8V50VvMy_LGI1_4Xv08Nya7GkmCx7y-/s640/08_joining_2_5.jpg" width="640" /></a></div>
<br />
<b>8. Final part</b><br />
The basic shape is there now, so it just remains to attach the buckle that connects the two ends of the strap together.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxTeHERBvAaf1QWMMAi1oVhwk5MXUzb-uGOmF7MYft6qIvCESNMD9Og7U9gC0Z1EmOHaBrt_Ay-dI252WHTdVWA9xp1ZaMoVMTJzNVPAg8vtoHmj2oW8HJEYzZvbvOw72uhlg2pR81kHSx/s1600/09_joining_4_6.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="1600" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxTeHERBvAaf1QWMMAi1oVhwk5MXUzb-uGOmF7MYft6qIvCESNMD9Og7U9gC0Z1EmOHaBrt_Ay-dI252WHTdVWA9xp1ZaMoVMTJzNVPAg8vtoHmj2oW8HJEYzZvbvOw72uhlg2pR81kHSx/s640/09_joining_4_6.jpg" width="640" /></a></div>
Join 4 and 6 together first. These have two positions, presumably for big and small heads. Fine adjustment of size uses piece 3.<br />
<br />
<h2 style="text-align: left;">
My Donation Plans</h2>
<div>
Making these on a K40 is slow and so I don't expect to be making more than a few hundred of these visors at most. So, personally, we will be donating these to care-workers and other people we know who are desperate for protective wear and not too worried about the quality on the basis that something is better than nothing. I think, I'll leave supplying to the NHS as something for the big players (with big laser cutters) to do. But that's just what I think.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
I hope to post part 2 of this tomorrow, if the clear plastic arrives.</div>
<div>
<br /></div>
<div>
Good luck and let me know how it goes.</div>
</div>
</div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-35072623591214268912020-02-11T01:20:00.000-08:002020-02-11T01:20:46.963-08:00Installing OpenCV 4 on a Raspberry Pi 4<div dir="ltr" style="text-align: left;" trbidi="on">
I have recently been updating the Computer Vision chapter of the third edition of my Raspberry Pi Cookbook. Way back when I was writing the seconds edition, I decided to use the SimpleCV wrapper to OpenCV because it was -- well very <i>simple</i> to use.<br />
<br />
SimpleCV is no longer maintained and in any case requires Python2. So the chapter's code needed to be changed to use OpenCV directly. Here's what I had to do on a Raspberry Pi 4 running Raspbian Buster (10).<br />
<br />
To install OpenCV, first install the prerequisite packages using these commands:<br />
<pre data-type="programlisting" style="background-color: #ececec; border-radius: 5px; border: 1px solid rgb(209, 209, 209); font-size: 0.9em; margin-bottom: 30px; margin-top: 30px; overflow-wrap: normal; overflow-x: auto; padding: 15px 5px;">$ sudo apt-get update
$ sudo apt-get install libhdf5-dev libhdf5-serial-dev libhdf5-103
$ sudo apt-get install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5</pre>
You may also need to update pip using:<br />
<pre data-type="programlisting" style="background-color: #ececec; border-radius: 5px; border: 1px solid rgb(209, 209, 209); font-size: 0.9em; margin-bottom: 30px; margin-top: 30px; overflow-wrap: normal; overflow-x: auto; padding: 15px 5px;">$ wget https://bootstrap.pypa.io/get-pip.py
$ sudo python3 get-pip.py</pre>
Then install OpenCV itself and Python image utilities using these commands:<br />
<pre data-type="programlisting" style="background-color: #ececec; border-radius: 5px; border: 1px solid rgb(209, 209, 209); font-size: 0.9em; margin-bottom: 30px; margin-top: 30px; overflow-wrap: normal; overflow-x: auto; padding: 15px 5px;">$ sudo pip install opencv-contrib-python==4.1.0.25
$ pip install imutils
</pre>
After installation is complete, you can check that everything is working by starting Python 3, importing cv2 and checking the version:<br />
<pre class="pagebreak-before" data-type="programlisting" style="background-color: #ececec; border-radius: 5px; border: 1px solid rgb(209, 209, 209); font-size: 0.9em; margin-bottom: 30px; margin-top: 30px; overflow-wrap: normal; overflow-x: auto; padding: 15px 5px;">pi@raspberrypi:~ $ <strong>python3</strong>
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> <strong>cv2.__version__</strong>
'4.1.0'
>>> exit()</pre>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-63607469115181329842019-11-08T07:29:00.003-08:002019-11-08T07:29:26.353-08:00Making an SD card out of 1960s transistors<div dir="ltr" style="text-align: left;" trbidi="on">
Reading about flash memory, I was staggered by the astronomical number of transistors in such a small place I decided to see what it would take to make one of these using 1960s technology.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3nlbN2xpQwyc_gN3ydV7qQkkSJ_iYWFYniTY8DqBuD8D3DWm6Vv6fhKkmPoD5Icfn06rQSPF3H63_9XPuzTi-3LGVPAA3hFwjWOj7unieKiAu9b1GPOhllm-tWxsqO21SCDLQ1wE38v4S/s1600/microSD.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="554" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3nlbN2xpQwyc_gN3ydV7qQkkSJ_iYWFYniTY8DqBuD8D3DWm6Vv6fhKkmPoD5Icfn06rQSPF3H63_9XPuzTi-3LGVPAA3hFwjWOj7unieKiAu9b1GPOhllm-tWxsqO21SCDLQ1wE38v4S/s200/microSD.JPG" width="178" /></a></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpdnEu_OS857R1iKoVREZfxjJBT35zgOsRKq0ikfzO38ZRHr9I2HCPScuU7GHnoJ1S4q7tXwRKc535CHOUY_WoBYa5VuIXfjS4VQi9yMjyTAgeLjqVRbUnlCiUirckOFate7w2VNHF1I3L/s1600/2n2222.JPG" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="847" data-original-width="467" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpdnEu_OS857R1iKoVREZfxjJBT35zgOsRKq0ikfzO38ZRHr9I2HCPScuU7GHnoJ1S4q7tXwRKc535CHOUY_WoBYa5VuIXfjS4VQi9yMjyTAgeLjqVRbUnlCiUirckOFate7w2VNHF1I3L/s200/2n2222.JPG" width="110" /></a><br />
<b><br /></b>
<b>Flash Memory:</b> Lets go with a modest 32GB micro-SD card.<br />
<div>
<br /></div>
<div>
<b>Transistor:</b> I'll use a TO-18 package transistor. If like me you are from the UK and of a certain age, then the BC108 or BC109 will bring fond memories of Wireless World magazine and minor soldering injuries. In the US, I think the 2N2222 was more popular.</div>
<div>
<br /></div>
<h2 style="text-align: left;">
How many transistors are there in a 32GB SD Card?</h2>
<div>
Each bit of flash memory is made up of a single special type of transistor (called a floating gate transistor) that uses the <i>quantum tunnelling </i>effect. I choose to understand this to mean that you can write to the memory bit electrons get trapped in an insulated region and you can tell they moved (and so whether they are a 1 or a 0) by how much current flowed. That's my probably erroneous and over-simplified understanding, but hey, it works for me.</div>
<div>
<br /></div>
<div>
So, bipolar junction transistors such as the BC109 and 2N2222 have been around since the 1960s and can in fact still be bought today. These transistors are not capable of storing a bit of data on their own, to do that, you would need to arrange two as a flip-flop. But remember this is a thought experiment, as you've probably guessed, it isn't actually possible to build a 16GB flash memory from 1960s transistors.</div>
<div>
<br /></div>
<div>
And so, to the calculation:</div>
<div>
32 GB means <b>roughly</b> (yes I know a GB is often taken to be 2^30) 32,000,000,000 bytes of data.</div>
<div>
Each byte comprises 8 bits, so let's say there are 8 x 32,000,000,000 = 256,000,000,000 bits of data.</div>
<div>
<br /></div>
<div>
Not only that, but the card will contain a whole load of transistors for control logic and caching. For the sake of this thought experiment, I am going to ignore this. So the answer is there are something like:</div>
<div style="text-align: center;">
<b><span style="color: red; font-size: large;">256,000,000,000 transistors in a 32GB flash memory</span></b></div>
<div style="text-align: center;">
<b><span style="font-size: large;"><br /></span></b></div>
<h2 style="text-align: left;">
<span style="font-size: large;"><b>Making this with TO-18 Transistors</b></span></h2>
Lets pretend we can make this thing with our TO-18 package transistors arranged in a square grid. To make a grid of 256,000,000,000,000 transistors is going to require a grid with the square root of 256,000,000,000,000 transistors on each side.<div>
<br /><div>
<div>
Thats roughly:</div>
<div>
<br /></div>
<div style="text-align: center;">
<span style="color: red; font-size: large;"><b>506,000 transistors per side</b></span></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpJGM7hgyGmdlxv6eFm37V4bZL0htEGUO1e8TWjzI3qm4lZertSy1X6bfnx3W7mVdFJWA-DwyGJJsY8ZERFo9ABqD2GWVwpT6Rw8SCczCCKZzmclxcp-drHwQjF6QDnW9qc3rF6wj-cx7_/s1600/grid_of_transistors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="456" data-original-width="465" height="313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpJGM7hgyGmdlxv6eFm37V4bZL0htEGUO1e8TWjzI3qm4lZertSy1X6bfnx3W7mVdFJWA-DwyGJJsY8ZERFo9ABqD2GWVwpT6Rw8SCczCCKZzmclxcp-drHwQjF6QDnW9qc3rF6wj-cx7_/s320/grid_of_transistors.png" width="320" /></a></div>
<div>
<br /><div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Each of our 1960s transistors is in a metal can with a diameter of about 5mm. If we assume that we need a bit of space around each transistor, then let's space them out to one transistor every 8mm. This means that each side of our array of transistors will have a size of 8mm x 506,000 or 4,048,000mm which is 4,048m which is roughly 4km (or roughly 2.5 miles)</div>
<div>
<br /></div>
<div style="text-align: center;">
<span style="color: red; font-size: large;"><b>A square 4km or 2.5 miles on each side</b></span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Let's superimpose a square 4km on each side on Manhatten.</div>
</div>
</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrhXg9GfXlTo5v92QlVUh9MGBjNq3zIGv0jFRxFTFEr4g1Lqai3ZLb78muAv1aBWhxHBTp1cg9LCZ_a0_E9wFrC1wcyHEVNq2yP2FFDnXiMNV_M982h3kX8o7jXOdyK_zndW4qgjZ1ANaj/s1600/manhatten.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1092" data-original-width="571" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrhXg9GfXlTo5v92QlVUh9MGBjNq3zIGv0jFRxFTFEr4g1Lqai3ZLb78muAv1aBWhxHBTp1cg9LCZ_a0_E9wFrC1wcyHEVNq2yP2FFDnXiMNV_M982h3kX8o7jXOdyK_zndW4qgjZ1ANaj/s640/manhatten.png" width="332" /></a></div>
<div>
<br /></div>
<div>
Each of our little transistors weights about 0.3g so 256,000,000,000 would weigh:</div>
<div>
<br /></div>
<div style="text-align: center;">
<span style="color: red; font-size: large;"><b>76,800 metric tonnes </b></span></div>
<div>
<br /></div>
<div>
- and thats ignoring the much greater weight of what it was mounted on.</div>
<div>
<br /></div>
<div>
When it comes to power consumption it's pretty hard to make anything useful up, especially as the distances involved mean that it would have no chance of actually working, even if our transistors were suitable. But let's just assume it would need its own power plant.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-49718547114961436062018-10-05T07:38:00.000-07:002018-10-05T07:38:25.567-07:00Arduino Air Quality Monitor<div dir="ltr" style="text-align: left;" trbidi="on">
I've recently spent some time developing the <a href="https://www.monkmakes.com/mb-co2/">MonkMakes CO2 Sensor</a> for micro:bit and have spent a fair amount of time researching into indoor air quality. It struck me that I actually had no idea how healthy (or otherwise) the air is, in the house that I both sleep and work in. <div>
<br /></div>
<div>
Time for a project! What's more I can reuse some of the sensors that I have accumulated while researching. These are low cost sensors, the whole lot costing probably less that GBP 50 (USD 50).</div>
<div>
<br /></div>
<div>
The project logs the following readings through USB back to the Arduino Serial Monitor, where you can copy and paste it into a spreadsheet:</div>
<div>
<ul style="text-align: left;">
<li>True CO2 level using the serial interface to the MH-Z14A CO2 sensor.</li>
<li>tVOC (Total Volatile Organic Compounds) in parts per billion (ppb) using a low cost CCS811 MEMs sensor breakout board</li>
<li>eCO2 - equivalent CO2 (derived from the tVOC sensor by the CCS811. You don't need these readings if you have real CO2 measurement, but I wanted them for comparison.</li>
<li>Particulates - µg/cubic metre - this was measured using a Sharp GP2Y1010 optical particulate sensor.</li>
</ul>
<div>
It all squeezed onto a breadboard and I used a <a href="https://www.monkmakes.com/mmd/">MonkMakesDuino</a> Uno compatible as the 'Arduino'. </div>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2VTAzjy3Y5YxFcjVM4qfy9wlxdlI985vYfl84-OVNSfOTDp5OH6EQSIMYWx6VLqPLffMsCU47U4WRord9qWssPGJpn-IYhcdW91OhDHEBhzxavOR7HWbPbm99E1QzNAdsdP7aayR4P3P8/s1600/finished+copia.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1580" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2VTAzjy3Y5YxFcjVM4qfy9wlxdlI985vYfl84-OVNSfOTDp5OH6EQSIMYWx6VLqPLffMsCU47U4WRord9qWssPGJpn-IYhcdW91OhDHEBhzxavOR7HWbPbm99E1QzNAdsdP7aayR4P3P8/s640/finished+copia.JPG" width="630" /></a></div>
<div>
<br /></div>
<div style="text-align: left;">
The output in the Serial Monitor is in Tab separated fields that can just be copied and pasted into a spreadsheet.</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/AVvXsEg-1YORSOgSdH8Jegr0Is37EXJbmSJUkUwnyiBYoamTjqlsoEHELV0h1q7xKM7cGWjiAJisOzl76fUlGpbqU-JNH5HDGE3lULK0iu6zU021BDv7iBj57n6X30Ev7iMYrB347ymvDnsqBFhn/s1600/serial_mon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="590" data-original-width="1136" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-1YORSOgSdH8Jegr0Is37EXJbmSJUkUwnyiBYoamTjqlsoEHELV0h1q7xKM7cGWjiAJisOzl76fUlGpbqU-JNH5HDGE3lULK0iu6zU021BDv7iBj57n6X30Ev7iMYrB347ymvDnsqBFhn/s640/serial_mon.png" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
Sensors</h2>
<h3 style="text-align: left;">
MH-Z14A (CO2)</h3>
<div>
You can find the MH-Z14A on eBay pretty cheap. While not the nicest CO2 sensor (I like the <a href="https://www.gassensing.co.uk/product/cozir-co2-sensor/">COZIR Ambient</a>) they do have the benefit of being really cheap (for a true CO2 sensor) and when compared with better sensors are accurate enough for this kind of project.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzi4t9jzXeF5xisxa17PGy7g5bnecmg4XueIKndV9LriCoOJSeh88fNUSxv5eE6YAjl7rgqjVYjZnIRMs782EzeeZk4RLqvby2i0WXjFk_IzM0Crq7fikbaziPKSOogDJlcNzNre7duaqD/s1600/mh-z14A.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="860" data-original-width="1600" height="344" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzi4t9jzXeF5xisxa17PGy7g5bnecmg4XueIKndV9LriCoOJSeh88fNUSxv5eE6YAjl7rgqjVYjZnIRMs782EzeeZk4RLqvby2i0WXjFk_IzM0Crq7fikbaziPKSOogDJlcNzNre7duaqD/s640/mh-z14A.JPG" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The device has a number of interfaces, but I used the TTL serial interface. This just requires 4 pins from the device (19-Tx, 18-Rx, 17-GND, 16-5V) shown left to right in the figure above.</div>
<div>
<br /></div>
<div>
The sensor has a serial protocol that requires a message to be sent from the Arduino, some-time after which a response will be received from which the PPM (parts per million) of CO2 can be extracted.</div>
<div>
<br /></div>
<div>
The sensor uses spectral absorption to optically measure the CO2 compensation. No compensation is made for temperature (indoor use, so stable temp assumed) or altitude (atmospheric pressure - but this is a small factor).</div>
<div>
<br /></div>
<div>
You can find the datasheet <a href="https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z14a_co2-manual-v1_01.pdf">here</a> but the datasheet for the older version of this product <a href="https://www.openhacks.com/uploadsproductos/mh-z14_co2.pdf">here</a> goes into more detail.</div>
<div>
<br /></div>
<div>
<br /></div>
<h3 style="text-align: left;">
CCS811 (tVOC)</h3>
<div>
This air-quality sensor chip measure Total Volatile Organic Compounds (unhealthy chemicals with a boiling point that makes them likely to get into our air). We breathe these out and they are also found from pollutants and chemicals we use in our lives. There are not many of them in good clean outdoor air - in most places anyway.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX8yNURC-4q4cCiqqdVDuQ3pHJBZVslEbEso0MhhMa6znGerCgo-WnOv3pyRgm7Z5xFM2SQj3U1rbygUPxraCeN2eCY9rep8coneW-bT7FOxByTXm7N__JsZpm-fuD84gr-cyoOwyB5Hsj/s1600/ccs811.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1057" data-original-width="827" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX8yNURC-4q4cCiqqdVDuQ3pHJBZVslEbEso0MhhMa6znGerCgo-WnOv3pyRgm7Z5xFM2SQj3U1rbygUPxraCeN2eCY9rep8coneW-bT7FOxByTXm7N__JsZpm-fuD84gr-cyoOwyB5Hsj/s320/ccs811.JPG" width="250" /></a></div>
<div>
My sensor came from eBay, but <a href="https://www.sparkfun.com/products/14193">Sparkfun also sell</a> a breakout board based on the same chip and made an Arduino library that I use in the code below.</div>
<div>
<br /></div>
<div>
It uses an I2C interface, but operates at 3.3V. You can find the <a href="https://cdn.sparkfun.com/assets/learn_tutorials/1/4/3/CCS811_Datasheet-DS000459.pdf">datasheet</a> here.</div>
<div>
<br /></div>
<h3 style="text-align: left;">
GP2Y1010 (Particulate density)</h3>
<div>
This is another eBay purchase. It measures reflections from particles in the air from which you can derive an approximate measurement of the number of µg per cubic meter of particles in the air. </div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYB76yEvYltNXzhFGFMxUNhmEs3HDBtEcaAmX8viBmyE1tfntg7KdP0RUj50YU421sf4xfp4JghMAdgwaAtrqfWz6PC2OggLYHv-eOCJmjAGPsySoqP4BOcVI-rgCaZKgK0UDXJf4o9xkd/s1600/GP2Y1010.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="943" data-original-width="1600" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYB76yEvYltNXzhFGFMxUNhmEs3HDBtEcaAmX8viBmyE1tfntg7KdP0RUj50YU421sf4xfp4JghMAdgwaAtrqfWz6PC2OggLYHv-eOCJmjAGPsySoqP4BOcVI-rgCaZKgK0UDXJf4o9xkd/s400/GP2Y1010.JPG" width="400" /></a></div>
<div>
<br /></div>
<div>
Pin 1 is the rightmost connection (white wire) in the figure above.</div>
<div>
<br /></div>
<div>
This depends on so many factors, not least the unknown mass of the particles, how much light (IR) they reflect etc that the reading has to be taken with a good dose of skepticism. But is does give an idea of how dusty the air is. </div>
<div>
<br /></div>
<div>
The device uses an analog output with a sensitivity of 0.65 Volts per 100µg per metre cubed.</div>
<div>
<br /></div>
<div>
You can find the datasheet for this device <a href="https://www.sparkfun.com/datasheets/Sensors/gp2y1010au_e.pdf">here</a>.</div>
<div>
<br /></div>
<h2 style="text-align: left;">
Schematic</h2>
<div>
Here's the schematic for the project.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhROHrqUCUiOEb-0EzHRiWr-96ZzFCIIt63U82984FPAN48QqfLDbEtoGqMgI4QBdDF6BhJypMZP80ujwmnTv0gBDHdNI4HWLlJ93gTNmUxrKx5LqI-PeVFm5kYSLm8rF5Be2AxsWRWHOM2/s1600/schematic.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1433" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhROHrqUCUiOEb-0EzHRiWr-96ZzFCIIt63U82984FPAN48QqfLDbEtoGqMgI4QBdDF6BhJypMZP80ujwmnTv0gBDHdNI4HWLlJ93gTNmUxrKx5LqI-PeVFm5kYSLm8rF5Be2AxsWRWHOM2/s640/schematic.jpg" width="572" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The GP2Y1010 uses high current pulses of IR. To prevent the switching of the IR sender affecting the readings because of drops in the supply voltage, a 150Ω resistor charges a 200µF reservoir capacitor to supply the IR LED with a pulse of power. The internal amplifier of the GP2Y1010 must be supplied directly from the 5V rail (pin 6).</div>
<div>
<br /></div>
<div>
Note that the CCS811 is 3.3V supply. It also needs the WAK (Wake) and AD (I2C address option) pins tying to GND. The module I used has built-in I2C pullup resistors.</div>
<div>
<br /></div>
<h2 style="text-align: left;">
Software</h2>
<div>
Here's the sketch. I've added lots of comments. Between the comments and the datasheets, it should make sense. You will need to add the <a href="https://github.com/sparkfun/SparkFun_CCS811_Arduino_Library/archive/master.zip">Sparkfun library</a> to your IDE, before it will compile.</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#include <SoftwareSerial.h></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#include "SparkFunCCS811.h"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#define CCS811_ADDR 0x5A</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">const int ledPin = A3;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">const int sensorPin = A0;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">const long samplePeriod = 1000L; // sample period in ms</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">SoftwareSerial co2Sensor(10, 11); // RX, TX</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">CCS811 vocSensor(CCS811_ADDR);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/* </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Messages to be sent by serial to the MH-Z14 CO2 Sensor</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">const byte requestReading[] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">const byte zeroCalibrate[] = {0xff, 0x87, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2};</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">byte result[9]; // buffer into which serial messages from the MH-Z14 are received</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Globals containing last sensor readings and the last time a set of readings was output</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">long lastSampleTime = 0; // more accurately when data was last logged to serial.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int vocCO2;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int tVoc;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int co2;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int partics;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">void setup() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.begin(9600);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> co2Sensor.begin(9600); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> vocSensor.begin();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> pinMode(ledPin, OUTPUT);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> digitalWrite(ledPin, HIGH); // active low</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> // write out headers for the columns of data</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.println("CO2 (ppm)\teCO2 (ppm)\ttVOC(ppb)\tParts (µg/m3)");</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Send the calibrate message to the MH-Z14 - setting it to 400ppm</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">void calibrate() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> for (int i = 0; i < 9; i++) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> co2Sensor.write(zeroCalibrate[i]); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">void loop() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> /*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Send the Z command after leaving the project in fresh 400ppm air for 5 mins</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (Serial.available()) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> char ch = Serial.read();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (ch == 'z') {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> calibrate();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> /*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * If the tVOC sensor has data ready, update the global variable</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (vocSensor.dataAvailable()) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> vocSensor.readAlgorithmResults();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> vocCO2 = vocSensor.getCO2();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> tVoc = vocSensor.getTVOC();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> /*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * If we are due to log another row of data, then take the CO2 and</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * partical readings and then send them all to serial</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> long now = millis();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (now > lastSampleTime + samplePeriod) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> lastSampleTime = now;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> co2 = readPPMSerial();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> partics = dustMicroGpm3();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.print(co2); Serial.print("\t"); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.print(vocCO2); Serial.print("\t"); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.print(tVoc); Serial.print("\t"); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> Serial.println(partics);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Send a serial message (9 bytes) to the MH-Z14 and wait for a response</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Parse the resulting data and return the reported CO2 concentration in ppm</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int readPPMSerial() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> for (int i = 0; i < 9; i++) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> co2Sensor.write(requestReading[i]); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> //Serial.println("sent request");</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> while (co2Sensor.available() < 9) {}; // wait for response</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> for (int i = 0; i < 9; i++) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> result[i] = co2Sensor.read(); </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> int high = result[2];</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> int low = result[3];</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> return high * 256 + low;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/*</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> * Return the particulates reading in µg/m3</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">int dustMicroGpm3() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> digitalWrite(ledPin, LOW); // active low pulse for the IR LED</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> delayMicroseconds(280); // wait before taking the analog reading</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> int raw = analogRead(sensorPin);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> delayMicroseconds(40);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> digitalWrite(ledPin, HIGH); // end the pulse</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> delayMicroseconds(9680); // give the capacitor time to recharge</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> float sensitivity = 0.0065; // V/µg/m3 .from the datasheet</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> float v = float(raw) * 5.0 / 1023.0;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> return int(v / 0.0065);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<br /></div>
<h2 style="text-align: left;">
Results</h2>
</div>
<div>
Here are the results for CO2, and eCO2, sampling every 10 seconds overnight in our bedroom. So, maybe time to sleep with the door open!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_mQ_gfj0hTyFaBCCcmpPLD43VAteuLA-L5I7cAdsO7ElGHojvvRVaGJmZYe96iu8iQPMXhY3TjUnwPI_mDgksjVikNxdPamIHTRV3RLLDPJtupiIK_xglgluEo6bm4q0GlWDL8JFZSJS/s1600/chart.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="482" data-original-width="1242" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_mQ_gfj0hTyFaBCCcmpPLD43VAteuLA-L5I7cAdsO7ElGHojvvRVaGJmZYe96iu8iQPMXhY3TjUnwPI_mDgksjVikNxdPamIHTRV3RLLDPJtupiIK_xglgluEo6bm4q0GlWDL8JFZSJS/s640/chart.png" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<h2 style="text-align: left;">
Links</h2>
<div>
You can find information on healthy levels of CO2 <a href="https://www.kane.co.uk/knowledge-centre/what-are-safe-levels-of-co-and-co2-in-rooms">here</a>.</div>
<div>
<br /></div>
<div>
For information on tVOC concentration and what it means, see <a href="https://iaqscience.lbl.gov/voc-intro">here</a>.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com2tag:blogger.com,1999:blog-5416726460697111362.post-46454000311414368322018-09-07T03:13:00.000-07:002018-09-07T03:13:31.931-07:00Review and use of: Katsu ZD-8915 Desoldering Station<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
Desoldering through-hole components with two or three legs, is pretty straightforward. Apply heat and some fresh solder to the underside and pull them out from the top. But when it comes to chips and modules with more pins, this approach doesn't work. </div>
Some people manage to master the use of the small pen-shaped 'solder-suckers'. The idea is that you melt the solder with an iron, and as soon as the solder is molten, place the solder-sucker over the joint and release the spring to suck up the solder. I've tried and failed to learn that skill.<br />
<div style="text-align: left;">
Enter stage left, the desoldering station.</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/AVvXsEg0Lo-b_f2E3GFoEGUL3MyW6u2ScUAh6M9tnhQgAVwNrgu-zJSexKjormbDJ7f6T_SxVY2GN8GsP0Je6VxxxL7mptRnHYTPQSLT-F84HRMgOnA15nROHOM9DHuTc1_TVX6Q2EGRq8QQPNzJ/s1600/whole_thing+copia.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1025" data-original-width="1600" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Lo-b_f2E3GFoEGUL3MyW6u2ScUAh6M9tnhQgAVwNrgu-zJSexKjormbDJ7f6T_SxVY2GN8GsP0Je6VxxxL7mptRnHYTPQSLT-F84HRMgOnA15nROHOM9DHuTc1_TVX6Q2EGRq8QQPNzJ/s640/whole_thing+copia.jpg" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
These use a hollow tip soldering iron and a vacuum pump, so that solder removal is a LOT easier than trying to use a pen-style solder-sucker.</div>
<div style="text-align: left;">
I bought the model shown (Katsu ZD-8915 Desoldering Station) from Amazon, but they are also available on eBay and I'm sure elsewhere too. </div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
What you get</h2>
<div style="text-align: left;">
The package included:</div>
<div style="text-align: left;">
</div>
<ul style="text-align: left;">
<li>the control unit, that shows both the actual and set temperatures (up to 480C)</li>
<li>de-soldering gun</li>
<li>two spare tips of different hole sizes, giving you three tips in total (1.0, 1.2 and 1.5mm)</li>
<li>a good solid stand for the desoldering gun</li>
<li>spare wadding pads </li>
<li>three sizes of cleaning tools to poke out the solder from the hollow nozzle</li>
<li>a factually correct but not very informative instruction book</li>
</ul>
<div>
Everything fitted together very well and actually felt like it was pretty good quality. The solder chamber containing the spring-loaded piston has to be occasionally emptied of solder and at first time is a bit confusing, as the wadding and metal disk just sit against the spring and fall out when you open up the chamber. Putting it back in, it took me a while to realise that the wadding pad goes in first, followed by the metal disk. After using the gun for a while I realised why there were spares of the wadding, as it gets spattered with solder.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1z5zrARQZuervgvtXr9vpFy7d6YZ0ncdJMWxdP9Fwkr9t0Pqfa6TaTm7Czt22kBnkHlymoqMhEbKaJQuIG1J_ulfPm01oe-WiJ9cyq2vvA6bXE-Tp438cBlN2qCXFwa8jvsWYBghQo6yw/s1600/nozzle+copia.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1z5zrARQZuervgvtXr9vpFy7d6YZ0ncdJMWxdP9Fwkr9t0Pqfa6TaTm7Czt22kBnkHlymoqMhEbKaJQuIG1J_ulfPm01oe-WiJ9cyq2vvA6bXE-Tp438cBlN2qCXFwa8jvsWYBghQo6yw/s640/nozzle+copia.jpg" width="640" /></a></div>
<div>
<br /></div>
<br />
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
Usage</h2>
<div>
I gave up on the instructions, which don't really explain how to use the gun and just watched a few YouTube videos.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG9Ox7OQ430-UjoLBL7aoYnRMqjeuEmG8vuQvCyDq7Hk7j24RXRwFBAOB_LO7xCtKge7oi-ObsUEzdue0IZ1rrPu14B5dxISSbDj5AS_Ixy0-dIkd9Tf-BsiKWPV_p40DWnh9FBHvHm7Xa/s1600/gun+copia.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1210" data-original-width="1600" height="484" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG9Ox7OQ430-UjoLBL7aoYnRMqjeuEmG8vuQvCyDq7Hk7j24RXRwFBAOB_LO7xCtKge7oi-ObsUEzdue0IZ1rrPu14B5dxISSbDj5AS_Ixy0-dIkd9Tf-BsiKWPV_p40DWnh9FBHvHm7Xa/s640/gun+copia.jpg" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Here's what I found to work for me, desoldering some DIL 7-segment LED modules for practice.</div>
<div>
<ol style="text-align: left;">
<li>Push the back of the piston down to prime the spring</li>
<li>Apply heat to the solder joint until the solder melts (applying a bit of fresh solder and adjusting the temperature as required)</li>
<li>Pull the trigger to turn on the suction pump</li>
<li>Adjust the angle of the nozzle to get as good a fit over the solder joint as possible. I found that if you listened to the vacuum pump you could hear it work harder when you get a better seal.</li>
<li>Release the piston to make the final suck and you should see a splodge of solder fly up the see-through piston and embed itself in the cotton. Thats the fun bit!</li>
<li>Inspect the joint and repeat if necessary.</li>
<li>Get a flat-bladed screwdriver under the thing you are desoldering and gently lever it out - desoldering some more if it won't move.</li>
</ol>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmpHmfC5cqxwPuDYTkTXJrYrciD9NyJc7cf375RYnRErOwuzn9QtWxkWR3r3ZOwzWtqd0_GejdfEjPgGYb6QoFHTumvrMHTSUykhupHUR7hjjNN9hI6Xil1iAbpzXq4CVObf6bgQTZVLw7/s1600/spring+copia.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="906" data-original-width="1600" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmpHmfC5cqxwPuDYTkTXJrYrciD9NyJc7cf375RYnRErOwuzn9QtWxkWR3r3ZOwzWtqd0_GejdfEjPgGYb6QoFHTumvrMHTSUykhupHUR7hjjNN9hI6Xil1iAbpzXq4CVObf6bgQTZVLw7/s640/spring+copia.jpg" width="640" /></a></div>
<div>
<br /></div>
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Feeling very pleased with my new purchase, I turned it off and went and had some lunch. When I came to start again, it didn't seem to be sucking.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
If I had read the instructions properly, I would have noticed the section warning me to <span style="color: red;">ALWAYS ROD OUT THE NOZZLE BEFORE YOU TURN OFF THE HEAT!</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
I had bunged up the nozzle, just where it meets the cylinder. It then took about an hour of poking, changing the temperature, running in more solder and even pouring in liquid flux. Eventually I unblocked it by taking the front off the gun and poking the solder out by rodding it from the other side.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Obviously this was entirely my fault and I'd like to say I have learned my lesson, but its quite possible that I'll forget again. </div>
<div style="text-align: left;">
<br /></div>
<h2 style="text-align: left;">
Verdict</h2>
<div>
Admittedly, this is the only desoldering tool that I've ever owned, so I don't have anything except the solder-sucking pens to compare it with, but I have to say I was very impressed.</div>
<div>
This has already more than paid for itself because I had some expensive modules that I really needed to reclaim. Overall, the quality is pretty good and I didn't expect it to be as easy to use as it was.</div>
<div>
<br /></div>
<div>
If like me you have some high value components, or a PCB that can't easily be replaced then I can recommend this tool. It really does work. </div>
<div>
<br /></div>
<div>
Just remember to clean it out before you turn it off.</div>
<div style="text-align: left;">
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-61363846493457511582018-06-14T07:38:00.000-07:002018-08-12T01:57:20.186-07:00Cuban Makers at "Copincha" in Havana<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
Last week I found myself in front of a room full of Cubans in Havana, delivering a course on Arduino in broken Spanish. Was this a variation on the kind of dream where you are sitting down to an exam without having done a stroke of revision? Or the dream where you find yourself at work having forgotten to put on your trousers? </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIOf65FlFx8Gd98L3q2u19Wqj-xr8KdFxW-IG1ILCMHRxg35yhRmSHRwjScdWPG4nLLx6iZ0_m3GPkfmDr-xoYyFdzhw2EijYgNzh_yKOPjO2RAbrvNSdkIEclDVk5JnevfiXBlpcFVJ4j/s1600/course_in_progress.jpg" 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/AVvXsEhIOf65FlFx8Gd98L3q2u19Wqj-xr8KdFxW-IG1ILCMHRxg35yhRmSHRwjScdWPG4nLLx6iZ0_m3GPkfmDr-xoYyFdzhw2EijYgNzh_yKOPjO2RAbrvNSdkIEclDVk5JnevfiXBlpcFVJ4j/s400/course_in_progress.jpg" width="400" /></a></div>
<div style="text-align: left;">
The sequence of events that led to this radical departure from my comfort zone - not so much stepping outside it, but more waving it goodbye and jumping on a plane - started a couple of years ago when I was contacted by Jonnet who had seen a Spanish language edition of one of my books and wanted to borrow it for her Cuban partner Mauri.<br />
Mauri and Jonnet were keen to establish some kind of makerspace in Havana to provide a place for local makers could come and share ideas, tools and resources. Cubans, by necessity, are an inventive and creative group of people. Resources are scarce and so a make-do-and-mend culture is totally natural to them. If ever there was a race of makers, it is probably the Cubans.<br />
My wife Linda and I have been learning Spanish for years despite little evidence of success. We also spent our honeymoon in Cuba and have very fond memories of the country. And so, to cut a long story short, in a rash moment I volunteered to run an Arduino course at their makerspace when it was up and running. And a year or so later, that is how I found myself in front of a group of Cubans, talking about Arduino in Spanish.<br />
Mauri, the driving force behind the makerspace also lives in the house containing the makerspace in quarters above the two rooms that make up the space. The space is called "Copincha" - "pincha" is Cuban slang for "work" and so "copincha" is a way of saying "co-work".<br />
Mauri and friends have used scrap wooden packaging cases to make box stools for sitting on as well as large work tables with table-tops that are removable to reveal ample storage space for tools and supplies to make best use of the space. There's probably ten square meters of table top and maybe twenty stools for sitting on. That is quite some labour of love!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC8geCxauPPjyZ-TtQAJDMW-pBAjq5X12FgVQcEj2U_o5PnRVgBfOU_s2xYDCKrSfhqPaKJ7-uziPDPqwzVTf1PWjnZDwvzjtX0VWLpkIZY0tGt-qLQxI6Uy5nga3HhWKVo9WD2ybdzcPG/s1600/advanced_group.jpg" 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/AVvXsEjC8geCxauPPjyZ-TtQAJDMW-pBAjq5X12FgVQcEj2U_o5PnRVgBfOU_s2xYDCKrSfhqPaKJ7-uziPDPqwzVTf1PWjnZDwvzjtX0VWLpkIZY0tGt-qLQxI6Uy5nga3HhWKVo9WD2ybdzcPG/s400/advanced_group.jpg" width="400" /></a></div>
<div>
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]-->
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:TrackMoves/>
<w:TrackFormatting/>
<w:PunctuationKerning/>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:DoNotPromoteQF/>
<w:LidThemeOther>EN-GB</w:LidThemeOther>
<w:LidThemeAsian>JA</w:LidThemeAsian>
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
<w:Compatibility>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:SplitPgBreakAndParaMark/>
<w:EnableOpenTypeKerning/>
<w:DontFlipMirrorIndents/>
<w:OverrideTableStyleHps/>
<w:UseFELayout/>
</w:Compatibility>
<m:mathPr>
<m:mathFont m:val="Cambria Math"/>
<m:brkBin m:val="before"/>
<m:brkBinSub m:val="--"/>
<m:smallFrac m:val="off"/>
<m:dispDef/>
<m:lMargin m:val="0"/>
<m:rMargin m:val="0"/>
<m:defJc m:val="centerGroup"/>
<m:wrapIndent m:val="1440"/>
<m:intLim m:val="subSup"/>
<m:naryLim m:val="undOvr"/>
</m:mathPr></w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"
DefSemiHidden="true" DefQFormat="false" DefPriority="99"
LatentStyleCount="276">
<w:LsdException Locked="false" Priority="0" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Normal"/>
<w:LsdException Locked="false" Priority="9" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>
<w:LsdException Locked="false" Priority="39" Name="toc 1"/>
<w:LsdException Locked="false" Priority="39" Name="toc 2"/>
<w:LsdException Locked="false" Priority="39" Name="toc 3"/>
<w:LsdException Locked="false" Priority="39" Name="toc 4"/>
<w:LsdException Locked="false" Priority="39" Name="toc 5"/>
<w:LsdException Locked="false" Priority="39" Name="toc 6"/>
<w:LsdException Locked="false" Priority="39" Name="toc 7"/>
<w:LsdException Locked="false" Priority="39" Name="toc 8"/>
<w:LsdException Locked="false" Priority="39" Name="toc 9"/>
<w:LsdException Locked="false" Priority="0" QFormat="true" Name="caption"/>
<w:LsdException Locked="false" Priority="10" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Title"/>
<w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
<w:LsdException Locked="false" Priority="11" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>
<w:LsdException Locked="false" Priority="22" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Strong"/>
<w:LsdException Locked="false" Priority="20" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>
<w:LsdException Locked="false" Priority="59" SemiHidden="false"
UnhideWhenUsed="false" Name="Table Grid"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>
<w:LsdException Locked="false" Priority="1" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 1"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 1"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 1"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>
<w:LsdException Locked="false" Priority="34" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>
<w:LsdException Locked="false" Priority="29" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Quote"/>
<w:LsdException Locked="false" Priority="30" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 1"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 1"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 2"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 2"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 2"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 2"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 2"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 3"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 3"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 3"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 3"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 3"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 4"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 4"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 4"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 4"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 4"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 5"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 5"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 5"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 5"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 5"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 6"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 6"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 6"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 6"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 6"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>
<w:LsdException Locked="false" Priority="19" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>
<w:LsdException Locked="false" Priority="21" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>
<w:LsdException Locked="false" Priority="31" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>
<w:LsdException Locked="false" Priority="32" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>
<w:LsdException Locked="false" Priority="33" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>
<w:LsdException Locked="false" Priority="37" Name="Bibliography"/>
<w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>
</w:LatentStyles>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:"MS 明朝";
mso-font-charset:78;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1791491579 18 0 131231 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1107305727 0 0 415 0;}
@font-face
{font-family:Cambria;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1073743103 0 0 415 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin-top:2.0pt;
margin-right:0cm;
margin-bottom:4.0pt;
margin-left:0cm;
text-indent:36.0pt;
line-height:150%;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;}
</style>
<![endif]-->
<!--StartFragment-->
<br />
<div style="text-align: left; text-indent: 0cm;">
My Arduino course was the first
course to be run at the makerspace and since we had mixed levels of ability,
with some very skilled Arduinoistas, I ran introductory Arduino lessons in the
morning and in the afternoon offered "consultations" to the advanced
groups who had projects that they wanted to work on.<br />
I brought Arduino compatibles
(actually <a href="https://www.monkmakes.com/mmd/" target="_blank">MonkMakesDuinos</a>) together with basic component kits and breadboards with
me but the course relied on the students having access to a laptop to program
the MonkMakesDuinos. In true Cuban style, this involved a fair amount of
borrowing and inventive solutions. For example, one student used a homemade
Raspberry Pi laptop to program the Arduino. Another used a Windows tablets with
a pop-up keyboard. With sharing and cooperation everyone was able to
participate.<br />
I am very pleased to hear that the course
is due to be repeated in July (when many Cubans are on leave from their day
jobs). This time, the course is being delivered by Yusinier, one of the local
experts at the course who amongst his many skills in art and technology has
taught Arduino to university students.<br />
The course and supporting code is
available as open source on <a href="https://github.com/simonmonk/arduino_course_es" target="_blank">GitHub here</a> and I would very much welcome any pull-requests to improve the Spanish.<br />
Here are just a couple of the things
that the course attendees made during the course:<br />
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">Juan, a retired mechanical engineer with a
passion for replica cars, worked on adding automation to a fibre-glass modelled
replica he was building from scratch. </span></div>
<div class="MsoNormal" style="text-align: left; text-indent: 0cm;">
<o:p></o:p></div>
<div class="MsoNormal" style="text-align: left; text-indent: 0cm;">
<o:p></o:p></div>
<div class="MsoNormal" style="text-align: left; text-indent: 0cm;">
<o:p></o:p></div>
<div class="MsoNormal" style="text-align: left; text-indent: 0cm;">
<o:p></o:p></div>
<div class="MsoNormal" style="text-align: left; text-indent: 0cm;">
<o:p></o:p></div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqcKWl_Pgx5uepf1m_0ARwsdg2lvEHeo_y6_Fa4V3fP34FHxhfh5mEqTeuEqoKixsBjRkaqt1PnjXrUqnXaDr_9_DDkXppngaBmEnYmQM6xCvjiiZnbG-x_6QtaJHm_D88Mbjb3QvSJUYp/s1600/juans_car_underside.jpg" 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/AVvXsEhqcKWl_Pgx5uepf1m_0ARwsdg2lvEHeo_y6_Fa4V3fP34FHxhfh5mEqTeuEqoKixsBjRkaqt1PnjXrUqnXaDr_9_DDkXppngaBmEnYmQM6xCvjiiZnbG-x_6QtaJHm_D88Mbjb3QvSJUYp/s400/juans_car_underside.jpg" width="300" /></a></div>
<div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]-->
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:TrackMoves/>
<w:TrackFormatting/>
<w:PunctuationKerning/>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:DoNotPromoteQF/>
<w:LidThemeOther>EN-GB</w:LidThemeOther>
<w:LidThemeAsian>JA</w:LidThemeAsian>
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
<w:Compatibility>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:SplitPgBreakAndParaMark/>
<w:EnableOpenTypeKerning/>
<w:DontFlipMirrorIndents/>
<w:OverrideTableStyleHps/>
<w:UseFELayout/>
</w:Compatibility>
<m:mathPr>
<m:mathFont m:val="Cambria Math"/>
<m:brkBin m:val="before"/>
<m:brkBinSub m:val="--"/>
<m:smallFrac m:val="off"/>
<m:dispDef/>
<m:lMargin m:val="0"/>
<m:rMargin m:val="0"/>
<m:defJc m:val="centerGroup"/>
<m:wrapIndent m:val="1440"/>
<m:intLim m:val="subSup"/>
<m:naryLim m:val="undOvr"/>
</m:mathPr></w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"
DefSemiHidden="true" DefQFormat="false" DefPriority="99"
LatentStyleCount="276">
<w:LsdException Locked="false" Priority="0" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Normal"/>
<w:LsdException Locked="false" Priority="9" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>
<w:LsdException Locked="false" Priority="39" Name="toc 1"/>
<w:LsdException Locked="false" Priority="39" Name="toc 2"/>
<w:LsdException Locked="false" Priority="39" Name="toc 3"/>
<w:LsdException Locked="false" Priority="39" Name="toc 4"/>
<w:LsdException Locked="false" Priority="39" Name="toc 5"/>
<w:LsdException Locked="false" Priority="39" Name="toc 6"/>
<w:LsdException Locked="false" Priority="39" Name="toc 7"/>
<w:LsdException Locked="false" Priority="39" Name="toc 8"/>
<w:LsdException Locked="false" Priority="39" Name="toc 9"/>
<w:LsdException Locked="false" Priority="0" QFormat="true" Name="caption"/>
<w:LsdException Locked="false" Priority="10" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Title"/>
<w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
<w:LsdException Locked="false" Priority="11" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>
<w:LsdException Locked="false" Priority="22" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Strong"/>
<w:LsdException Locked="false" Priority="20" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>
<w:LsdException Locked="false" Priority="59" SemiHidden="false"
UnhideWhenUsed="false" Name="Table Grid"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>
<w:LsdException Locked="false" Priority="1" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 1"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 1"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 1"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>
<w:LsdException Locked="false" Priority="34" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>
<w:LsdException Locked="false" Priority="29" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Quote"/>
<w:LsdException Locked="false" Priority="30" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 1"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 1"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 2"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 2"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 2"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 2"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 2"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 3"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 3"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 3"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 3"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 3"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 4"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 4"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 4"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 4"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 4"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 5"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 5"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 5"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 5"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 5"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 6"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 6"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 6"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 6"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 6"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>
<w:LsdException Locked="false" Priority="19" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>
<w:LsdException Locked="false" Priority="21" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>
<w:LsdException Locked="false" Priority="31" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>
<w:LsdException Locked="false" Priority="32" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>
<w:LsdException Locked="false" Priority="33" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>
<w:LsdException Locked="false" Priority="37" Name="Bibliography"/>
<w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>
</w:LatentStyles>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:"MS 明朝";
mso-font-charset:78;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1791491579 18 0 131231 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1107305727 0 0 415 0;}
@font-face
{font-family:Cambria;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1073743103 0 0 415 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin-top:2.0pt;
margin-right:0cm;
margin-bottom:4.0pt;
margin-left:0cm;
text-indent:36.0pt;
line-height:150%;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;}
</style>
<![endif]-->
<!--StartFragment-->
</span><br />
<div style="text-align: left; text-indent: 0cm;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">The chassis of the car was built to
use a single gear-motor as rear-wheel drive and a servo motor to control the
steering. This was combined with an ultrasonic range-finder to detect obstacles
and invoke an avoidance function that involved a randomly chosen turn to the
left or the right, followed by reversing. The design also included automatic
brake lights. The steering mechanism was made entirely from waste pieces of
plastic and skilful use of a Dremmel.</span><br />
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">Juan has an enormous collection of
vintage model cars that he restores, some of which are for display and some for
sale at a shop he runs with friends, at San Lázaro 1060 entre San Francisco y Espada
- somewhere around <a href="https://www.google.com/maps/place/23%C2%B008'22.2%22N+82%C2%B022'29.2%22W/@23.1395049,-82.3769718,17z/" target="_blank">here</a>.</span><br />
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">Yusinier is a visual artist and film maker and
amongst other things has to devise his own props, such as remotely triggered
fake bullet strikes. He often uses Arduino and his project during the course
was the controller for a motorized camera dolly.</span></span></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">
</span>
<br />
<div class="MsoNormal" style="text-indent: 0cm;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><o:p></o:p></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;">
</span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyXJOvBdfzHL2iJIi8KQfq58Qe88YqoYAHhKe92o7KQiBMLC1E-p6VzFfHtx5rMVpzLHOuLGV2oNSjp7PKNUo9qubAOhPqIP5gbZYPCKZimd1A3BglvuBUeHMHNktcaQqGvodvHiq17Kwd/s1600/yusniers_camera_controller.jpg" 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/AVvXsEiyXJOvBdfzHL2iJIi8KQfq58Qe88YqoYAHhKe92o7KQiBMLC1E-p6VzFfHtx5rMVpzLHOuLGV2oNSjp7PKNUo9qubAOhPqIP5gbZYPCKZimd1A3BglvuBUeHMHNktcaQqGvodvHiq17Kwd/s400/yusniers_camera_controller.jpg" width="300" /></a></div>
<div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">
<!--[if gte mso 9]><xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
</o:OfficeDocumentSettings>
</xml><![endif]-->
<!--[if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:TrackMoves/>
<w:TrackFormatting/>
<w:PunctuationKerning/>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:DoNotPromoteQF/>
<w:LidThemeOther>EN-GB</w:LidThemeOther>
<w:LidThemeAsian>JA</w:LidThemeAsian>
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
<w:Compatibility>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:SplitPgBreakAndParaMark/>
<w:EnableOpenTypeKerning/>
<w:DontFlipMirrorIndents/>
<w:OverrideTableStyleHps/>
<w:UseFELayout/>
</w:Compatibility>
<m:mathPr>
<m:mathFont m:val="Cambria Math"/>
<m:brkBin m:val="before"/>
<m:brkBinSub m:val="--"/>
<m:smallFrac m:val="off"/>
<m:dispDef/>
<m:lMargin m:val="0"/>
<m:rMargin m:val="0"/>
<m:defJc m:val="centerGroup"/>
<m:wrapIndent m:val="1440"/>
<m:intLim m:val="subSup"/>
<m:naryLim m:val="undOvr"/>
</m:mathPr></w:WordDocument>
</xml><![endif]--><!--[if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"
DefSemiHidden="true" DefQFormat="false" DefPriority="99"
LatentStyleCount="276">
<w:LsdException Locked="false" Priority="0" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Normal"/>
<w:LsdException Locked="false" Priority="9" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="heading 1"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/>
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/>
<w:LsdException Locked="false" Priority="39" Name="toc 1"/>
<w:LsdException Locked="false" Priority="39" Name="toc 2"/>
<w:LsdException Locked="false" Priority="39" Name="toc 3"/>
<w:LsdException Locked="false" Priority="39" Name="toc 4"/>
<w:LsdException Locked="false" Priority="39" Name="toc 5"/>
<w:LsdException Locked="false" Priority="39" Name="toc 6"/>
<w:LsdException Locked="false" Priority="39" Name="toc 7"/>
<w:LsdException Locked="false" Priority="39" Name="toc 8"/>
<w:LsdException Locked="false" Priority="39" Name="toc 9"/>
<w:LsdException Locked="false" Priority="0" QFormat="true" Name="caption"/>
<w:LsdException Locked="false" Priority="10" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Title"/>
<w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/>
<w:LsdException Locked="false" Priority="11" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/>
<w:LsdException Locked="false" Priority="22" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Strong"/>
<w:LsdException Locked="false" Priority="20" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/>
<w:LsdException Locked="false" Priority="59" SemiHidden="false"
UnhideWhenUsed="false" Name="Table Grid"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/>
<w:LsdException Locked="false" Priority="1" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 1"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 1"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 1"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/>
<w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/>
<w:LsdException Locked="false" Priority="34" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/>
<w:LsdException Locked="false" Priority="29" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Quote"/>
<w:LsdException Locked="false" Priority="30" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 1"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 1"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 2"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 2"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 2"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 2"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 2"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 3"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 3"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 3"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 3"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 3"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 4"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 4"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 4"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 4"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 4"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 5"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 5"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 5"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 5"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 5"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/>
<w:LsdException Locked="false" Priority="60" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Shading Accent 6"/>
<w:LsdException Locked="false" Priority="61" SemiHidden="false"
UnhideWhenUsed="false" Name="Light List Accent 6"/>
<w:LsdException Locked="false" Priority="62" SemiHidden="false"
UnhideWhenUsed="false" Name="Light Grid Accent 6"/>
<w:LsdException Locked="false" Priority="63" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/>
<w:LsdException Locked="false" Priority="64" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/>
<w:LsdException Locked="false" Priority="65" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/>
<w:LsdException Locked="false" Priority="66" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/>
<w:LsdException Locked="false" Priority="67" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/>
<w:LsdException Locked="false" Priority="68" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/>
<w:LsdException Locked="false" Priority="69" SemiHidden="false"
UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/>
<w:LsdException Locked="false" Priority="70" SemiHidden="false"
UnhideWhenUsed="false" Name="Dark List Accent 6"/>
<w:LsdException Locked="false" Priority="71" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/>
<w:LsdException Locked="false" Priority="72" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful List Accent 6"/>
<w:LsdException Locked="false" Priority="73" SemiHidden="false"
UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/>
<w:LsdException Locked="false" Priority="19" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/>
<w:LsdException Locked="false" Priority="21" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/>
<w:LsdException Locked="false" Priority="31" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/>
<w:LsdException Locked="false" Priority="32" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/>
<w:LsdException Locked="false" Priority="33" SemiHidden="false"
UnhideWhenUsed="false" QFormat="true" Name="Book Title"/>
<w:LsdException Locked="false" Priority="37" Name="Bibliography"/>
<w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/>
</w:LatentStyles>
</xml><![endif]-->
<style>
<!--
/* Font Definitions */
@font-face
{font-family:"MS 明朝";
mso-font-charset:78;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1791491579 18 0 131231 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1107305727 0 0 415 0;}
@font-face
{font-family:Cambria;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:-536870145 1073743103 0 0 415 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin-top:2.0pt;
margin-right:0cm;
margin-bottom:4.0pt;
margin-left:0cm;
text-indent:36.0pt;
line-height:150%;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"MS 明朝";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:Cambria;
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;}
</style>
<![endif]-->
<!--StartFragment-->
</span></span><br />
<div class="MsoNormal" style="text-indent: 0cm;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;"><br /></span></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">
</span></span>
<br />
<div class="MsoNormal" style="text-indent: 0cm;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">The attendees at this first course at Copincha were: Sergio Valdés García, Yusnier Mentado Fernández, Lisa Gómez Blanco, Juan Infante, Alberto José Quesada Madrigal, Javier Quesada Madrigal, Os Leans and Jossue Arteche .</span></span><br />
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;"><br /></span></span>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">In England, when I need components,
an Arduino or a cheap module from China, all of these things are easily
obtainable with a few clicks of a mouse. This is not so easy in Cuba. For most Cubans a £30 Raspberry Pi represents more than a months pay. Even if they want
one, they cannot just order it from Amazon or any of the other sources that we
take for granted. Typically, getting such things into Cuba relies on visitors
to Cuba like us bringing things with us when we visit. Donating things as personal gifts to
Cubans. Visitors to Cuba are advised in the guide books to bring crayons, bars
of soap and Lego as gifts so why not things for makers? <o:p></o:p></span></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">
</span></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8BVsIsItLr_H9EXSKsMu6sGnendurGfHnREgaFALdCL8RUdm_xJ9TuWEoyt_5RyvVgaaKQK9UH-8beC9IzUs-TUmXxuUvIbDYIvJIrl65HLZJ65Xp8pU3h0VtvDtVDjXbtd2abN1u0vHq/s1600/makers_group_photo_web.jpg" 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/AVvXsEj8BVsIsItLr_H9EXSKsMu6sGnendurGfHnREgaFALdCL8RUdm_xJ9TuWEoyt_5RyvVgaaKQK9UH-8beC9IzUs-TUmXxuUvIbDYIvJIrl65HLZJ65Xp8pU3h0VtvDtVDjXbtd2abN1u0vHq/s400/makers_group_photo_web.jpg" width="400" /></a></span></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">
</span></span>
<div class="MsoNormal" style="text-indent: 0cm;">
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;"><br /></span></span></div>
<span style="font-family: "cambria"; font-size: 12.0pt; line-height: 150%;"><span style="font-size: 12pt; line-height: 150%;">
<span style="font-size: 12pt; line-height: 150%;">Perhaps if you are planning a trip to this
beautiful country and will be visiting Havana, you could contact Mauri (maurice.haedo@gmail.com)
and see if he could make use of a few Arduino clones, or eBay specials for "Copincha".
If you do, you will be assured of a warm welcome a great coffee and a glimpse
behind the scenes of this amazing country.</span></span></span></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-56981082880720063422018-03-09T05:30:00.002-08:002018-03-10T02:39:38.410-08:00Review and Test of the MH-Z14A NDIR CO2 Sensor<div dir="ltr" style="text-align: left;" trbidi="on">
The MH-Z14A measures CO2 concentrations using absorption of infra-red light. These devices are available on eBay, Amazon and other places from about $20.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhohLz8pe2_9Sg5BgiLAjYgT8T0dsEhOUP8roGd_7Z1j2n54W6rY-Ke8kdu2eDzjg16NIc4vbDkNb9nw2DxmCGUsqhDtGCMOK8nP52x8DP1fHshE46NugKpUQgbUuQOv7RTWhB-5Th_qwc_/s1600/sensor.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="1275" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhohLz8pe2_9Sg5BgiLAjYgT8T0dsEhOUP8roGd_7Z1j2n54W6rY-Ke8kdu2eDzjg16NIc4vbDkNb9nw2DxmCGUsqhDtGCMOK8nP52x8DP1fHshE46NugKpUQgbUuQOv7RTWhB-5Th_qwc_/s320/sensor.jpg" width="320" /></a></div>
Ignore the capacitor across the power pins - this was a failed attempt by me to improve the reliability of the analog outputs.<br />
<br />
My initial impressions of the module were pretty favourable. It looks pretty space-age with its gold coated chamber and 4 LEDs in the corner of the fabric window that allows the air to enter. These LEDs blink once a second as the readings are taken.<br />
<br />
You can find a datasheet for the module <a href="http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z14a_co2-manual-v1_01.pdf" target="_blank">here</a>.<br />
<br />
The device is available configured for different ranges of CO2 concentration. This module uses the most common range of 0 to 5000ppm.<br />
<br />
<h2 style="text-align: left;">
Interfaces</h2>
The module actually has three interfaces - described in the datasheet.<br />
<br />
<ul style="text-align: left;">
<li>Analog output - proportional to the ppm of CO2 range of 0.4 to 2V for full range.</li>
<li>PWM output - very slow PWM over the period of a second, with the HIGH duration being proportional to the ppm of CO2.</li>
<li>9600 baud 3V/5V TTL UART interface. You send a message saying you want a reading, it responds with a reading.</li>
</ul>
<h2 style="text-align: left;">
Pinout</h2>
<div>
The module has lots of pins on it, most of which are duplicates. I just stuck to the main 0.1inch pitch 2 x 6 connector on the right. Note that the pin numbering on the board reflects the evolution of various connectors added through versions of the boards, and is therefore a bit odd.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhERwjhByk3S4GDzueNsB40h0Lx6j1APOSckSAEIPBD-F25h0W1Voa3HASYI7_1nxhH_6Z507REpSoGcntovGn_Trjz6iZKzn_iXReF5-n-k3KoTPbdJd7ZlFxhgabAYT-MF54Ch8kfssDI/s1600/pinout.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="699" data-original-width="1600" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhERwjhByk3S4GDzueNsB40h0Lx6j1APOSckSAEIPBD-F25h0W1Voa3HASYI7_1nxhH_6Z507REpSoGcntovGn_Trjz6iZKzn_iXReF5-n-k3KoTPbdJd7ZlFxhgabAYT-MF54Ch8kfssDI/s320/pinout.jpg" width="320" /></a></div>
<div>
<br /></div>
<br />
<h2 style="text-align: left;">
First Use</h2>
My first experiment was just to power-up the board (5V to pin1, GND to pin 2) with a multimeter on the analog output (pin 4).<br />
<br />
As soon as it powered up it was obvious that every second or so, the LEDs behind the fabric would light up and the current would surge to around 100mA. This was very short in duration so I expect the average power consumption of this unit is actually pretty low.<br />
<br />
The analog output on pin 4 indicated 0.85V using the datasheet the ppm is calculated as:<br />
<br />
ppm = (Vout - 0.4) * (5000 / 1.6)<br />
<br />
In this case a ppm of 1406. This was wrong, I was in a big room with the door open and not breathing on the sensor, so I would expect a reading of around 400ppm.<br />
<div>
<br /></div>
It looked like the device was not calibrated. Or, calibrated in a somewhat unhealthy factory.<br />
<br />
<h2 style="text-align: left;">
Calibration</h2>
You can calibrate by sending a serial message (see later) or by connecting pin 8 to GND for at least 7 seconds. Using the pin 8 methods, the new voltage reading was a much more believable 0.52V indicating a plausible 375 ppm.<br />
<br />
After huffing on the sensor for a bit, it was easy to get the readings to go up and then work their way back down to ambient levels after about 5 minutes.<br />
<br />
Its looking good!<br />
<h2 style="text-align: left;">
Arduino</h2>
The next step was to hook the device up to an Arduino Uno so that I could compare the reading methods and also do a bit of logging.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQXONwNrMhkr86eczkxfSR6n_3dA0xVDgl_oZh6-8Q7Afh6jiKm-eSGhyphenhyphenPHRXDCKe7zTTNigsOMR0hN0qzCXVfGCp-vGT5wKFUv6XF05FhXL7myP_ReOZr9j2mlwjhEaHVRahSqtPweo90/s1600/arduino.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1489" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQXONwNrMhkr86eczkxfSR6n_3dA0xVDgl_oZh6-8Q7Afh6jiKm-eSGhyphenhyphenPHRXDCKe7zTTNigsOMR0hN0qzCXVfGCp-vGT5wKFUv6XF05FhXL7myP_ReOZr9j2mlwjhEaHVRahSqtPweo90/s320/arduino.jpg" width="297" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1s4L9b3iIjqEz3Pcekytf1hIDIsAjo59fGMEUWqGVkL8e-0Dr9tYS-wTJm9vsUFOV8BUDypKT7bLyZmRFFM84YjUF2lZaO3KeHoFaOATGH4qhG0JbUhKZuhCydqq-S3BUU9_yVvBe2WVx/s1600/connections.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1s4L9b3iIjqEz3Pcekytf1hIDIsAjo59fGMEUWqGVkL8e-0Dr9tYS-wTJm9vsUFOV8BUDypKT7bLyZmRFFM84YjUF2lZaO3KeHoFaOATGH4qhG0JbUhKZuhCydqq-S3BUU9_yVvBe2WVx/s320/connections.jpg" width="320" /></a></div>
<br />
Here is the test script that displays the readings from all three output methods in the Arduino Serial Monitor once every 10 seconds.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">#include <SoftwareSerial.h></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">const int analogPin = A0;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">const int pwmPin = 9;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">const long samplePeriod = 10000L;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">SoftwareSerial sensor(10, 11); // RX, TX</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">const byte requestReading[] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">byte result[9];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">long lastSampleTime = 0;</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">void setup() {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.begin(9600);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sensor.begin(9600);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> pinMode(pwmPin, INPUT_PULLUP);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">void loop() {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long now = millis();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (now > lastSampleTime + samplePeriod) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> lastSampleTime = now;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int ppmV = readPPMV();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int ppmS = readPPMSerial();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int ppmPWM = readPPMPWM();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.print(ppmV); </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.print("\t"); </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.print(ppmPWM); </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.print("\t");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Serial.println(ppmS);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">int readPPMV() {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> float v = analogRead(analogPin) * 5.0 / 1023.0;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int ppm = int((v - 0.4) * 3125.0);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return ppm;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">int readPPMSerial() {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (int i = 0; i < 9; i++) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sensor.write(requestReading[i]); </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> //Serial.println("sent request");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> while (sensor.available() < 9) {}; // wait for response</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (int i = 0; i < 9; i++) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> result[i] = sensor.read(); </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int high = result[2];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int low = result[3];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> //Serial.print(high); Serial.print(" ");Serial.println(low);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return high * 256 + low;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">int readPPMPWM() {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> while (digitalRead(pwmPin) == LOW) {}; // wait for pulse to go high</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long t0 = millis();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> while (digitalRead(pwmPin) == HIGH) {}; // wait for pulse to go low</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long t1 = millis();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> while (digitalRead(pwmPin) == LOW) {}; // wait for pulse to go high again</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long t2 = millis();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long th = t1-t0;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long tl = t2-t1;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> long ppm = 5000L * (th - 2) / (th + tl - 4);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> while (digitalRead(pwmPin) == HIGH) {}; // wait for pulse to go low</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> delay(10); // allow output to settle.</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return int(ppm);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<div>
<br /></div>
<div>
Here is a sample of the results from the Arduino Serial Monitor.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDV9RrJPlDOpwwAY12dEb-dAytHpGDB_PC3lshzcDrHunwyxKulGWI91G0EXr-K0Af4pf_TnTqP9qOQYjqgRF4eE5YO6b6JoFBnoo9UoBNSSZDp6xyn3iDRIXkuJsGX3ZwiCtZEXOBrye/s1600/serial+monitor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1147" data-original-width="1600" height="457" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDV9RrJPlDOpwwAY12dEb-dAytHpGDB_PC3lshzcDrHunwyxKulGWI91G0EXr-K0Af4pf_TnTqP9qOQYjqgRF4eE5YO6b6JoFBnoo9UoBNSSZDp6xyn3iDRIXkuJsGX3ZwiCtZEXOBrye/s640/serial+monitor.png" width="640" /></a></div>
<br />
The first column is the analog reading, the middle column from the PWM interface and the right column from the serial interface.<br />
<br />
The analog readings are all over the place. I don't think this interface is useable.<br />
<br />
<b>UPDATE: The analog output actually appears to be unbuffered. Using my DMM which has a Zin of about 10MΩ the voltage readings were within a couple of % of the serial readings. It was the relatively low Zin of the Arduino ADCs sample and hold messing things up. So, a unity gain op-amp buffer should do the trick.</b><br />
<br />
The PWM interface is pretty consistent with the UART interface, although every so often there will be a bad reading.<br />
<br />
The Serial interface is clearly the winner and if you implement the checksum algorithm specified in the datasheet I would expect 100% reliable readings.<br />
<br />
<h2 style="text-align: left;">
Logging</h2>
To give the module a long term test, I set it running overnight in out bedroom with the following somewhat worrying results.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpeHa-oiAQ5uqchpjj7eItiyMVoitSyHnXcX3dJer4lKeUnD5-6vBMc0d2_EHXDSTc9pc72pCx7DMs_AebjK_knD0jT7JD3M4wz9XTyoPpqcAFb99frPIb0GXAfIwa3HfSnx0v_Ud2IW6P/s1600/logging.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="635" data-original-width="1600" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpeHa-oiAQ5uqchpjj7eItiyMVoitSyHnXcX3dJer4lKeUnD5-6vBMc0d2_EHXDSTc9pc72pCx7DMs_AebjK_knD0jT7JD3M4wz9XTyoPpqcAFb99frPIb0GXAfIwa3HfSnx0v_Ud2IW6P/s640/logging.png" width="640" /></a></div>
<br />
The y-axis is ppm of CO2 and the x-axis time (1 sample per minute).<br />
<br />
I used the PWM measurement method and you can see the frequent misreadings (perhaps 1 in 50). But the trend is pretty good, showing the ppm rising well above 4000ppm, before the bedroom door was opened in the morning and the readings fell back to ambient values of 400ppm or so. Yes, we were all still alive!<br />
<br />
The high overnight readings seem worryingly high for me, but at the moment, I do not have a calibrated sensor to compare with.<br />
<br />
<h2 style="text-align: left;">
Conclusion</h2>
<div>
The sensor module's Serial interface works well and the PWM interface acceptably but the analog interface is only useful if buffered.</div>
<div>
<br /></div>
<div>
A serial interface that it both 5V and 3V compatible makes the module suitable for use with a Raspberry Pi or Arduino without the need for level conversion.</div>
<div>
<br /></div>
<div>
I cannot comment on the accuracy of the sensor without comparison to a trusted device. When I get one, I will come back here for an update.</div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-53804103605304319732017-12-05T08:04:00.002-08:002017-12-05T08:06:14.044-08:00Bluetooth Control of a micro:bit and motor using Bitty<div dir="ltr" style="text-align: left;" trbidi="on">
<a href="http://www.bittysoftware.com/" target="_blank">Bitty</a> is a suite of software that allows you to use your smartphone as an interface to your <a href="http://microbit.org/" target="_blank">micro:bit</a>. The software comes in two parts. A resident program that you download from <a href="https://drive.google.com/uc?id=0B2Ud_NaMFsQSWmJhSDBfZGdwd0k&export=download" target="_blank">here</a> as a HEX file and copy onto your micro:bit and an App that you install on your smartphone (search your app store for Bitty Blue.<br />
<br />
Here's a video of me using Bitty Blue to turn a <a href="https://monkmakes.com/mb_relay" target="_blank">MonkMakes Relay for micro:bit </a>on and off and hence control a motor.<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/4wv2hRCar2g/0.jpg" src="https://www.youtube.com/embed/4wv2hRCar2g?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<br />
The Bitty Blue app has a load of other fun things to do with your micro:bit, so do try them out as well.<br />
<br />
Bitty also have a range of other apps for things such as:<br />
<br />
<ul style="text-align: left;">
<li>Turning your micro:bit into a wireless data logger (for which a <a href="https://monkmakes.com/mb_sensor" target="_blank">Sensor for micro:bit</a> might be handy)</li>
<li>Bluetooth control of a <a href="http://www.kitronik.co.uk/" target="_blank">Kitroniks robot</a>.</li>
<li>Controlling lighting</li>
<li>An audio prank</li>
<li>even a Christmas tree bauble</li>
</ul>
<div>
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com1tag:blogger.com,1999:blog-5416726460697111362.post-17403277395665316392017-10-16T04:15:00.001-07:002017-10-16T04:18:03.401-07:00How to Get Started in Electronics<div dir="ltr" style="text-align: left;" trbidi="on">
I sometimes get asked how to get started in electronics and so at Maker Faire New York 2017 I gave a short talk on this topic. In particular I looked at how hobby electronics now almost inevitably starts with the use of a microcontroller board like the micro:bit or an Arduino or a single board computer like the Raspberry Pi. The question then arises, which do you pick?<br />
<div>
<br />
Here are the slides from this presentation. You can also find a video of it here (although there was a lot of noise).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/nTDn4BU3kXE/0.jpg" src="https://www.youtube.com/embed/nTDn4BU3kXE?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjUYUoOYWgACZW5x4IlODaCW5GfqT-qe6IUIIJQ25HsNEhm1TFnqaH8ysBM4-tqnW9MEXHSqN7WxsbNEWS6Vztq3gH7gfafzEtf2qD7Hg2S_PhARCHyXihXgN28agiPQYkI3CCxFrG0wNv/s1600/Slide01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjUYUoOYWgACZW5x4IlODaCW5GfqT-qe6IUIIJQ25HsNEhm1TFnqaH8ysBM4-tqnW9MEXHSqN7WxsbNEWS6Vztq3gH7gfafzEtf2qD7Hg2S_PhARCHyXihXgN28agiPQYkI3CCxFrG0wNv/s320/Slide01.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcz6I-WevEaeonxiI-uxiNAhsufwdalsHy3TKksc6Os9BoJ9Zt6srcrUqAK7aN2SwUriQMbV5fuaX1LDDTWci02ujTlaYsZkbV3rCxX3ss93iLjPgCiCEWrwr7sX1n8laHtIp-vACWqt5i/s320/Slide02.png" width="320" /><a href="http://simonmonk.org/" target="_blank">http://simonmonk.org</a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeiI9USMtnCl1p6zENpbQvm6X-Np0MEpOE7mntpMR5XIlULqMaUKX1vetV7ufHv7_04hPyiPCFRMTitCZAioPGFp-jlOjhGTdPMmSl6NZushVK6KEA7U6SG8G66dGVWtm4-6Lrsyfubhkb/s1600/Slide03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeiI9USMtnCl1p6zENpbQvm6X-Np0MEpOE7mntpMR5XIlULqMaUKX1vetV7ufHv7_04hPyiPCFRMTitCZAioPGFp-jlOjhGTdPMmSl6NZushVK6KEA7U6SG8G66dGVWtm4-6Lrsyfubhkb/s320/Slide03.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGVmUL5fGCiVNH0MkY8h49sH0kiBKsDJt5RQfufdKO61lRnDXhl1nUn_r-3krBTvNpKVPC0HGgR1K7uqNl-TaOzF2IkAVUFLe3q8NtbxGbdUg17a3bzSWYlujopOvnRgBdDhAGKM5jZGfJ/s1600/Slide04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGVmUL5fGCiVNH0MkY8h49sH0kiBKsDJt5RQfufdKO61lRnDXhl1nUn_r-3krBTvNpKVPC0HGgR1K7uqNl-TaOzF2IkAVUFLe3q8NtbxGbdUg17a3bzSWYlujopOvnRgBdDhAGKM5jZGfJ/s320/Slide04.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjhCP4dXVPViM8Nd2q6aksv1lnYstkMU0ruNBQfy28ztpu7J3-r1v5nbewry5XZOCW_3mFSTDzSZJqUoKciS3r_1svOEm5HTmRqiDus23xQ6oQStdSb2NFJwFPvwMBMHTzMSgHSxTiJS2U/s1600/Slide05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjhCP4dXVPViM8Nd2q6aksv1lnYstkMU0ruNBQfy28ztpu7J3-r1v5nbewry5XZOCW_3mFSTDzSZJqUoKciS3r_1svOEm5HTmRqiDus23xQ6oQStdSb2NFJwFPvwMBMHTzMSgHSxTiJS2U/s320/Slide05.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjchqfGovt4fYBQ_3NHjzvs16JmVDSvfdQdDD2BqvpDL7VFs5zKOLoTt1QhDWVQ6Rvb0bJMvzLYr0U8QAON7fG-bgVKbDOlKHoY90jBBiSN9MYLpvlrkp0_jeF9Y1UR4XcjhXRXdqeSi2Mr/s1600/Slide06.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjchqfGovt4fYBQ_3NHjzvs16JmVDSvfdQdDD2BqvpDL7VFs5zKOLoTt1QhDWVQ6Rvb0bJMvzLYr0U8QAON7fG-bgVKbDOlKHoY90jBBiSN9MYLpvlrkp0_jeF9Y1UR4XcjhXRXdqeSi2Mr/s320/Slide06.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFlURDe6zv2ENVv1Qkv1DlFv4gcJhCJ-LDYI4LeG6o23u_5znAWFdrplXm43BIMgD55mQChNRuKe97T4Mkn7vqSmhoGnyGCWb5Qs7Y90fakVVe46tSi-uG0xp0EJ-1P09RayhImm7KZYm9/s1600/Slide07.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFlURDe6zv2ENVv1Qkv1DlFv4gcJhCJ-LDYI4LeG6o23u_5znAWFdrplXm43BIMgD55mQChNRuKe97T4Mkn7vqSmhoGnyGCWb5Qs7Y90fakVVe46tSi-uG0xp0EJ-1P09RayhImm7KZYm9/s320/Slide07.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRN4YXGMptb3roYzx_avn9O3GHNdwtgkEus4hS-nT5WgC5-RwDQw0L-V0kPi0Kvmw8FLkCSuA5oJ5o5CGMGYpv3gLlhQcO2qiO6rknhJgYcsYwuj3fge3UFOc_Mqad5Oxy9oaxJGuV5pKz/s1600/Slide08.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRN4YXGMptb3roYzx_avn9O3GHNdwtgkEus4hS-nT5WgC5-RwDQw0L-V0kPi0Kvmw8FLkCSuA5oJ5o5CGMGYpv3gLlhQcO2qiO6rknhJgYcsYwuj3fge3UFOc_Mqad5Oxy9oaxJGuV5pKz/s320/Slide08.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD2ZgInid2JELjrHJzNk_AKJmC55fDk5Y8aemDh4MTMpndiRQnUIzuTaeaKpB6yxisBoHC99LnORgDbAXbmnAfeCjyhyphenhyphenbBusIKWI1hi6W2mU2SflP5EnCvQ2FdgPdUDJDFgy7kVT4rVsSH/s1600/Slide09.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD2ZgInid2JELjrHJzNk_AKJmC55fDk5Y8aemDh4MTMpndiRQnUIzuTaeaKpB6yxisBoHC99LnORgDbAXbmnAfeCjyhyphenhyphenbBusIKWI1hi6W2mU2SflP5EnCvQ2FdgPdUDJDFgy7kVT4rVsSH/s320/Slide09.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOMkNzVlQBBWVmUqUqk8PX7a-e6MqPTPWtBuvqvmwvDyTo1-eQv0Kqe_5TiAJryniBKU4MBUkYikf_VvG4w2Te4QLa9TNiFx13LmARAIcsWX8r0AuGF9uS3OGjjidpgVjpj0IHGfoyF1og/s1600/Slide10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOMkNzVlQBBWVmUqUqk8PX7a-e6MqPTPWtBuvqvmwvDyTo1-eQv0Kqe_5TiAJryniBKU4MBUkYikf_VvG4w2Te4QLa9TNiFx13LmARAIcsWX8r0AuGF9uS3OGjjidpgVjpj0IHGfoyF1og/s320/Slide10.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://arduino.cc/" target="_blank"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGADMFk7r_FzhzUyKKpV-6IbV5snugE85qBKOVszxnIEwQ-frLG5uomhSxj9jgljjoIxTqIDfWBMFDg8clo40q1udTLvFNw3vxILmwnpqYZDJCOuZ3_RqjXe0FqI4jAe5YT_UiazwWq5tP/s320/Slide11.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Ras7yCsKaCzSTuLqeO9wsjXIeFf9gfuOfeThwbQa4uzUA40qMJNiXUZ6tkZvOLTx9xTrl3wea5lcsmmwUcieUsae1JWXHir5huTjPjQsrFNEwjx_1cOrCJMy7FJ7xA2_SH5-BoMXX4aW/s1600/Slide12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Ras7yCsKaCzSTuLqeO9wsjXIeFf9gfuOfeThwbQa4uzUA40qMJNiXUZ6tkZvOLTx9xTrl3wea5lcsmmwUcieUsae1JWXHir5huTjPjQsrFNEwjx_1cOrCJMy7FJ7xA2_SH5-BoMXX4aW/s320/Slide12.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg86s2cdIZHy6xhh8kSyRyD4u3PpqMl_Luysw4kkeScWEyOpO8G3_MaUlTD-g0ukEj3r2xOB4HakbTG19QERruoafUrDyFrfPoEgEL2J2iv9-0Mj7zQ41VfrXJ17xwO34ftO_XgxIhyphenhyphenv4u2/s1600/Slide13.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg86s2cdIZHy6xhh8kSyRyD4u3PpqMl_Luysw4kkeScWEyOpO8G3_MaUlTD-g0ukEj3r2xOB4HakbTG19QERruoafUrDyFrfPoEgEL2J2iv9-0Mj7zQ41VfrXJ17xwO34ftO_XgxIhyphenhyphenv4u2/s320/Slide13.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://monkmakes.com/mmd" target="_blank"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-OO31QZrSxLRaZzsiv7ltpSPm6ww_-iZ_YkcQzFhmEqR-fb8vkUSjDWrOBNYsx91iyhRqWuV6x8S7am3k206UHS0U-kZ8fLwZwPBGcwqMU1b8pK9XJgqRlfCfjdfi2KA460JG6xmSk9A_/s320/Slide14.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://raspberrypi.org/" target="_blank"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg25Pbh0kTA-fdv-i8Dg_StgrB4DOAZpi_RAQtahgP7YZc0b-9zoEbmLaOfMhqfxvHZtAMnRVQ3crzF2bLFrCv59YG2Hn8RTqdZAaWI5KTWGBvGdA6qjDF9NYoVjGLno1084zdD2qGpsLng/s320/Slide15.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyQhdj_IWDziM1b3jJURfBODMkMi8QAenCO2RspfVAtR6H_XIBabACzrS33EE_e1qMY5bZJl_Vfifx2wSL5gfyXMmw6LPYUWKaSXxUSB54u4Z-wwydUEC7f4JIbwsBJBlM6FY1AFhCi4SZ/s1600/Slide16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyQhdj_IWDziM1b3jJURfBODMkMi8QAenCO2RspfVAtR6H_XIBabACzrS33EE_e1qMY5bZJl_Vfifx2wSL5gfyXMmw6LPYUWKaSXxUSB54u4Z-wwydUEC7f4JIbwsBJBlM6FY1AFhCi4SZ/s320/Slide16.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVw0YIQK1b14y6cJpQSoWrMXdvuYJH-K-0s48GoCz5ZIN7q0m6XhwvwzCT2MkLNpXRdzloak_yW9xBWbiGHFV73Gz7rQDr7ezMCFPYPZVNVxMDoZmNKgMOorbpB2HF5O6XPeVAM_1bVJkn/s1600/Slide17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVw0YIQK1b14y6cJpQSoWrMXdvuYJH-K-0s48GoCz5ZIN7q0m6XhwvwzCT2MkLNpXRdzloak_yW9xBWbiGHFV73Gz7rQDr7ezMCFPYPZVNVxMDoZmNKgMOorbpB2HF5O6XPeVAM_1bVJkn/s320/Slide17.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.monkmakes.com/rpi_esk/" target="_blank"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj12nCoab1BhrxuRaiBLp8XSyYIaDohb3JUBO-Tne5FjlqtkFgfG8FaboFTvUsZUUdRFywhn0vq8j0W_UuKojK1v15cH2WF7nc-V32OABcTl7IvXX3hi28DM6C9c768Uup7iCQi_UFxag96/s320/Slide18.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4aXPMhINiqFB2-dFbg65e0BpPBgp8p80rj7ZLK8DhoIjrKMMHCFOIWSvFCN_RdNQTMhILJY_ywQQU6BnHW9vwCye8YxQDtbDFGOYF3C8fE1UvcY5dNkytLSdLYAZHdaCCGK_3UKUB0gPl/s1600/Slide19.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4aXPMhINiqFB2-dFbg65e0BpPBgp8p80rj7ZLK8DhoIjrKMMHCFOIWSvFCN_RdNQTMhILJY_ywQQU6BnHW9vwCye8YxQDtbDFGOYF3C8fE1UvcY5dNkytLSdLYAZHdaCCGK_3UKUB0gPl/s320/Slide19.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgocOA_v9_CUUtlDuB7TENgdXRogL8GIZJdsp4ubkK1MaIt0ZtKaeVXAQHCCzWt82wuyDyV-9WgOoN3MY-pWVJ2FoMU2PL3QDgjRZJ1yrCyHW8Hm_cVYsJD6Hn_Y39SgaU-uYghlbXLJSVf/s1600/Slide20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="720" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgocOA_v9_CUUtlDuB7TENgdXRogL8GIZJdsp4ubkK1MaIt0ZtKaeVXAQHCCzWt82wuyDyV-9WgOoN3MY-pWVJ2FoMU2PL3QDgjRZJ1yrCyHW8Hm_cVYsJD6Hn_Y39SgaU-uYghlbXLJSVf/s320/Slide20.png" width="320" /></a></div>
<br /></div>
<div>
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-92097894573715409152017-04-01T02:44:00.001-07:002017-04-01T03:16:33.672-07:00Introducing the MonkMakesDuino<div dir="ltr" style="text-align: left;" trbidi="on">
Yet another Arduino clone, but his time a bit different in that is is designed with education and breadboard use as its main goal.<br />
<br />
Its <a href="https://www.kickstarter.com/projects/simonmonk2/monkmakesduino">on KICKSTARTER now</a>, so take a look if you are interested.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9543Tv7NaYwQBj8RtislJmq5uWb9fqQAxy0bNZyM-TR6WBQsPeUIhRGTrA_NVlZ1tjaDPJYOWB96K9YfwZ22EPrbpsWKmwedBqWmWOxUASX9A_oh040IAtCaCcSUcoKDqzV4t1QJdhGpA/s1600/monkmakesduino+anotated.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9543Tv7NaYwQBj8RtislJmq5uWb9fqQAxy0bNZyM-TR6WBQsPeUIhRGTrA_NVlZ1tjaDPJYOWB96K9YfwZ22EPrbpsWKmwedBqWmWOxUASX9A_oh040IAtCaCcSUcoKDqzV4t1QJdhGpA/s640/monkmakesduino+anotated.jpg" width="640" /></a></div>
<div class="separator" style="clear: both;">
The main features are:</div>
<div class="separator" style="clear: both;">
</div>
<ul style="text-align: left;">
<li>Breadboard friendly - clearly labelled pins</li>
<li>Arduino Uno compatible (Board Type: Arduino Uno in the Arduino IDE)</li>
<li>Low-cost simple design</li>
<li>Built in USB interface with high quality drivers available (CP2102)</li>
<li>Polyfuse over-current protection</li>
<li>5V USB powered</li>
<li>Buffered 'L' LED on pin 13</li>
</ul>
<div>
You get the same pins as the Arduino Uno (more or less) but in a single line that fits over one edge of the breadboard, leaving the rest of the breadboard free for your project.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYu48OmV5lKSdO47b_S4W4rX7ma5CnvjSbN5heNCMAFMYLG_s-N-faHBIHyFDzrqKT7yY0zGpIraLTXDVXl2dGfoa5HmJ-HYsmNW5hYyDl22ARVCqk6GHg98NXsbva5lSpIL1MmaUB6GCA/s1600/larson_scanner+web.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="506" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYu48OmV5lKSdO47b_S4W4rX7ma5CnvjSbN5heNCMAFMYLG_s-N-faHBIHyFDzrqKT7yY0zGpIraLTXDVXl2dGfoa5HmJ-HYsmNW5hYyDl22ARVCqk6GHg98NXsbva5lSpIL1MmaUB6GCA/s640/larson_scanner+web.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.kickstarter.com/projects/simonmonk2/monkmakesduino"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2bsUPl1P6g4Z2fL-1549Wx07VgJO3Zto9_gv_ulkK47njebGDI3yhPmmsbGya1Mde6qfamyNfCtZrCOgTX0O_vW2tcUe6Xf3pmsLZE1trY1ENjyDLVIj0v7406ePmolzwJNaOqJQDsfNQ/s640/monkmakesduino.png" width="640" /></a></div>
<br /></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com0tag:blogger.com,1999:blog-5416726460697111362.post-77915200889403175532017-03-24T04:42:00.000-07:002017-03-24T04:42:03.271-07:00Logging Multimeter Readings with a Digitek DT-4000ZC on a Mac<div dir="ltr" style="text-align: left;" trbidi="on">
I bought one of these multimeters a few months ago <a href="http://www.ebay.co.uk/itm/Digitek-DT-4000ZC-DT-4000ZC-Multimeter-/332153377776?hash=item4d55e253f0:g:NzkAAOSwB-1YxqGi" target="_blank">on eBay</a>, to be able to automate the timed taking of readings using a multimeter.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm_a9NjHUgIcb9oe9Kpc9kaMXMeF1gJQfLuHM6aI42AdygzqnZH49CVoJyCtuGfpHh5Tf4qMUhUi7sn4Ln8va1Ln_-VdLBkyUqeFOnwkBlT_R4w5I_9E_Fh10gt28qxnnCidHYNXUNSMLk/s1600/logging_multimeter.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgm_a9NjHUgIcb9oe9Kpc9kaMXMeF1gJQfLuHM6aI42AdygzqnZH49CVoJyCtuGfpHh5Tf4qMUhUi7sn4Ln8va1Ln_-VdLBkyUqeFOnwkBlT_R4w5I_9E_Fh10gt28qxnnCidHYNXUNSMLk/s320/logging_multimeter.jpg" width="279" /></a></div>
<br />
Given the price, I wasn't expecting much, but it works pretty well.<br />
<br />
Being a Mac user, I am used to either using software in a Windows XP virtual machine, or searching out alternative software for a device. I this case, I found that a <a href="https://github.com/Xuth/tp4000_dmm" target="_blank">Python library</a> has already been written to decode the multimeter's strange display-based protocol. The protocol actually transmits the state of each of the segments on the display - an interesting problem to code.<br />
<br />
To get this going, you will need to:<br />
<br />
<br />
<ol style="text-align: left;">
<li>Install Python on my Mac </li>
<li><a href="https://github.com/Xuth/tp4000_dmm/archive/master.zip" target="_blank">Download the TP4000ZC library</a></li>
<li>Unzip it and then in the directory containing the library python files you just downloaded, create a new file called 'dmm.py' and paste the following code into it:</li>
</ol>
<br />
<div>
<span style="font-family: Courier New, Courier, monospace;">import tp4000zc</span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">import time</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">port = '/dev/tty.wch ch341 USB=>RS232 1420'</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">dmm = tp4000zc.Dmm(port)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">last_time = 0</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">period = 1.0</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">try:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> while True:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> val = dmm.read()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> t = time.time()</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if t > last_time + period:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> last_time = t</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> value = val.numericVal</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> print(value) </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">except:</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> dmm.close()</span></div>
<div>
<br /></div>
</div>
<div>
The multimeter is supplied with an RS232 interface, so I bought a cheap USB to RS232 adapter. You may need to install drivers for this, and then you have to work out what the device name is and modify the line of dmm.py that starts 'port =' to match the device name for your USB adapter.</div>
<div>
<br /></div>
<div>
Run the program, and readings will start to appear.</div>
<br />
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">MacBook:tp4000_dmm si$ sudo python dmm.py </span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">Password:</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">-0.0</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">-0.0</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">-0.0</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.086</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.136</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.141</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.146</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.182</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.284</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.235</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.33</span></span></div>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo}
span.s1 {font-variant-ligatures: no-common-ligatures}
</style>
<br />
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;">0.329</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Courier New, Courier, monospace;"><br /></span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Times; font-size: small; font-variant-ligatures: normal;">To draw charts and analyze the data, just select the readings from the terminal and then paste them into a spreadsheet.</span></span></div>
<div class="p1">
<span class="s1"><span style="font-family: Times; font-size: small; font-variant-ligatures: normal;"><br /></span></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1mce3D3yzP_JSV3_va5Kp1suBXHgi7A6NiFe6tdXdp7W61_vTfVaZseunIzRiixfge5vz2pEJof0J0nre9p0EHsUAgrKkGoW_0G4x0HNtW5kFq5At9-hfAhLXhTYHjhnJPzxWNti26SdX/s1600/spreadsheet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="315" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1mce3D3yzP_JSV3_va5Kp1suBXHgi7A6NiFe6tdXdp7W61_vTfVaZseunIzRiixfge5vz2pEJof0J0nre9p0EHsUAgrKkGoW_0G4x0HNtW5kFq5At9-hfAhLXhTYHjhnJPzxWNti26SdX/s400/spreadsheet.png" width="400" /></a></div>
<div class="p1">
<span class="s1"><span style="font-family: Times; font-size: small; font-variant-ligatures: normal;"><br /></span></span></div>
</div>
Simon Monkhttp://www.blogger.com/profile/11397717497833049913noreply@blogger.com1