 Hello, everyone, I'm Andrey Vlasovsky, I'm from St. Petersburg, Russia, and I'm the lead developer of PyCharm Community Edition at JetBrains. I've also been working on various type hints related stuff in Python, especially on PEP44, so I usually give talks about type hints, study code analysis and stuff like that. But now for something completely different, microcontrollers. Well, a microcontroller is a device that combines a CPU, your memory and your input and output devices in a single device, something like that. It's really tiny, I have a bunch of them over there, I will show you more of them later. And these devices are used everywhere. So basically they are used to control physical equipment, physical devices like proximity sensors, accelerometers, LEDs, servo motors and so on. And there are billions of microcontrollers in the world. It's the most frequently used computing device actually, because for example every cell phone and every PC has dozens of microcontrollers in it. And microcontrollers are also very important for Internet of Things. They are very cheap, this allows us to use them for controlling everything in consumer electronics. But why should you care? Why do I speak about microcontrollers at a Python event? The reason is that you had to program them in C or even in the assembly language, but starting from 2014 you can now use Python to program microcontrollers. Well, sort of Python, it's not exactly 100% compatible with your familiar C Python, but still it's closed and you can only use it on some microcontrollers, but I believe it's already good enough. So how does it look like? Let me give you a quick example of what sort of things you can create with MicroPython. For example, this is a small program that blinks an LED on this particular board and this board is connected via USB only to provide it with power. You can perfectly run it using a battery. So the code should look very familiar, it's just a regular Python with a few imports that are specific to microcontrollers. But other than that, it should be familiar and very readable. Why would you want to use Python instead of C? Well, for obvious reasons. Python is a high-level language and it does lots of stuff for you. For example, it manages your memory, so you now have to allocate and deallocate memory as you do in C, for example. And generally speaking, high-level languages win over time. So for example, in the early 2000s, C started to replace the assembly language on microcontrollers and I think now is the time for Python to replace C there. But the problem is regular Python still doesn't fit. So the CPUs are actually powerful enough for running Python. But microcontrollers usually have only a tiny amount of RAM. A typical amount is something like 100 kilobytes. It's not your usual gigabytes like you have on your laptops. It's not even megabytes like you did on your PC in the 90s. It's really kilobytes, the stuff from the 80s, from the era of ZX Spectrum and stuff like that. So it's a really tiny amount of memory. And C Python requires a hundred to a thousand times more. So enter a micropython. Micropython is basically a Python language implementation, specifically designed for really low memory consumption. So it's highly optimized exactly for this purpose. It's not a fork of C Python. It's a completely different implementation. And it's designed with this idea in mind. For example, micropython can be run on BBC Microbit, this small device manufactured by BBC. It has only 16K of RAM, 16 kilobytes. It's just enough for a few dozen of tweets, more or less. And even though you are able to run your micropython repo, there is a compiler for Python there and so on. So it's very incredible. So I would like to give you an impression of what kind of optimization techniques micropython used to achieve these results. I'm not going to dive too much deep into the details, but I think it's a good idea to have an impression of what kind of optimizations made it possible. The first one is related to memory management. Micropython uses only garbage collection. It doesn't use reference counting, for example, like the regular C Python does alongside with GC. The reason for it is that in micropython they don't want to store ref counting fields with each Python object. And in Python, everything is an object, so you basically have to have these reference counting fields. Instead of that, micropython drops almost all the memory management fields, except for a few bits that are required for garbage collection to mark your objects as traversed. And you might have heard that garbage collection and the only method for managing memory is quite slow, especially when you have lots of RAM. But for micropython and for microcontrollers it's not really an issue because you have so little memory that you can traverse the whole memory in just like a millisecond or so. So it's a perfectly good technique to manage your memory on microcontrollers. The next trick micropython uses to reduce the amount of memory is storing integers in pointers. Well, the idea is that memory is word-addressable, it's not byte-addressable. So you cannot retrieve, for example, the third byte or the second byte. You can only retrieve a word of memory, a four-byte word in a 32-bit architecture. And you basically can retrieve it only if the memory address is divided by four in this architecture. So you get your memory in words. And this means that the two lowest bits in your memory address are not really used for any purposes. You can just put some random stuff in there and it will continue to work. So micropython utilizes these two lowest bits. For example, if these two bits are zeros, then it's a regular pointer to your memory block. But if the lowest bit is one, the rest of the 31 bits are actually the actual value of your integer. So the integer in micropython takes only four bytes of RAM. And how many bytes of RAM does integer take in your CPython? Who knows? 38. Any other ideas? 28. Yeah, for smaller integers it's 28, right? So for just storing the integer one, having 28 bytes of RAM is huge, I think. The next technique is storing your objects in read-only memory. The thing about microcontrollers is that they have a single address space for both your RAM memory and your ROM memory. So you can use the same pointers to point either to RAM or to your flash ROM memory, your persistent storage. So you can put immutable objects, for example, compiled built-in modules like CIS or OS modules to your ROM to free up your RAM. Or for example, strings are also good candidates to put them in ROM. Now let's consider importing the CIS module. How much memory do we need in micropython to import it? Well, let's count. We have to update our globals or locals dictionary with the name CIS and the pointer to the CIS module. Well, the string CIS is stored on ROM, so we need only one pointer to point to it. And another pointer will point to the actual machine code for the CIS module. So we'll need only eight bytes of RAM to import the CIS module, which is pretty impressive. So using these kinds of optimizations, micropython was able to achieve these results and to be able to run on microcontrollers. So what you get from micropython is more or less the same language as Cpython 3.4 with just a few differences. For example, handling complex object class hierarchies is a bit different. Or accessing your introspection techniques could also be a bit different. But other than that, the biggest change is that you don't have the full standard library of Python available on microcontrollers for obvious reasons, because there is just not enough space to do it. So the standard library is reduced just to a few modules. You can pick the right modules for your application and create a custom distribution of micropython, custom build. And these modules are usually reduced to the most important functions in the modules. They are not quite compatible with your regular micro... sorry, Cpython modules. So we've talked about the micropython implementation, but most of us are not really core developers of micropython, right? We are more interested in using micropython to create some sort of Internet of Things applications, for example. So I'm going to speak about seven features of what makes micropython coding different from Cpython. And I think that seven is the right amount for this talk. Starting from the feature number zero, as we count stuff in Python, the development process. It's really different. Well, first thing... first, you have only your own program run on microcontroller, on your microcontroller. So you have no operating system. So you don't have any processes, any threads, and you are really the only program that is being run. And you don't have your usual devices to, for example, enter stuff using keyboard or display stuff. So you connect your device using a serial cable. And the only way to upload some stuff to your device is via this serial USB connection. So the first thing you should do is to flash the actual image, the binary compiled image of micropython to this board. For ESP8266, for this little board, for example, you can download it directly from the micropython website and upload it using a package called ESP2 with a bunch of different options for that. Then you'll get your interactive REPL session available. Again, we have this serial connection. You'll get the user stuff, your compiler, your exact function. And micropython, for example, will emulate or actually create a file system for you. Remember, you don't have an operating system. You don't have your file system drivers. There is no file system there. Micropython will create one for you in order to provide you the ability to store stuff using the convenient API of the file system. So this way, you can actually store your own programs. And this is the main way, actually. So for example, in the interactive session, you can open your file and start putting your Python code in there as strings. And then you save this file on your file system and you then can import your modules. And this is the process for putting them onto your disk. There are also command line tools to automate that. But since I'm the lead developer of PyCharm Community Edition, I thought that it could be a good idea to create a micropython plugin for PyCharm. So for example, this plugin provides you with the ability to just click on a file and upload it to micropython to execute it there. But it also provides some static code analysis capabilities. For example, it will provide you with code completion for micropython modules and it will provide you with type checking and other code inspections that will ensure that your code looks correct. And even more, I have provided documentation for built-in functions and for functions from some micropython modules. The way I did it is by using Python type-hinting steps. So there are some step files where I actually recreated the APIs of these modules using the Python type-hinting syntax. And there isn't, there is no documentation for the micropython modules on the ESP devices or on other micropython devices. Is that because doc strings just consume memory and don't do anything else. And they don't put it there. But here in this plugin, using type-hinting steps, you are able to look at your documentation while you are developing your code. But that's enough about self-promotion. Let's continue with micropython. Next, the types of devices. Well, there are some types of devices you might want to consider. For example, people often create sensors with their micropython devices. Like temperature sensors or accelerometers or stuff like that. And the typical program structure for this kind of device looks like that. You have your vial true loop because, again, you are the only program that is run on your device. So you have to run it forever. And then you basically take a measurement from your sensor. You store this data somewhere on your own memory. Or you can, for example, send it via Wi-Fi if you are an IoT device. And then you go to sleep until the next, it's time to read the next portion of data. Another type of device you might want to consider is controllers. Controllers actually control physical equipment, physical hardware like LEDs like motors or switches and so on. The program structure looks similar to sensors, but when you get some data from your user, like when the user presses some button, you actually have to drive your device. You have to enable it, you have to power it on or send you some commands to act for this device to react upon it. So the program structure looks like that. But there is an important kind of controllers called negative feedback loop controllers or just basically robots. These devices maintain some constant condition. They live in some environment. For example, a thermostat is a good example of a robot or, for example, a drone. The thermostat keeps the amount of the temperature constant. So basically you have to read your actual temperature compared to your desired temperature. And if there is any difference, you should act upon this difference to compensate for that. And the same stuff applies to drones or, for example, for automotive electronics, for example, like anti-locking braking systems. They are all run on microcontrollers. Next thing is electronics. Well, it's hard to talk about microcontrollers and not to mention electronics at least once. Well, likely for us, only a few basic concepts of electronics are required. So basically, in order to start working with MicroPython, you only need your school level knowledge of physics or electronics. You have to know what the voltage is, what the electric current is. You have to know the ohms law, obviously. And just using this information, you will be able to create small projects like, for example, a process with LEDs. The only extra thing you have to know is that LEDs have polarities, so you have to respect that. And they are sensitive to high levels of voltages and currents. So you have to calculate the amount of resistance you have to add to your electronic components in order to make this thing work and not to burn. While you are playing around with microcontrollers, you will encounter that there are recurring patterns of electronics that you will be using with your devices. For example, polar resistors, batteries, capacitors and so on. And there are good tutorials on these topics that are very easy to read and so on using this URL. This is a great resource to learn about basic stuff in electronics. Next up, memory usage. Well, I talked a lot about how it was important for MicroPython itself to keep the memory footprint low. Well, you have to help it in order to not use too much memory in your own code. And from the practical point of view, this basically means procedural programming. So forget about your object-oriented class hierarchies with complex inheritance patterns. And forget about your functional programming, your pure function that transform immutable data. You have to stick with basic stuff like you do in C with buffers that you reuse in order to not allocate new memory and stuff like that. Unfortunately, that is the case, but I see it as a challenge because it's interesting how this kind of programming can be really used in your Python code. Next thing is device drivers. When you think about your device driver, you usually think about going to the Internet to download a driver for your printer. It's some magical software that makes things work, but in this world of microcontrollers, you can write drivers in Python. Basically, drivers are just libraries for working with your devices. For example, for this device, it's a temperature and humidity sensor. You can create your own driver. Well, you have to know something about it, like read the spec about this device. It has some pins. It uses some wire protocol called I2C to communicate with you and to transmit this data. But more or less, this is the complete source code of this device driver in Python. Basically, you can see some concepts I have already talked about, like only occasional use of object-oriented programming just to put your function and your data structures together. But other than that, it's procedural code. You have your byte array as a buffer that you reuse over and over and you read stuff into this buffer. Then you have just integers operations in order to calculate the actual value of temperature and humidity from this sensor. The implementation of the wire protocol for I2C is provided by your microcontroller, by your micro-Python implementation, so you don't have to worry that much about it. Next up, hardware interrupt. When you talk about hardware, people often talk about things like RQs or interrupt requests. Hardware interrupts are basically callbacks. If you are familiar with the web programming, for example, you know that you can set up a callback when there is an answer to your HTTP request, a response for it. Well, hardware interrupts are like callbacks, but for hardware, for example, when the amount of voltage on a pin of your microcontroller goes from digital 0 to digital 1, you'll get your interrupt request. Your callback will be called. So the code looks like regular Python callbacks. The only thing is that you cannot do that much in these hardware callback functions because you have to be very careful. This interrupt can occur at any time and even during your micro-Python internal working, like in the middle of garbage collection, for example, and you obviously don't want to mess up with garbage collection. So you don't have to allocate any new memory here. Item number six is power management. It's especially important for sensors. You want your sensors to work on battery in order to make them autonomous. And if you take a typical battery and a typical ESP device, it will live only for one day. This is nowhere near enough. And if you are careful with things and you use, for example, machine.isle in order to save some memory when you don't do stuff, then you can get two days. But in order to get more, you have to use a technique called deep sleep. Basically, you power down your CPU completely. Well, first of all, you store some state in order to be able to restore from this power down. But then you power down your CPU so it doesn't consume any energy. And the only thing that keeps running on your board is actually the real-time clock. And you set your alarm clock in order to wake your CPU up after a certain amount of time. And this way, you can make your sensors work for like six months or so. And the item number seven is debugging. Well, debugging is hard. It was always hard, but there is something wrong with my slide, right? And the reason for it is that I promised to talk about seven features. And I started to count my features from zero and the debugging was the seventh feature. So I'm out of my range of my byte array of features. So in MicroPython and in SIMPython, if you access the item that is out of range, you will get a nice index error. The traceback that will help to debug your program and it's very helpful. And it's really different from what you used to have on microcontrollers using C, for example, when your program just starts to behave sporadically when you read some random data from memory and also having an interactive variable helps a lot when you debug your code. But I guess that's pretty much it because you don't have, for example, your step-by-step debugger yet. And just to recap, MicroPython is highly optimized for memory usage and it's more or less compatible with the Python 3.4. And coding for microcontrollers is really fun. It's a bit different, but I can promise you it's a lot of fun with your own hardware devices, your Internet of Things applications, or your combinations of hardware and software to create, for example, games for kids and so on. And I have a few devices like BBC MicroBeat, Pie Board and others. You can stop by our booth at the expert hall right next to this room and I'll show you various live demos so you can get a hands-on experience with these devices. And you can always reach me on Twitter if you have any questions. So thank you. This is a very nice talk. I hope everyone gives a try to MicroPython, maybe some IoT projects at home. So if you have any questions now, you can reach out to the mic on the side. Thank you for the talk. If I understood correctly, when you upload your script, it lives in the memory. So you have to take care to keep all this. Yeah, when MicroPython interprets your Python code, it keeps it in RAM. Yeah, so you should be careful with not writing too large programs. Keep everything to a minimum. Yeah, or you can rewrite stuff in C and put it in ROM, but it's not ideal. Hi, so I was actually working on my MicroPython project. It was supposed to be like a music controller and why it's important because it has both input and display. And I noticed because I got schooled in assembly 10 years ago and so on, and I basically done everything, like main loop was gnoping, and everything was basically interrupts. And my question is basically with Python now, because we can't really go that much into objective-like-style programming. How do you actually manage all this state when you... I know you have multiple buttons. They all can interrupt each other's work, but you can only... On your display have one thing to read on. How do you manage the state with having so many interrupts to work in the same space in the same device, like if you're not only one at the time? Yeah, well, I guess there are many techniques. The thing I used personally is that I had a global object and stored states in their fields, more or less, stuff like that. So I don't know of any advanced techniques for managing this problem, unfortunately. Do you do debugging related with deep sleeping as it could be a low-powered device and could lose its communications? I guess there is no simple answer to this question. If your battery dies, then you cannot debug it. And if your device is currently in deep sleep, you have to provide a hardware signal to wake it up. So debugging could be complicated for these applications. Can you test for the code outside the controls? You can run your MicroPython interpreter on your laptop. There won't be any hardware-specific modules for that, but if you mock them, then you can test your core logic, but not the communications. You have to mock them. You mean CPU-wise or memory-wise? Yeah, you use it. I saw these benchmarks on the Internet. I don't remember the site for it, but yeah, there were benchmarks, and I know that some people even use MicroPython on their laptops just to consume less memory and to write faster code. But of course, this approach is limited to certain applications. And then do you know of any that uses MicroPython already? Automotive? Nothing comes to my mind, unfortunately. In European space engines? Yes, they are right. Very silly, but where did you find these at $1? I have a bunch of those, but I bought them anywhere between $4 to $12. Well, if you buy devices in small amounts, then they cost more, but you can order a huge pile of devices and then you'll get discounts. I mean, if you create consumer devices, you create to sell them. And you can buy them in bulk in order to reduce the cost divided by unit. Before the talk, I just want to take this opportunity to tell people that there is an open space today at 4. Oh, great. About MicroPython and electronics in general. So if you are interested in that, you can... Oh, great, great. So, thank you again very much. Thank you.