LIN Bus The Little Sibling Of CAN Bus

Today I learned about existence of Local Interconnect Network or LIN bus. It is a set of specifications defining a network communication system describing everything from raw voltage levels up to logical communication data protocol. A LIN network has up to sixteen devices: one controller and up to fifteen peripherals, and they communicate via asynchronous serial over a shared wire. At a high level, there’s a lot of resemblance to how serial bus servos work, but LIN came from the automotive field.

As car components got more sophisticated, basic on/off or analog voltage was no longer enough to convey status. They needed an actual data network protocol, and the industry has settled on CAN bus. While capable and robust, CAN bus is overkill for basic functions. LIN bus is a simpler protocol that trades capability for less expensive implementation hardware. A focus on simplicity meant the LIN steering group decided their job here was done and is now a mature standard also known as ISO 17987.

Based on my limited reading, I understand the division of labor for an illustrative modern car driver’s door would be something like this:

  • A host controller connected to the car’s CAN bus communicating with the rest of the car, and connected to other devices inside the door via LIN bus.
  • A microcontroller monitors all the power window switches and report their status to the door host via LIN.
  • A microcontroller manages the power window motor based on commands received from door host via LIN.
  • Repeat for power door locks, and power mirrors.
  • Other sensor inputs like whether door latch is closed.
  • Other control outputs like illuminating puddle lights.

Given the close proximity of these devices to each other inside the door, full signal integrity robustness of CAN bus was not strictly necessary. LIN bus modularity means fewer wires. For example, wires that would otherwise be necessary if the host controller had to monitor each power window switch individually could now be replaced by a single LIN data wire. It also simplifies adding/removing functionality for higher/lower trim levels in a product line, and reduce cost of adapting to regional differences like left- or right-hand drive.

That’s all great for automobile manufacturers. But since LIN bus is simpler than CAN bus, it also lowers the barrier to repurposing automotive components for hobbyist projects. A quick look on Arduino forums found several threads discussion LIN bus devices, and there exists affordable breakout boards (*) to interface with microcontrollers. This could be an entryway into a lot of fun.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Window Shopping Hugging Face LeRobot

Recently there have been a lot of excitement around several fields of machine learning that broke out of their research paper phase. Meaning they got good enough for everyday people to see what they could do without having to chew through dense research lingo. Most of the hype centered around large language models powering ChatGPT and friends. Generative systems have also come of age. I played around with image generators briefly, but there are also audio and video generators out there.

None of those systems are specifically applicable to a rover brain, so while technically interesting I didn’t see anything I wanted to pursue yet. I knew it was a matter of time, though, for those technologies to pioneer enough infrastructure leading to something that would produce rover-applicable machine learning systems. This might have just happened, with the launch of LeRobot by Hugging Face.

According to Wikipedia, Hugging Face company has a few related divisions. One of them is Hugging Face Hub, a repository of machine learning models and datasets. Sort of like how GitHub is a repository of source code, but at a higher conceptual level and focused on machine learning. The index of models on Hugging Face Hub are tagged by topic. If I click on any of the “Natural Language Processing” tags today, they return tens of thousands of models. But if I click on “Robotics”, there are only 27 models. LeRobot is an effort by Hugging Face to jumpstart this field and I’ll be watching to see if it takes off or fizzles out.

Rerun.io

Regardless of LeRobot’s success or failure, a quick skim through its documentation taught me a lot and I didn’t even follow all its links to other projects. Out of those I looked at, the most promising gem is data visualization tool Rerun.io. Skimming through its documentation and examples, Rerun sounded like something right out of my dreams: a time-based data visualization tool not just on 2D graphs like Grafana, but also visualize data in 3D space. From simple spinning LIDAR to depth cameras, Rerun claims to put all data into a single time-indexed visualization. I will definitely take a closer look in the near future.

Mama And Baby Bird

A tree in my yard has grown tall enough to approach some overhead wires, so I started trimming it back. A few weeks ago I climbed my ladder and a bird I hadn’t noticed took off. The takeoff point was less than a meter from my face so it was startling. I thought “oh, a bird, OK” and went about my business. It didn’t occur to me to think about the fact local birds usually keep much greater distance.

The next day I climbed the ladder to continue trimming, and was startled again by a nearby bird. Once may have been a random bird that happened to perch on a tree, twice in the same place is not a coincidence. I looked closer and finally noticed a nest with an egg within. Oh no, I had interrupted a very important project!

Mama bird had stayed with her well-camouflaged nest as long as she could, but when I got within arm’s reach it was too much for her. That’s why she took off so close to my face. Sadly, my trimming meant her nest wasn’t as well camouflaged as it used to be. I couldn’t exactly glue those branches back on, but I could pause my trimming until she finishes her project.

I’ve read that some prospective mother birds would abandon a nest if it proved too dangerous, and I was worried it might happen here. Next day I was happy to see she had returned, now that I know where to look and know to keep my distance. I pulled out my big zoom lens and took this picture from 5-6 meters away.

Over the following weeks I checked in on mama bird daily. She was not happy with my tree trimming and erected additional camouflage to mitigate my damage. That made it more difficult to see her but hopefully provided some protection against predators. I hadn’t trimmed the tallest branches yet so she still had decent overhead coverage against other birds, but I was worried about cats in the neighborhood who could now better see the nest from ground level.

Due to mama bird’s new additions and the fact I kept my distance, it was hard to know if her project was progressing. Her perch position seem to change as time went on, but I couldn’t see anything definitive. Besides, if that egg had hatched, it would make sense for her to sit shielding her baby from the exposed side of the nest.

But eventually I saw baby bird sitting on the “dangerous” side of the house, prompting me to pull out my camera equipment again for this family photo. Less than a week after this picture, my daily check of the nest found it empty. It remained empty every day for a week. I hope the family voluntarily moved on to a safer home, but I will never know for sure. Either way, they’re gone now so I resumed trimming my tree.


CadQuery Learning Curve Climbing Plan

Reading through CadQuery documentation, I’m getting into topics like software integration. While fascinating and full of possibilities, this is putting the cart before the horse. I don’t know if CadQuery will be useful for my own projects. If I end up hating CadQuery, none of the rest would matter. Here are some foreseeable markers to help measure progress ramping up my CadQuery skills, and I’ll find out how far I get.

North Star

The long term goal is for CadQuery (or whatever I decide to adopt) is to fulfill my wish list for open-source collaborative CAD which includes not just the CAD aspect but also integration into project reference documentation. I want to pick up my neglected micro Sawppy project with CadQuery plus associated tools, then roll what I’ve learned (both in the rover design itself, as well as CAD and documentation systems) to revamp standard size Sawppy into a significantly enhanced version 2.0. Even if everything goes perfectly (which it won’t) I expect to take at least a year for this to unfold.

Starting Small

Since it would be foolhardy to jump into such a big project with a new platform, I will start small and tackle small 3D printing projects. Solve problems that can be solved with only a few pieces or just a single piece, before I increase complexity with multi-piece assemblies.

External Dimensions

My 3D printing objects are rarely standalone, they almost always fit onto something that already exists or tie multiple existing components together. Which means dealing with measurements of those existing objects, and I don’t yet know how well I can handle that with a code CAD platform like CadQuery. This will be interesting to figure out on my own, as CadQuery documentation doesn’t cover this topic.

Documentation Updates

When looking at somebody’s GitHub repository, I appreciate having a picture to help tie the words and code and other pieces together. I do the same for my mature project repositories. I include a screen shot for a web app project, and the same for a reverse-engineered KiCad schematic. The downside is keeping the image in sync with latest changes to the project. Instead of having to remember to go back and take another screen shot, I should be able to script CadQuery to automate image update.

  • Crawl: A Python script I manually run on my own computer to dump out an image file.
  • Walk: Translate that to GitHub Actions to run automatically upon every new commit.
  • Run: Integrate with full-fledged documentation system (sphinx-doc or equivalent.)

I think it’ll take a few months just to cover those beginner goals. If I make it that far (which I failed to do with FreeCAD) then I’ll worry about picking some intermediate level goals.

CadQuery External Integration Potential

I was happy to learn CadQuery selecters weren’t limited to string descriptions, those strings were merely shorthand for a far more powerful (if verbose) Python syntax. That should be fun to experiment with later. Another CadQuery feature on the long term experimentation list is its potential to be integrated into other software workflows. The default GUI CQ-editor is merely one example of what the team hopes will become an ecosystem of embedded CadQuery. We will see if those hopes pan out but I like where their thoughts are going.

The other example listed in CadQuery documentation is cq-directive. This allows CadQuery to work as a component in Sphinx documentation generation engine. I need to examine this in more detail, because cq-directive or another tool like it can help me make progress towards a documentation system that solves the challenges I had on a documentation wish list. Come to think of it, this is actually an area of overlap between that and my wish list for collaborative open-source CAD solutions. In theory CadQuery meets almost everything on that latter document, but I won’t know more until I start working through some projects to get hands-on experience.

I expect that I will find a few features I like, but many other items in my wishlist will be missing. For a commercial package like Onshape that would simply be the end of the discussion. But with an open source CAD solution, technically speaking I could write my own implementation to patch these holes. Whether I find the motivation to learn enough to actually do so is a separate problem.

CadQuery Selector Full Capability Via Code

Since CadQuery designs are described via Python code syntax, it has several code-friendly advantages that I hope will prove useful. But I was wary of CadQuery selector examples like .edges("|Z") to select all edges parallel to the Z axis. This seems useful, but “|Z” means an opaque string as far as Python syntax checking is concerned. Special syntax for strings embedded in source code is nothing new, inline assembly and inline SQL as the top two examples coming to my mind. And as one language hiding inside another, I’ve always encountered problems with them.

So I was happy to learn that such strings are merely a shorthand and not selectors’ true form. Officially they are Python code just like the rest of CadQuery. That “|Z” shorthand translates into a call to cadquery.selectors.ParallelDirSelector() with a vector pointing along the Z axis. That is one of several listed in selector section of the API reference. In addition to selectors getting their own page in CadQuery documentation. The string shorthand is itself a Python selector method StringSyntaxSelector.

Selectors were one of the biggest features that motivated me to ramp up on CadQuery, so learning their implementation as actual methods gave me peace of mind. It means if I run into problems with the special text string, I can always fall back to code. The other advantage is that using long form code syntax selectors open up capabilities not (yet?) available via a shorthand string. Three selectors caught my attention:

  1. NearestPointSelector to select an entity near the given coordinate. Useful for finding that one face or edge at a specific known point.
  2. BoxSelector to select all entities within a box. This should allow me to do things like selecting all edges where two objects met up, so I can perform a chamfer operation to smooth edges transitioning from one object to another.
  3. BaseDirSelector may be part of a solution to build a CadQuery UI. GUI CAD users are accustomed to clicking on an object to select it. This involves performing a 3D ray cast to transform the mouse click coordinate backwards through the 3D camera transform to obtain a vector through 3D space. I think that vector can be passed into this selector to perform hit-testing, but I could be wrong. This is pretty far down the line (if I get to it at all) so there’s little immediate need to figure it out just yet. It’s one of many potential CadQuery extension project ideas.

CadQuery Natural Code CAD Advantages

I found some novel features like “extrude until” while reading through “Examples” section of CadQuery documentation. The final example on that page (as of this writing) was for a cycloidal gear and it reminded me of a big reason why I’m looking into code CAD to begin with: I can do things in code! Cycloidal gear profile can get a bit involved to draw with standard 2D sketching tools, and 2D sketches require work to make them adjustable to suit different parameters. But as a code CAD platform, CadQuery can consume gear profile defined with Python math functions. And since it’s a Python function, it takes very little extra work to have it recompute a different profile based on function parameters.

But while a cycloidal gear looks cool, it’s not what I would want to design and 3D print. Well, I tend to avoid printing gears entirely because 3D printers don’t have the precision necessary for good gears, but when it is unavoidable, I prefer to use standard mechanical engineering involute gears. As they are quite standard, I was confident someone has already written CadQuery code to generate involute gears and I found not one but two examples in the CadQuery contributions repository.

Easy publication of small functional snippets like this is another advantage of code CAD: it fits right into source code control and publishing infrastructure. A bit of Python file is a lot more easily maintained and ensure availability compared to FreeCAD’s approach of publishing an entire workbench called FCGear.

While I love seeing the concept of user-contributed code CAD repository, the actual execution may not be panning out. Code contribution frequency to cadquery-contrib isn’t as high as what I would interpret as a popular and vibrant user community. What’s going on? Maybe this specific repository fell out of favor for some reason with the user community, and they’re sharing via some other mechanism I haven’t discovered. Or maybe nobody is using CadQuery and the project is on a path of a slow decline into irrelevance. I hope it is the former and not the latter, but even then it wouldn’t be the first time I put effort into a platform that faded away. I shouldn’t let that fear discourage me as I climb CadQuery’s learning curve.

CadQuery “Extrude Until” Could Prove Powerful

As I’m slowly chewing through CadQuery examples (with a side of CadQuery error handling) I am mostly learning CadQuery syntax for familiar CAD concepts. But “Extruding until a given face” showed something novel I hadn’t seen before. Instead of extruding a 2D profile out to a specified distance, this option allows specifying an extrusion operation to go until it reaches an existing face. This is especially powerful when that destination face is irregularly shaped.

The example showed this to good effect: a circle is extruded out to a half-torus, then a rectangle is extruded until it reaches that doughnut shape. Without this tool, the rectangle would need to have been extruded then trimmed with a cylinder to fit doughnut curvature. This CadQuery “extrude until” option skips the intermediate cylinder shape and associated trim operation. This allows for simpler CadQuery command list and captures design intent, which I see as a good thing.

I hadn’t noticed any counterparts to this capability during my time with Fusion 360, Onshape, or FreeCAD. If it exists in any of those tools, it would have been hidden away in a menu option I had not explored. Perhaps it’s not a mainstream option because it has some “Here be Dragons” edge cases when the extrusion profile (rectangle in example above) could not be fully projected onto an existing face (half-doughnut.) There is a small Warning text box within CadQuery documentation explaining the result may be unpredictable. What does that mean? I increased the example rectangle size so it is larger than doughnut profile, and it extruded a flat shape out beyond the doughnut. From this experiment I think “unpredictable” only means “your shape will be wrong” and not “crash CadQuery and lose all of your recent unsaved changes”.

So it could cause problems in parametric designs if certain values go beyond others. Another downside of using a novel capability absent from other CAD packages is added work if I want to translate it to another CAD package. I rarely try to perform a direct translation, though, given it has rarely worked out well. When Sawppy project moved from Fusion 360 to Onshape, my first export/import effort was a disaster so I redrew from scratch. Given this precedent I think I’ll be fine to use “extrude until” in my CadQuery projects. It’s just something to keep in mind as I explore CadQuery advantages as a code CAD platform.

Exploring CadQuery Errors Via Examples

CadQuery documentation page on assemblies seem to be the last of their conceptual overviews page. After that was a large list of examples, which illustrated many concepts not explicitly covered by earlier overview pages. I expect this page will be a great reference if I continue using CadQuery. To make the most of it, though, I should run through it once now so I have concepts in the back of my head even if I don’t fully understand all the subtleties yet. It also turned out to be an opportunity to see how CadQuery behaves when things don’t go perfectly.

This opportunity came from my decision not to copy/paste each example into CQ-editor. I typed the commands in line by line, pressing F5 after each line to see results of the most recent action. This helps my memory retention and understanding of CadQuery commands. This also means I would occasionally make mistakes as I go.

I’m worried about the fact CadQuery documentation didn’t have a section on how CadQuery handles errors. I’m not talking about raising and catching exceptions kind of error-handling, I’m referring to how it reports errors in user input. FreeCAD set a low bar to clear, as it too often reports only a “Recompute failed!” and left the user up a creek. The good news is that CadQuery seems to offer more feedback, the bad news is the feedback can be quite opaque. Here are two examples:

TypeError: object of type ‘float‘ has no len()

I was mystified when this error came up because I didn’t call len() on anything, but I did type in a pair of coordinates as floating point numbers so I knew at least which line of code to look at. It didn’t take long before I found I had mistakenly typed a period instead of a comma on the second coordinate.

r = r.pushPoints([(0, 0.75),(0.-0.75)])

Great, but the error message was not terribly unhelpful. I’m worried I’ll pull my hair out at future equally unhelpful errors, we’ll just have to see. But I’m optimistic based on my experiment to deliberately make the same error on the first coordinate instead of the second:

r = r.pushPoints([(0. 0.75),(0,-0.75)])

For this line, CadQuery gave me this error:

SyntaxError: invalid syntax. Perhaps you forgot a comma?

This is wonderful! I don’t know why behavior differed between first and second coordinates. (Maybe the negative sign has something to do with it?) But I am very encouraged by the fact CadQuery at least tried to be helpful.

ValueError: No pending wires present

Thanks to CadQuery’s initial overview page, I know what “wires” are in this context. (2D entities with a length but no surface area or volume.) And since I typed in each command on its own separate line, I was able to use CQ-editor’s ability to step through line-by-line to understand this was an error from a call to extrude(). I looked over my commands before calling extrude(), which drew a 2D profile line by line. I eventually found a typo in one of the coordinates, which mean its endpoint didn’t line up with another and left a gap in my 2D profile.

The bad news is this is worse than FreeCAD error message, which at least told me the profile was not closed. The good news is that I can mitigate such errors by using different 2D sketch commands. For example lineTo() will always draw from the previous point to ensure there are no gaps, and close() will draw a line from the previous point to the first point and ensure shape is closed. I hope that will spare me future headaches.

In the meantime, exploring examples introduced me to some novel and potentially powerful tools like “extrude until”.