Qt Quick with PyQt5 on Raspberry Pi

QtLogoThe prime motivation for me to go through Qt licensing documentation and installing Qt Creator IDE was to explore the new UI infrastructure introduced in Qt 5 under the umbrella of “Qt Quick“. As far as I can tell, this is an entirely different system for creating user interface of a Qt application. Built with modern ideas such as OpenGL graphics acceleration for animation effects and UI layout declared with a text-based markup language QML (probably stands for Qt Markup Language.)

Up to this point my experience with building graphics user interface in Qt was with the QWidget-based infrastructure, which has a long lineage in past editions of Qt. Qt Quick is new for Qt5 and seem to share nothing in common with QWidget other than both a part of Qt5. Now that I’ve had a bit of QWidget UI work under my belt I wanted to see what Qt Quick has to offer. And this starts with a smoke test to make sure I could run Qt Quick in the environments I care about: Python and Raspberry Pi.

Step 1: Qt Creator IDE Default Boilerplate.

Once the Qt Creator IDE was up and running, I followed the Qt Quick tutorial to create a bare bones boilerplate Qt Quick application. Even without any changes to the startup boilerplate, it reported error messages complaining of missing modules. Reading the error message, I looked at the output of apt list qml-module-qtquick* and installed the ones that sound right. (From memory:qml-module-qtquick2qml-module-qtquick-controls2, qml-module-qtquick-templates2, and qml-module-qtquick-layouts)

QML CPP

Once the boilerplate successfully launched, I switched languages…

Step 2: PyQt5

The next goal is to get it up and running on Python via PyQt5. The PyQt5 documentation claimed support for QML but the example on the introductory page doesn’t quite line up with the Qt Creator boilerplate code. Looking at the Qt Creator boilerplate main.cpp for reference, I translated the application launch code into main.py. This required sudo apt install python3-pyqt5.qtquick in addition to the python3-pyqt5 I already had. (If there are additional dependencies I forgot about, look for them in the output of apt list python3-pyqt5*)

QML PyQt

Once that was done, the application launched successfully on my Ubuntu desktop machine, albeit with visual appearance very different from the C++ version. That’s good enough for now, so I pushed these changes up to Github and switched platforms…

Step 3: Raspberry Pi (Ubuntu mate)

I pulled the project git repository to my Raspberry Pi running Ubuntu Mate and tried to run the project. After installing the required packages, I got stuck. My QML’s import QtQuick 2.7 failed with error module "QtQuick" version 2.7 is not installed The obvious implication is that the version of QtQuick in qml-module-qtquick2 was too old, but I couldn’t figure out how to verify version number is indeed the problem or if it’s a configuration issue elsewhere in the system.

Searching on the web, I found somebody on stackoverflow.com stuck in the same place. As of this writing, no solution had been posted. I wish I was good enough to figure out what’s going on and contribute intelligently to the discussion!

I don’t have a full grasp of what goes on in the world of repositories ran by various Debian-based distributions, but I could see URLs flying by on-screen and I remembered that Ubuntu Mate pulled from different repositories than Raspbian. I switched to Raspbian to give that a shot…

Step 4: Raspberry Pi (Raspbian Stretch)

After repeating the process on the latest Raspbian, the Qt Quick QML test application launches. Hooray! Whether it was some configuration issue or out of date binaries we don’t know yet for sure, but it does run.

That’s the good news. Now the bad news: it launches with the error:

JIT is disabled for QML. Property bindings and animations will be very slow. Visit https://wiki.qt.io/V4 to learn about possible solutions for your platform.

And indeed, the transition between “First” and “Second” tabs were slow. Looking on the page that it pointed to, it looks like the V4 JavaScript engine used by Qt for QML applications does not have JIT compilation for Raspberry Pi’s ARM chip. That’s a shame.

For now, this excludes Qt Quick as a candidate for writing modern responsive user interfaces for Raspberry Pi applications. If I want to stick with Qt and Python, I’m better off writing Qt interfaces in the old school QWidget style. We’ll keep an eye on this – maybe they’ll add JIT support for Raspberry Pi in the future.


(The source code related to this blog post are publicly available on Github.)

Qt Licensing Means Reading Big Walls of Text

QtLogoFrom a legal perspective, Qt is an interesting beast. There are two sets of licenses for application developers who wish to use Qt: a commercial license, or an open-source license. I’m sure this “dual-license” approach is intended to let people have the best of both worlds. In practice, it means people who try to do their legal due diligence will have to wade through a lot of legal language. It’s a very challenging barrier – most of the Qt Frequently Asked Questions page is devoted to licensing.

And that’s the condensed version. The legal Terms and Conditions section has multiple pages dedicated to different aspects of using Qt. As a non-lawyer, it’s very hard to not let my eyes gloss over the thick language. Even if we just focus on just the open-source side of the licensing, there is an array of licenses to worry about. There are the strong GPL , the more permissive BSD licenses, and the LGPL that attempts to strike a balance between them. I didn’t even know about LGPL until today. All of them are in play for various parts of Qt.

Fortunately, since my work so far is not for profit, and I intend to put everything up in public on Github, most of the terms of the open-source license should be easy to meet. I would definitely need to consult a lawyer before embarking on a commercial project, though.

With this basic due diligence complete, I went looking for the open-source edition of the Qt tools. They don’t exactly make it easy to find on the official Qt downloads page. It takes some persistence to navigate through the menu structures, looking for the de-emphasized texts and links, to find the download areas for the free open-source edition.

Before I found that compiled binaries repository, I found the information to build Qt5 and Qt Creator from source code. It seemed to be confused by the Qt (both 4 and 5) that appeared to already exist on my Ubuntu installation and I never got the home-built Qt5 up and running. After I stumbled across the binaries repository, I decided to come back to building Qt5 from source after I’ve gained a bit more experience with Linux build systems.

First OSH Park Order Arrived

My first KiCad project was sent to OSH Park almost two weeks ago, and my digital design is now back in my hands in physical form. It is really quite exciting to hold in my hands a circuit board I designed. Three copies of it, in fact, as per usual OSH Park practice.

The first order of business is to check for simple mistakes. I pulled out my multimeter to verify that I have good connection between all the VCC pins to the VCC plane, and similarly all the ground pins are connected to the ground plane. Then I brought up my design in KiCad and checked continuity for the pins I designated. I don’t know if I exhaustively checked them all, but a large portion were verified.

Once I’m satisfied my design has been faithfully produced by KiCad, it was time to pull out the soldering iron. I thought I’d do some incremental tests – solder a subset of components to verify the subset of LEDs light up correctly – but I was eager to see it all light up so I went ahead and populated the whole board. The legs of the 2N2222A transistors in their TO-92 package were closer together than I’m used to in my soldering projects, but other than that challenge it was all simple and straightforward soldering.

Populated LED board

And finally, the moment of truth. I was working in Tux-Lab and a bunch of nearby guys gathered around to see me power up the board for the first time.

<drum roll>

It’s alive! The test pattern already programmed into the PIC started cycling through the LED display. This success is a great confidence-builder. I had fully expected to find problems with the board that I would have to fix in KiCad and send back to OSH Park for another set of circuit boards to be produced. The only problem I encountered was the PICkit 3 does not fit nicely alongside the power connector. I could make it work by making them wedge together at an angle. Neither were happy with it but it should be relatively rare to have the programmer attached.

Well, I guess break time from PIC software is over – I no longer have an excuse to play with other projects. The task of writing my I²C driver routine for this display is back on the to-do list.

Vacuum Subsystem Test

Since we just tested the air subsystem and found problems that will probably require buying parts from McMaster-Carr, we decided to perform a vacuum subsystem test with what we already have on hand to see if we need to add anything else to the shopping list. Only some of the fittings and vacuum lines have been replaced, and the vacuum table itself is in pieces, but we can put together enough to test the vacuum pump, the accumulator tank, the solenoid-actuated vacuum valve, and the fittings and lines connecting them.

We were happy to see the system could generate vacuum beyond an indicated 25 inches of mercury. This measurement is taken with a grain of salt coming from the old vacuum gauge that was on the machine. But while the absolute value (“25 inches”) might be suspect, the relative value is still useful information. We shut off the vacuum pump and went to work on other things. After 15 minutes, the vacuum held steady enough that there was no visible movement of the needle.

Vacuum Holding

The next test is the rate at which vacuum is generated. We don’t need it to be super fast, but we don’t want it to be the limiting factor in cycle time. As soon as the softened workpiece is pulled against the mold, the vacuum should start building back up. It can continue doing so as the completed workpiece is removed and the next workpiece is loaded and heated. By the time the next piece is heated, we want to have sufficient vacuum in the system ready to go instead of having to wait.

Using the solenoid, we opened the valve and admit air into the system, dropping the vacuum down to an indicated 5″ Hg. We closed the valve and started writing down the vacuum reading relative to a stopwatch.

Vacuum Recovery

The recovery rate is acceptable. After one minute it was back up to an indicated 23″ and 90 seconds brings us to 25″. It didn’t have much grunt beyond that – it took double the time (an additional 90 seconds or 3 minutes total) to reach 26.5″, where the needle stopped moving.

We expect a new pump to recover vacuum more quickly, and provide a stronger vacuum, than this tired old thing. But this performance indicates the vacuum pump will not be the limiting factor in our cycle time and that’s good enough.

(Cross-posted to the Hackaday.io project page.)

New Compressed Air Fittings and Lines

We’ve just completed the milestone of replacing the compressed air fittings and lines in the thermoforming machine being rebuilt at Tux-Lab. We replaced the fittings because we expect the old air seals within them to have decayed with age. Since we have everything disassembled, replacing them now is relatively easy and reduces many potential points of failure.

New Air Fitting

The same logic also applied to replacing lines carrying compressed air throughout the machine. For extra bonus, the new air lines are blue and the old ones are green, making it instantly visible which pieces have been replaced.

New Air Line

Once the compressed air subsystem was buttoned up, we wanted to do a subsystem test. Since we have yet to wire up the 220V power distribution, we can’t run the built-in air compressor just yet. So we unplugged the output port of the air compressor and plugged that into the shop air.

Loud hissing announced the presence of a leak in the system. We felt all around the newly installed air lines and fittings, but the source of the leak wasn’t any of the new stuff. We eventually located the source of the leak to the compressed air tank that we had not yet touched. Before this test, the quality of the air tank was a question mark. Now that we have finally pulled it out and gave it a good look, we have answer to that question!

Holey Tank

During disassembly we noted there was no air dryer between the compressor and the tank, so moisture would have collected in this tank. There is a fluid drain port (not visible in this picture) but it doesn’t look like it has ever been used. This hole implies the inside of the tank is a rusty mess and a hole patch repair would only be a futile short-term solution. If we want a self-contained machine not dependent on shop air we will need to replace this tank.

After this discovery, we disconnected the air line from the output port of this tank and hooked that up to shop air. It allowed us to test the rest of the machine.

  • The mechanism to move the heater rearward seems OK.
  • The mechanism to move the heater forward has a leak that needs to be investigated.
  • Trying to move the heater forward/back repeatedly showed no problems (aside from the above leak.)
  • The mechanism to move the frame up/down each seems OK individually.
  • Trying to actuate up/down movement rapidly would cause the two sides of the air cylinder to fight each other. We are missing an air relief mechanism somewhere in the system. Either we forgot we removed something during disassembly, or an existing relief mechanism has plugged up.

(Cross-posted to the Hackaday.io project page.)

There’s More To Wire Twisting Than Meets the Eye

For as long as I’ve been playing with electronics, there’s been bundles of wires held together by twisting the individual strands together. It’s so ubiquitous that I had never given it thought. It seems to be perfectly obvious how they are made: lay wires out alongside each other, hold the ends, twist, done. Right?

Today I learned: yes… mostly.

Certainly the simple straightforward way is sufficient for my daily life, because I only ever need short segments to be twisted. Household electric projects using twist nuts only deal with 1-2cm worth of wire. Hobbyist projects can also get away with this kind of thing – sometimes assisted by a cordless screwdriver/drill – because we rarely need more than a few meters of wire. There are pliers designed for twisting, but again they are only for a meter or less of wire.

When the wires are twisted simply, the individual strands also receive a rotational torque tension. Each strand will want to relieve this tension by un-twisting the bundle. For short runs, this tension can be mostly ignored. It is also less of a factor when the individual strands are relatively rigid: they’ll want to hold their shape more than they want to untwist. (Even more if the strands are hammered together.) But for longer twists of flexible cable, it’s easy to see the wire bundle trying to untwist itself.

When the twisted wire bundle needs to be longer – much much longer – this tension will become unacceptable. So wire twisting machines that make long runs of cables (hundreds of feet or longer) have added complexity. For example, the twisted pairs in our CAT-5 networking cable. As the wires are getting twisted together, the individual strands also must rotate with the twisting motion to relieve the tension before being merged into the twisted bundle.

A simpler way to approximate this is to let the individual strands move freely while twisting. The built-up tension at the point of twist will be relieved in the form of the individual strand rotating about. This can seen in video of some wire-twisting machines. (Pay attention to the individual strands rotating in the feed tube.)

A twisted wire bundle built using this technique is less likely to fight to untwist itself. In this picture, I hand twisted about 5cm of wire while letting the individual strands rotate to relieve the torque tension. I then held both ends and twisted another 5cm in the naive method. As soon as I released the stranded end, the second half of the bundle untwisted itself. The first half stayed twisted.

Wire twist test

UPDATE: I didn’t have any luck finding YouTube videos illustrating the twisting that needs to be done for the wiring bundle to stay together. At least, not machines that twist wire. I found one that twists yarn, but illustrates a similar principle.

Raspberry Pi Pin Initial States are a Consideration For Machine Control

As an intermediate step towards controlling the thermoforming machine with the Raspberry Pi, we populated a breadboard with some components we planned to use. A Raspberry Pi could only source a total of 50mA of power across all the IO pins, so we had it switch circuits on/off via opto-isolators that required far less current to activate. We started by using these opto-isolators to control power to LEDs. Just to see how it works and make sure nothing unexpected occurs before we start hooking up bigger things.

This proved to be wise, as it exposed some Raspberry Pi behavior we did not expect. When the Pi was powered-up, some of the LEDs glowed dimly. They’re not full bright, but they’re definitely not dark, either. Once the control program starts up and all pins are initialized to off, they go dark as expected. But there’s something going on between initial power-on and when the control program starts running.

This was important to chase down because we don’t want the machine relay to close when we’re not expecting them to close. Even worse if it occurs while the system is powering up and components are not yet in known good states. Making this an important consideration in designing our system.

A bit of web searching confirmed this startup behavior was noticed and investigated by a lot of people looking at various parts of the system. The answer was most succinctly answered by a post on the Raspberry Pi subsection of StackExchange: In the peripherals manual for the BCM2835 chip at the core of the Raspberry Pi, the power-on initial states are explicitly stated: All IO pins are configured to be input and not output. Furthermore, pins 0-8 are set with pull-up to 3.3V and pins 9-27 are pulled-down to 0V.

Looking back on the breadboard, we could confirm the explanation matches the observed behavior. The dimly lit LEDs were controlled by opto-isolators that were, in turn, connected to Raspberry Pi pins 5 and 6. None of the other isolators were controlled by pins in the 0-8 range. Since opto-isolators required so little current to operate, the weak pull-up on a pin set to input was sufficient to partially activate the circuit.

Once the cause was determined the solution was simple: move all output control out of the 0-8 range of pins. These pins would be fine for input, so the task of reading the position of a limit switch was moved to pin 5.

The resulting breadboard is visible in the attached image, and the code was changed to match the new pin assignments in this commit. After these changes, we observed no partially lit LEDs which also hopefully means no unexpected relay activity when we hook it up to the machine.

IMG_5266

Setting Up Raspberry Pi GPIO Pins For Device Control

A rough draft of the thermoformer touchscreen control panel application, witting in Python with the Qt UI framework, is now up and running. Now it is time to see how it works controlling some physical hardware. We’re going to build up to this in steps on the way towards actually controlling the thermoform machine. The first step is to have the Pi light up some LEDs as commanded by the control panel application.

I had been playing with a Microchip PIC16F18456 earlier, which can drive LEDs effortlessly. Each pin can handle 50mA which is more than enough to drive LEDs as they typically require no more than 20mA each. I had assumed the Pi would be even more capable with its onboard voltage regulators, but I thought it’d be better to check just to be safe. I’m glad I did! It turns out the pins on the Raspberry Pi has significantly lower power capability than the pins on the PIC16F18345.

The consensus on the Raspberry Pi forums says the limit is 16mA per pin, and 50mA total across all pins. A bunch of LEDs would quickly exceed the 50mA total cap. Given this, we’re going to take two baby steps at once.

We’ve known we couldn’t drive the thermoforming machine directly with Pi. And even if we could, a direct connection is not the best idea. The plan had always called for the use of opto-isolators to keep some separation between the delicate low-power circuitry on the Raspberry Pi chip and the high-power components of the machine. I just didn’t expect that bright LEDs to qualify as “high power” in this context. But since they are, we’re going to use opto-isolators to build the LED proof of concept.

The current design for the control has 9 outputs to relays, and 1 input from a limit switch. For the outputs we’re starting with the Vishay 4N32 chip to see how they work. For input, we wanted a chip that works in the reverse direction, and we’re starting with the Toshiba TLP2200. With the help of a Raspberry Pi I/O breakout board we could hook everything up on a breadboard for the first test.

IMG_5266

First Use of Python Threads is Quickly Followed By First Crash… in Qt

QtLogoBased on experience, I fully expected my first venture into Python multi-threading to run into problems. I just didn’t know exactly what that problem would look like. I had hoped that my first Python threading bug would be friendlier to understand and debug, just as the Python programming language has been friendlier for a beginner to write.

Sadly, no such luck. After I started using my GPIO class, with the debounce routine powered by threading.Timer, the crash is a very unfriendly Segmentation Fault. Surprisingly, it’s not the full “Segmentation Fault (core dumped)” so there was no core for me to debug with. No matter, it’s my program and I can relaunch it under gdb and try to dissect each instance of the crash.

The symptoms are consistent with a multi-thread timing issue:

  • It is unpredictable. I could use my program for several minutes without a problem, or the program might die within a few seconds of launch.
  • When something does go wrong, the actual point of failure that crashed in gdb is deep in the bowels of the system far from the actual problem.
    • In one case, a Python thread worker without any of my code on the stack.
    • In another case, internal system corruption error “Error in `python3': corrupted size vs. prev_size
  • The state of the rest of the system is also unpredictable. Using gdb’s “info threads” command I could get an overlook of the rest of the program, and it looks different every time.

I thought my timer-related code was simple: it checks the state of the input pin, and if the pin level has changed (after the debounce wait) also change the appearance of the visual indicator. The visual indication change was done by changing the stylesheet on the QWidget on screen. One of the error messages gave me my first clue that was my bug.

Could not parse stylesheet of object 0x21f6f58

Going back to look at the state of the other threads with this in mind, I saw they all had something in common: the main UI thread at the point of the crash is working on some part of visual rendering.

So we have a candidate explanation: I had been updating the QWidget stylesheet in the timer callback, which executes on a thread that is not the main Qt UI thread. So when this occurs when the UI thread is in the middle or rendering the QWidget, it would see the data structure change out from under it by the timer thread. This is not good and could explain the crash.

To test the hypothesis, I modified my program to perform stylesheet updates from the timer callback thread and do it frequently. Tens of times per second versus once every few seconds in my normal execution. The program now crashes consistently within a few seconds of launch which I saw as good confidence builder for my hypothesis.

The next thing we need is a fix. I need to make sure the stylesheet update occurs on the UI thread, and it seems simplest to post a message to the UI thread event queue. I can accomplish this by emitting a signal from the timer thread and have that go to a slot on the UI thread via a Queued Connection. The slot executes on the UI thread and can safely update the stylesheet there.

After this modification, the test program is now only emitting a signal from the timer callback thread to queue a stylesheet update, instead of performing the actual update itself on the timer thread. And now the test program no longer crashes.

I started debugging this believing I ran into a problem deep in the bowels of Python implementation internals. It turns out my clumsy use of threads had confused Qt.

Lesson learned, moving on to the next lesson…

(The project discussed in this blog post is publicly available on GitHub. The threading fix is in this commit.)

 

Learning Timers: Qt QTimer and Python threading.Timer

QtLogoWhen I interfaced my PyQt application to the Raspberry Pi GPIO pins, I ran into a classic problem: the need to perform input debouncing. The classic solution is to have the software wait a bit before deciding whether the input change is noise to be ignored or not. A simple concept, but “wait a bit” can get complicated in the world of GUI programming. When writing simple programs, we can probably get away with a literal wait by “going to sleep” for a little bit. But we don’t have that luxury in the world of GUI programming – going to sleep would freeze everything in the program. In general, users do not appreciate their UI becoming frozen and unresponsive.

Python LogoThe solution: a timer. In a Windows application, the programmer can use the operating system timer and do their “after waiting a bit” tasks in response to the WM_TIMER message. I went looking for the Qt equivalent and found several timer-related features. QTimer, QBasicTimer, and QObject::startTimer(). Thankfully, the documentation also provided an overview describing how they differ. For debounce purposes, the most fitting mechanism is a single-shot timer.

Unfortunately, when I tried to use it, I received an error message telling me I could only use Qt timer objects from code launched with QThread. Which apparently wasn’t the case with code running under the context of a QWidget within a QApplication.

I had hoped the Qt timers, working off of the QApplication event queue, would stay on the UI thread. But it appears they have to have their own QThread. I could put in more time to figure out how to get Qt timers to work, but I decided to turn to Python library instead. If I have to deal with multi-threading issues anyway, there’s no reason to avoid Python’s Timer object in the threading library.

It does mean I had to review my code to make sure it would be correct even if called from multiple threads. Since the important state are the status of the GPIO pins, they are handled by the pigpio library and the code in my app should be fairly safe. I do set a flag to avoid creating multiple Timer objects in the case of input bounce. If I cared about making sure I only ever create a single Timer, this flag should be protected against cross-thread access. But reviewing the code I decided it was OK if a few Timer ends up being created – the final result of reading the GPIO pin should still be the same even in the case of multiple Timers doing duplicate work.

(The project discussed in this blog post is publicly available on Github.)

Notes on “ZetCode’s PyQt5 Tutorial” From a Windows Developer.

QtLogoOnce I decided to learn how to create a GUI application using the PyQt5 Python binding for the Qt framework, I looked online for some resources to get started. The reference guides for PyQt5 and Qt version 5 itself seems to be fairly robust, but I needed a little push to get over the initial learning curve to understand where to look for what I need.

The Python Foundation’s wiki for PyQt tutorials has a fairly long list. But when I looked, only one explicitly states it is for PyQt5. So off I go to Zetcode’s PyQt5 Tutorial. It was a very bare-bones tutorial that might be a bit too bare for a complete beginner trying to learn GUI programming. But for somebody who already knows the general concepts of a windowing graphics interface system, it is a quick primer to learn the vocabulary.Python Logo

Since I’ve worked with various flavors of Windows frameworks (from raw Win32, to MFC, to WPF) I just needed a tutorial to help me connect concepts in my head to the terminology used in Qt. For example: in Qt, when something happens, a notification called a “signal” occurs. A signal can be connected to a “slot” which can then respond to whatever just happened. Once I learned this, I was able to translate the concepts into my head: a “signal” is an event that could be raised, and a “slot” is an event handler. Once I got this and a few other basic “Rosetta Stone” translations in my head I could switch to the reference documentation to find answers.

One important note: Even though it is labelled as a PyQt5 tutorial, Zetcode’s tutorial is actually pretty much the PyQt4 tutorial updated with the changes to syntax needed for PyQt5. It doesn’t actually cover anything that is new in Qt5. For me this is fine, because the “old way” covered in the tutorial is probably what I’ll end up using when I go even further back in time for the ROS flavor of Qt.

But know there’s no coverage of the Qt5 advancements in declarative interface construction, hardware-accelerated rendering, etc. Anybody who wants to learn the new toys of Qt 5 would have to look elsewhere.

Qt + Python = GUI for Raspberry Pi Project

Since the mission of the Raspberry Pi foundation is to “put the power of digital making into the hands of people all over the world” there is no shortage of options for programming the Pi. We have at our disposal many choices in programming languages, each with multiple application frameworks, and a large community of Raspberry Pi users for support.

QtLogoFeeling overwhelmed with options, I chose the one that best lines up with my long-term goal of getting up and running on ROS. The ROS plug-in architecture for operator GUI is rqt, based on Qt. And like much of ROS, the user has the option of working with rqt in either C++ or Python. Since I had started dabbling with ROS in Python before getting distracted, I thought the combination of Qt and Python would be a good direction to go.Python Logo

The Qt framework itself is aimed at C++ developers, and its documentation is written accordingly. Fortunately there are translation layers (language bindings) for Python. The one that seems to be the most mature is PyQt with a long list of resources, books, and online tutorials.

The next decision to make is which version to start learning. Browsing through the resources, it looks like Qt 4 is the mainstream version and Qt 5 is the new shiny. Since ROS is still in the midst of transitioning from Python 2 to Python 3, I assume rqt would be relatively old school as well. No matter which one I choose, there’ll be differences I have to tackle whenever I get around to diving deep into ROS. On the assumption that the latest and greatest versions are also the most polished (an assumption based on how Python 3 cleaned up a lot of architectural messiness of Python 2) I thought I’d start learning with the latest releases and make adjustments later as I need to.

So: Qt 5 and Python 3 it is, with the help of PyQt5 binding. Which is easily installed on a Raspbian Stretch system by installing the packages “pyqt5-dev” and “pyqt5-dev-tools”.

New Project: Thermoforming Machine Touchscreen Control

I help where I can in the Tux-Lab effort to rebuild the old thermoforming machine. I’ve been doing more learning than helping, though, since others have more experience with industrial machinery than I do. The initial goal is to get things up and running under manual control, and we’ll tackle automation later.

That doesn’t keep us from chatting about ideas for the automation effort, which is roughly divided up into three tiers of complexity.

At the low-end, we can drive it with a PIC micro controller. A modern PIC should be more than capable of duplicating the level of automation that existed in a decades-old machine. It would be the lowest-cost solution, if the cost difference was significant enough to matter.

The mid-tier option is an Arduino. It should be the easiest to get up and running due to the components already integrated on an Arduino board and the large existing library of code we can draw upon.

Both of the above would offer the option of reusing the control panel as-is, which would be important if we wanted to preserve the exterior appearance of the machine. At the moment it is not a goal to do so – we are not a museum and see little value in historical preservation on this machine. Especially since it’s a huge mess of wires in there.

IMG_5242

So, as can be expected of a bunch of tinkerer types, the dreams started getting wilder and wilder. It wasn’t long before we started talking about a touchscreen-controlled thermoforming machine that is network-connected for job monitoring and logging. Which leads us to the high-tier option: a Raspberry Pi with the matching LCD touchscreen.

The team has members with experience in PIC programming, and in Arduino programming, but we’re light on Raspberry Pi programming expertise. Since this is something I wanted to learn to do anyway, I volunteered to investigate.

In the short term we’re still focused on the manual toggle switch operation mode. In the medium term we might still implement Arduino control. And that might be a good enough place to stop, but I wanted to see if we can turn the wild dream into reality.

Tux-Lab Thermoforming Machine Disassembly

One of the projects on the Tux-Lab to-do list is to revive a thermoforming machine. Purchased cheaply in non-working condition, it has potential to enable some very interesting projects. It has been gathering dust while waiting for enough interest from enough people to reach critical mass to start the project. I think we finally reached that point! We pulled it out of the corner it’s been sitting in, and merrily started pulling everything apart.

Disassembled

I thought we would document the original condition as we pulled things apart, but it quickly became apparent there’s no “original condition” to document. The wide range of age and quality of components made it clear it has seen continual modifications in its decades of service. The decision was made to go all the way back to fundamentals.

The bottom cabinet held the air machinery: a vacuum pump and an air compressor, each with an associated accumulator tank. They had all been bypassed with external connectors, which was not a vote of confidence in their functionality. We were hopeful that the previous owner(s) just wanted to reduce noise and vibration by hooking into their shop’s existing compressed air and vacuum lines.

The vacuum pump turned and could pull 26 inches of mercury, which is quite acceptable. The air compressor pushed out 40 psi, which was rather was less so. Fortunately a disassembly and cleanup was enough to help it push 100 psi. The two air tanks are question marks.

There are two air cylinders in this machine: One moves the thermoforming frame up and down, the other  moves the heater front and back. A quick test of both revealed they move and no air leak hissing was audible at either of their end positions.

The thermoforming frame was designed with two electromagnets to hold it closed. We assumed the magnets were broken because somebody installed some Home Depot quality mechanical latches. But we were able to energize the coils and feel it hold. Maybe the failure was in the control circuitry, maybe it doesn’t hold strongly enough for some task. We’ll find out for sure later.

Latch

The brains of the machine are the clearest indication of the age. We see a lot of discrete logic components and no indication of a microcontroller at the heart of it all. The control panel has a button “Automatic” and we wonder what that used to do. For the moment we will not worry about it: the initial milestone is to get it up and running in manual operation mode. If we get around to implementing an automatic cycle, we’ll pull in an Arduino or something modern to orchestrate the various bits and pieces.

Brains

On the assumption that old air hoses and fittings will be leaky, they will be replaced with new parts. The air valves should still be good and will be used until proven otherwise. Same for the big honkin’ contactors (240V, 40A) in the back to control the heater.

Orders have been placed for replacement parts – once they show up we can install them to get a better idea of how everything will (or won’t) work together.

(This project is cross-posted to Hackaday.io)

Placed First OSH Park Order

After several revisions – including several PCB layouts that were restarted from scratch – I’ve learned a lot about using KiCad.  I don’t know for sure it’s all going to work, but I feel confident enough to make the first revision of my board. If it comes back and the board doesn’t work, I’ll have new lessons to learn. Or if it does, I celebrate!

Off to OSH park!

They have a very KiCad-friendly pipeline that accepts the PCB data file directly, no file conversion or data export necessary. I was worried about file format compatibility since I am running the latest nightly build and OSH Park only officially supports the most recent stable build. Some people have reported issues, but in my case it seemed to have gone through successfully.

The OSH Park verification screen is a great confidence builder. They took my file and generated these images for me to look over. This is awesome! I can clearly tell that it is my design and it generally looks fine. The resolution is a little lower than I would have liked. It is starting to be difficult to make out individual traces on my board, it would obviously be impossible to do so on a large complex board. But I assume detailed checks are not the point, we just need to verify we haven’t uploaded the wrong board and that nothing’s fundamentally broken in OSH Park’s interpretation of it.

OSH Park Verify

Upon checkout I was surprised that two Teensy boards were available as add-ons to my purchase. I don’t know why the circuit board fabrication shop is selling their own edition of the Teensy board, but since I had been thinking about buying one to play with anyway, it was an easy impulse buy to add a Teensy LC to the basket.

And now I wait. The board should arrive in two weeks and I won’t know what I need to fix in KiCad until I get the board and put it to (in)action. This puts a hold on the PIC micro controller hardware side of the project, and I can turn my attention to something else for a while.

(The work described in this blog post are publicly available on Github.)

Refining the LTC-4627JR Driver Board

I am lucky to have some local people who have worked with KiCad and were willing to help a beginner. I’ve asked for tips before I started, but much of them didn’t make sense until I had a run with my own project. Now I can go back and ask the questions again, and with some firsthand experience to anchor the concepts, the answers make much more sense.

I learned that there were flaws in my schematic. I had connected my PIC micro controller output pin directly to the base of a 2N2222 transistor. I shouldn’t directly expose the 2N2222 to the full voltage and current from the PIC. It is not an immediately catastrophic condition – I got my bread board prototype up and running without them – but in their absence the transistors end up burning much more power than necessary and likely reduces their lifespan. So the schematic receives five additional resistors, one for each transistor.

I also neglected a pull-up resistor recommended for the Vpp pin in the PICkit 3 manual. Again, my bread board seems to run OK without it, but it’s better to follow spec.

These six additional resistors complicate the PCB layout. Fortunately, I received some useful tips here as well. I chose one design pattern to practice: separate the front and back layers into vertical and horizontal traces. This requires copious use of vias to connect these individual segments into a full connection. I had been concerned that every via is a connection and a potential source of failure, but I’ve been reassured that’s not a concern. When the horizontal/vertical division, wire traces can cross paths in a safe manner because the directions keep those traces isolated.

I also learned the concept of a fill zone, which makes it easier to distribute the voltage input and ground to all the components on the chip. Instead of running individual narrow traces that might not be able to handle the full power, they are distributed across all the spare surface area I can reach. I use my front copper layer to distribute power, and the back copper layer became the ground layer.

The downside is that, by breaking horizontal and vertical onto their individual layers, it because much more difficult to visually follow the logic of a board. A situation not helped by the fill zones, which obscure other layers so I have to look at the front and back separately.

PCB5 F.Cu

PCB5 B.Cu

The upside of this approach is that it makes layout much easier to do. And despite the visual appearance, the net result is actually simpler despite being broken up across the two layers. Before learning these techniques my trace count was in the 180-200 range. Now it sits at 164 and this is after adding six resistors to the circuit complexity.

These are quite satisfying steps forward.

(The work described in this blog post are publicly available on Github.)

A Beginner Learns PCB Routing is Hard

Drawing up the circuit diagram/schematic was a new thing, but I got through it with minimal headaches and was feeling pretty good about using KiCad. After I was done with the first draft, I moved on to route all the connections to be placed on the printed circuit board (PCB). Doing this, I get firsthand experience that wire routing is a hard problem.

The first few connections were easy, but then it got progressively more difficult as I struggled to find a route for the later connections. The center of the board inevitably became a traffic jam and I started having to go around the jam. Every track that go around the outside perimeter of the PCB is a surrender that I couldn’t find a better way.

In addition to the traces going around the outside perimeter, another way to quantify my frustration with my circuit is the number of tracks in the KiCad PCB file. This is a number easily readable in the text format save file.

Fortunately, it doesn’t cost anything to learn by doing, redoing, and repeat.

The first attempt was a hopeless mess and I had to abort before I could connect everything. Here is version 2, where everything is actually connected with almost 200 tracks and multiple traces that go around the perimeter in a last-ditch effort.

LTC-4627JR I2C PCB v2

Version 3 changed the layout of the components in an attempt to make routing simpler. Moved the LEDs to the top, etc. It felt cleaner but is still quite a mess. I managed to avoid long traces that went around the left and right perimeters, but I still needed several at the bottom perimeter. And the track count didn’t improve by much – still just under 200.

PCB Route v3

Version 4 had the same basic layout as version 3 but I’ve learned to recognize a few signs of upcoming problems and could work to avoid them. The result had a further reduction in tracks, almost a 10% cut down to under 180. Plus I needed even fewer perimeter rescue paths.

PCB 4

The English language has the colloquialism “Paint yourself into a corner” and this is a very similar thing – it’s very easy to route yourself into a situation with no way out. I wish I could condense the lessons I learned into a summary here, but so far it’s just a lot of trial-and-error. Try something until I run into an obstacle, then try to figure out how to get out of this mess.

At this point the only words of wisdom I could offer is – dive in and try. It won’t work, but you’ll learn. Try and try again until you get good enough to get to a point where everything is connected, however inelegant it might be, and keep iterating to improve from there.

(The work described in this blog post are publicly available on Github.)

KiCad Circuit Diagram Schematic Editor (Eeschema) Amateur Hour

The KiCad Getting Started guide only covers the basics, but it’s enough to let the user embark on exploratory adventures to learn the rest of the tool piece by piece. I know I don’t have the knowledge and experience to do a good job at circuit design, but I’m a believer that such knowledge and experience is built up by learning from mistakes. So: let’s dive right in and try to implement the circuit board for my LTC-4627JR driver project and see what we learn.

The circuit diagram portion was relatively straightforward. Most of the lessons in the Getting Started guide applies, up to and including how to build a custom component for my schematic because the LTC-4627JR was not in the KiCad standard library. Somebody had built a library of components that included the LTC-4627JR, and made it available on Github. But this is a learning exercise and I wanted to learn how to do it myself.

The PIC16F18345 was not actually in the KiCad library, but a sibling part PIC16F18344 was available with a 20-pin DIP footprint, which is what I want right now. However, the eventual goal is to go to the surface mount version of the part and I hope I’ll be able to find another substitute with the same 20-pin SMD footprint.

There was no specific KiCad part for the 2N2222 transistor, but there are generic NPN transistors and I think that’s good enough. I was puzzled by the large number of options until I figured out they were different combination of a transistor’s pins. The three pins were labelled in order of pin number. So the variant tagged “BEC” has the base on pin 1, emitter on pin 2, and collector on pin 3. The “BCE” variant has the latter two pin swapped, etc. Looking at my 2N2222, I decided to use the EBC variant because that’s the order I see in the Wikipedia article.

The resistors were straightforward, as were the two I/O headers on the board. A four-pin connector for power, ground, and the 2 I²C wires. The five-pin connector is for the PICkit 3 to perform in-circuit programming.

From looking over schematics in the past, I got the distinct feeling of a stylistic convention for laying things out. Much like there are conventions for software source code. But a gut feel is not enough – I needed help from somebody to concretely spell out the rules. A web search for “circuit diagram conventions” pointed me to this article on Electronics StackExchange.

Armed with the list of conventions and a few hours to bump my head in KiCad, I got a passable basic schematic.

LTC-4627 I2C schematic

(The work described in this blog post are publicly available on Github.)

Notes on KiCad “Getting Started” Guide

To get started learning KiCad, I tried the obvious thing first: Go to the KiCad web site, click on “Documentation”, and click on “Getting Started”. This beginner’s tutorial walked me through drawing the circuit diagram schematic and then turning that abstract design into something that can be fabricated on a circuit board.

Because circuit board design is a fairly esoteric field, a tool like KiCad also has lots of terminology that’s a little tough for a beginner to digest. Thankfully the getting started guide helps put a lot of things in the context of the basic design process, so I could see words and phrases used in context and try to derive their meaning that way.

A lot of areas in KiCad were not covered in the tutorial, but that is to be expected. I just wanted the bare bones to start and I can explore other venues later.

The downside of learning a piece of software in active development is that it is still changing, throwing the tutorial out of date. Some menus were moved, though thankfully the keyboard shortcuts seem to have stayed consistent. Some parts of the software hasn’t only been moved, their icons had been changed. The tutorial occasionally gave instruction as “Click on the button with this icon” so when the icon changed, the beginner is lost.

(Workaround: Keep reading the tutorial to get a feel of what the next step is, what menu might pop up, etc. Then mouse-over each of the icons on the page and look for names that sound like they might be related to the activity.)

There were many of those minor annoyances, and there was one major annoyance. The guide had a section on how to generate a Bill of Materials (BOM)  using a plug-in module. The plug-in module was not installed at the location the guide stated. I went hunting on the KiCad Github repository to find the file, and once I downloaded it, it didn’t work with a bunch of error messages I had no hope of understanding.

Fortunately, BOM generation is not yet a priority for my usage. And I got far enough to draw a simple schematic and turn that into a simple circuit board design.

That’s good enough for a start.

KiCAD Tutorial

 

Tutorial circuit board

New Adventure in Circuit Board Design with KiCad and OSH Park

There are several things I can work on for my PIC-controlled LED practice exercise. The software is far from done, with lots of features I still want to implement. But I’m turning my focus to the hardware for the moment. Now that I’ve built a few iterations of my circuit on the prototyping breadboard, I have some confidence it’ll work for whatever software I write. So I’m going to look into translating the simple design into an actual circuit board.

When I started learning electronics many years ago this was a daunting step that I never took. Back then making my own circuit board meant buying sheets of copper-clad circuit boards. I would then need the ability to drill precise holes in this board for the component pins and I would need to etch my circuit into the copper layer. Either via precise mechanical removal or a chemical etching processes. This DIY fabrication was required because it was not economical for commercial circuit board manufacturers to do low-volume production for hobbyists.

Thankfully, the internet has enabled a solution. We now have circuit board fabricators who batch up many little projects from around the world into low volume production runs. The local electronics hobbyists speak well of OSH Park, who bills by the square inch and each order gets three copies of the circuit board. There’s enough demand for these services that OSH Park has competitors, both domestic and overseas, but I’m happy to start with the known quantity that has worked for people I’ve talked to.

The downside for this economical service is time: because of the job batching pipeline, it takes around two weeks from order submission to parts in my hand. Since I have more time than money to devote on these learning projects, I’m happy to accept this trade-off. It also means I should start the first iteration of my circuit board now: once I send the order, I will have two weeks to polish my software. (Or get distracted by other projects.)

kicad_logo_smallWhat I need to do to start this process is to translate my breadboard circuit design into something OSH Park can fabricate. This also used to be a huge barrier: industrial-level circuit board design software carried industrial-level price tags. Fortunately there’s a free open-source option in KiCad, whose development received a significant boost from CERN. It’s still considered beta software in active development but the current builds are good enough for me to get started.

It’s time to learn KiCad!