maker comments edit

For Christmas last year Jenn got me a SainSmart 3018 CNC router and I’ve really been getting into it. It’s a steep learning curve, a bit more than 3D printing, but my 3D printing knowledge has helped a lot in knowing what sort of things I should look for.

I’ve been getting into it enough that I wanted to upgrade the spindle in it, and my parents got me a Makita RT0701C trim router. This is a fairly common upgrade path - replacing the stock spindle with a Makita or DeWalt router - and you’ll see it in larger setups like the Shapeoko XXL.

IMPORTANT UPDATE: After posting this article I found that, while I was successful in getting the router mounted and generally working in 2D carving (like making letters on a sign), when doing 3D carving I lost Z height a lot. After a lot of trial and error I determined that the SainSmart 3018 PRO does not have strong enough stepper motors to drive the weight of the Makita router. Later models like the 3018PROVer do have the strength, which is why you see so many folks successful with this. For me, I ended up reverting my 3018 back to the stock spindle and upgrading to a Sienci LongMill 30 x 30 which is where I’ve got my Makita router now.

There are two challenges to overcome when you upgrade the spindle to a router like this.

First, you have to figure out how to mount the router to the CNC frame. I solved this by creating a 3D printed combination holder and dust shoe, which you can get on Thingiverse.

Second, you have to change how you turn the power on and off when carving. The stock spindle is powered right off the control board. When you send your gcode to the router, one of the codes turns the spindle on, which sends power to the spindle and it gets moving. A larger trim router like this is plugged in separately and instead of the control board turning it on and off, it’s generally accepted that you have to turn the router on manually with its power switch before you start cutting. Since nothing will be attached to the actual control board power, the “turn on the spindle” command will be effectively ignored.

I… don’t like that. I’m fine if I have to adjust the speed manually on the router, but I would really like the control board to turn the router on and off as needed for the cut. Lots of people, myself included, solve this using a relay. This shows you how to wire it up.

DISCLAIMER: You’re going to be working with electricity. Be safe. Make good connections. Don’t get your fingers in there. I’m not responsible for you burning your house down by making bad wire splices or injuring yourself from touching live electrical stuff. Respect the electricity. This isn’t much more difficult than wiring up a new lightswitch at home, but… just be careful.

Parts you’ll need:

  • One extension cord. It doesn’t have to be very long, you’re going to cut it to get the two end plugs. (Amazon)
  • One solid state relay. It should allow an input voltage of 12V DC and an output voltage matching your router (mine is a 120V AC router). I bought a relay that allows 3 - 32V DC input and 24 - 380V AC output so it’ll “just work.” (Amazon)
  • Your original spindle power cable. You’re going to cut it because you want the wires and the plastic connector that attaches to the control board. You could also make a new one, but I don’t anticipate plugging my old spindle in again.
  • Extra wire in case you want the connection between the control board and the relay to be longer.
  • A battery with some leads. The battery should be enough to trigger the relay. I chose a 9V battery which falls in that 3 - 32V DC range. You’ll use this for testing the relay wiring.
  • Something to plug in to test the relay wiring. I used a light bulb.
  • Solder and soldering iron.
  • Electrical tape.
  • Wire cutters.

Relay circuit parts

First thing we’re going to do is just make sure the relay is working. This is also helpful to understand how the control board will be turning the router on and off; and it gets your test set up.

Attach one wire to the positive input terminal of the relay and another wire to the negative terminal. Connect your battery to the wires - positive to positive, negative to negative. You should see the light go on to indicate the relay has been triggered. (If you’re usinga mechanical relay, you should hear a click.) When the control board “starts the spindle” it’s going to send 12V in and trigger the relay just like the battery is doing now.

Triggering the relay

Disconnect the battery. We’re done with this part of the testing.

Cut the extension cord so you can get some wires connected to the plugs. I cut about 12 inches from each end of the cord. That left me with:

  • A male plug with about 12 inches of cord
  • A female plug with about 12 inches of cord
  • A long strand that came from the middle of the cord

You can leave more cord connected to the plugs if you want. Just make sure you leave enough that you can make a good splice and have some slack to plug in. We don’t need that strand from the middle of the cord. You can save it and do something else with it or you can throw it away.

The extension cord will have an outer insulation/wrap and three wires inside it. Each wire also has insulation around it. Likely they’ll be color coded - green is ground, black is “hot” or “active,” and white is neutral. The black and white wires are what effectively makes the circuit powering your router, so we’re going to insert the relay in the middle of one of those to act like a switch. I chose to put the relay in the middle of the white wire.

If you don’t know how to make a good wire splice I would recommend watching this quick YouTube video on how to do a linesman’s splice. You’re working with some real electricity here and a bad splice can cause all sorts of problems like burning your house down.

Splice the two green wires together so the ground is continuous. My router is a two-prong non-grounded plug so it doesn’t use ground, but having this finished is valuable for later, I think. Wrap that splice in electrical tape to make sure it’s insulated from the other wires.

Now splice the two black wires together so the “hot” path is continuous. Again, wrap that in electrical tape so it’s nice and insulated.

Finally, attach one white wire to each of the “output” terminals on the relay. Make sure there’s a good connection and that they’re screwed down nice and tight.

You should end up with something that looks like this:

Wires spliced

Test time! Now it’s time to make sure your wire splices are good, that things are wired up correctly, and so on. This is also where you’ll want to be extra careful because if you didn’t wire stuff up right, it could be bad news.

Plug in your test load (like I used a light bulb) to the female plug. Then plug in the male plug to an electrical outlet (ideally with a surge protector and/or GFCI circuit breaker for your protection). At this point, even plugged in, the test load (light) should be off. Finally… connect the battery to the input terminals of the relay just like we did in the earlier test. The relay should activate and the test load should turn on! If you remove the battery, it should turn back off.

Test your splices

Disconnect the battery and unplug the relay from the wall and disconnect the wires you were using to test with the battery. The last step is to get the power connector from the control board to the relay working.

If you’re going to make a brand new cable that runs from the control board to the relay, now’s the time. I didn’t do that and I’m not walking through that process.

If you are reusing the original spindle power cable like I did… Snip the metal clips off the ends of the red and black wires that used to power your old spindle. Strip a small amount of the ends of the wire and connect red to positive, black to negative on the relay. It’ll end up looking like this:

Connect the control power cable

That’s it. That’s the whole circuit. Plug this into the wall, plug your router into this, connect the control cable to your control board on the router, and then flip the router switch on. If you use a gcode sender to send M3 that will turn the spindle on. You should see the light on the relay turn on and the router itself should turn on. If you use the gcode sender to send M5 that will turn the router back off.

I recommend putting this in a box or covering it. You don’t want the connections on the relay to get accidentally shorted. I made a quick 3D printed box for mine; you can do something similar or figure something else out. It all depends on the size of the relay and cord you bought, so it’s not one-size-fits-all. If you want to buy a box, search for “project boxes.”

All done, here’s what my setup looks like now:

The finished setup

The black box in the middle mounted to the wall contains the relay. It plugs into the power strip along the left. The red and black cables go to the control board. My Makita router plugs into the relay. (I have the cord routed up and hanging so it’s out of the way.)

I hope that helps folks get back some of their control with the upgraded router!

Note: You might be wondering how you can now automated speed control of the spindle, not just on/off. That’s not as straightforward and there are tons of forums involving rewiring routers with variable electronic speed controls (VESC) and all sorts of other cool-but-non-trivial things. I didn’t solve this problem since setting the speed dial before the cut isn’t a huge deal; and I generally don’t change speeds a lot.

csharp, javascript comments edit

I saw a Twitter thread the other day that got me thinking:

One of the responses hit home for me:

Warning: I’m going off on a bit of a tear here, and I color a little outside the lines of the argument. I’m having a tough time trying to convey a lot of frustration I’ve had recently with Go and Spring Boot / Java, and reading about folks loving the removal of boilerplate as a feature is touching on a pain point.

My daily work is C# and TypeScript. However, I sometimes also work in Terraform and the related SDKs, which are all in Go. So… I do have to use Go. Sometimes, but not often. When I do, I, too, find that I need to relearn nearly from the ground up. I also work, very occasionally, with Java, mostly apps based on Spring. Same thing there - I see the stuff, I sorta figure out what I need to, but if I come back to it a month later, I have no idea what’s going on.

I’m trying to figure out why that is. Like, if I have to get into a Python program and figure something out or add to it, I don’t have that feeling of being instantly just “lost.” I totally feel that with Go.

I think this part hints at it: “I … have no tolerance for excessive boilerplate.” I’m curious what, exactly, that means. I can guess, having messed around with Go - the convention-over-configuration for project structure, for example.

This is a lot of what I see Spring Boot in Java trying to address. Removing boilerplate. Convention over configuration. Auto-wireup. Just make it happen - code less, get more done.

But… if you’re removing boilerplate, you have to supplement that with easy to locate, comprehensive documentation that explains how to get things done.

The command go test runs your unit tests. Cool. What are the parameters you can pass to that? Go search on go test parameters. I’ll wait. You know what the first several results are? The test package. Doesn’t tell you anything. OK, cool, here’s a hint - just run go and you can start tracing down the help stack. Eventually you’ll get to go help testflags. Hmmm. Seems like a lot of references to GOMAXPROCS in there. What does that mean? Back to searching…

Here’s another one - I wanted to turn up the log level on a Spring Boot app that was in a Docker container. This seems like it should be easy. There is no reasonable set of search terms that will get you to the point where you just see a clear explanation that setting -Dlogging.level.root=TRACE or setting LOGGING_LEVEL_ROOT in the environment is the thing you want. I’ll save you the trouble, it’s not there. It’s just layers upon layers of abstractions in an effort to remove boilerplate, but you have to know what’s being abstracted in order to understand how to work adequately with the abstraction.

This seems to be a sort of conflicting goal in the tweet - the person doesn’t have a “tolerance for excessive boilerplate” but also doesn’t want “overabstracted APIs.” By definition, I think, removing the boilerplate necessarily implies there’s some abstraction bridging that gap.

Looking at the whole C# 9 feature of “top-level programs” - that is, a program that doesn’t require a Main() method. Seems like removing nice boilerplate, right? Except, read that bit about args - “args is available as a ‘magic’ parameter.’”


I’m not sure writing a class and a method declaration as an explicit entry point for my program was really the stumbling block for getting things done. And what’s the debugging story? When you have to figure out where the “magic parameter” comes from… how do you do that?

I think that’s the crux of my whole issue here. I’m not a fan of just throwing away keystrokes (though you’d be hard pressed to realize that from this rant), but there’s gotta be a balance between “fewer keystrokes,” “ease of use,” and “maintainability.” If I need to spend a year learning everything that sits under Spring Boot so I can understand how to change the log levels in an app, that’s not maintainable. It might save keystrokes, it might be easy to use ‘if you know,’ but… if you don’t?

I wonder if this contributes to the polarization of people working with languages. It becomes harder and harder to be that polyglot programmer because the stack you have to know for each individual language just grows. Eventually it’s not worth trying to span all the languages because you aren’t getting anything done. So you get the C# fans, or the Go fans, or the Python fans, or the JavaScript fans, and they all love their individual languages and ecosystem, but only because they spend all day every day in there. They know the right search terms to plug in, they know the stack and why the boilerplate was removed.When they switch to something else (as it is with me), it’s a “somebody moved my cheese” situation and the tolerance for pain is far lower than the desire to just get back to being productive.

ndepend, net, vs comments edit

I love NDepend and I’ve been using it for a long time. It’s a great way to get a big-picture view of your application code whilst still being able to drill in for good details. However, I have to say, the latest version - v2020.1 - has the coolest dependency graph functionality. It’s a total overhaul of the feature and I think this is going to be my new go-to view in reports.

First, it’s worth checking out the video that walks you through how to use it. The help videos are great and super valuable.

I watched this and had to try it out. I went and grabbed the Orchard Core codebase which is one solution with 156 projects in it, at the time of this writing.

I got the new version of NDepend and installed the VS extension. It’s interesting to note there’s still a VS 2010 version of the extension available. Are you still using VS 2010? Please upgrade. Please. Also stop using IE.

Install NDepend extension for VS

I loaded up the Orchard Core solution, fired up a new NDepend project for it, and ran the analysis. (If you don’t know how to do this, there is so much help on it, just waiting for you.).

After that, I dived right into the new dependency graph. And… wow. Orchard Core is big. Here’s the initial eye chart you get, but don’t be overwhelmed - it’s a high-level view, right, like looking at a map of the world. I didn’t even bother letting you click to zoom in because it’s just too much.

The Orchard Core map of the world, in dependency graph form

I decided to start by looking at things the main OrchardCore.Cms.Web application references, to get a more specific picture of what the app is doing. I went to Solution Explorer and dragged the OrchardCore.Cms.Web project right into the Dependency Graph. This highlighted the project on the graph so I could zoom in.

OrchardCore.Cms.Web dependency graph

Looking at that, I noticed the red double-ended arrows under OrchardCore.DisplayManagement.Liquid. Hmmm. Let’s zoom in and check that out.

OrchardCore.DisplayManagement.Liquid dependency graph

Hmmm. There are three codependencies there, but let’s just pick one to figure out. Seems the OrchardCore.DisplayManagement.Liquid namespace uses stuff from OrchardCore.DisplayManagement.Liquid.Tags, but the Liquid.Tags namespace also uses stuff from the parent Liquid namespace. What exactly is that?

Easy enough to find out. Double-click on that double-arrow or right-click and select “Build a Graph made of Code Elements involved in this dependency.”

Dive into the OrchardCore.DisplayManagement.Liquid codependency graph

Whoa! Another really tall graph. You can see OrchardCore.DisplayManagement.Liquid.LiquidViewTemplate calls a bunch of stuff in the OrchardCore.DisplayManagement.Liquid.Tags namespace… but… what’s that little arrow at the bottom being called by OrchardCore.DisplayManagement.Liquid.Tags.HelperStatement.WriteToAsync?

OrchardCore.DisplayManagement.Liquid codependency graph

That looks like the culprit. Let’s just zoom in.

OrchardCore.DisplayManagement.Liquid.ViewBufferTextWriterContent is the culprit!

Aha! There is one class being referenced from the Liquid.Tags namespace back to the Liquid namespace - OrchardCore.DisplayManagement.Liquid.ViewBufferTextWriterContent. That’s something that may need some refactoring.

All done here? Click the “application map” button to get back to the top level world map view.

The application map button

That’s a really simple example showing how easy it is to start at the world view of things and explore your code. There’s so much more to see, too. You can…

  • Change the clustering and grouping display to get as high or low level as you want - maybe in simpler apps you don’t want to group as much but in more complex apps you want to be more specific about the grouping.
  • Show or hide third-party code - by default it’s hidden, but have you ever wondered how many dependencies you have on something like log4net?
  • Run a code query using CQL, put your cursor over a result, and see the corresponding item(s) highlighted in the dependency graph.

Truly, check out the video, it’s six minutes of your time well spent.

I’m going to go start loading up some source from some other projects (things I maybe can’t provide screen shots of?) and see if there are some easy refactorings I can find to improve them.

azure, git comments edit

I use Azure DevOps wikis a lot and I love me some PlantUML diagrams - they’re far easier to maintain than dragging lines and boxes around.

Unfortunately, Azure DevOps wiki doesn’t support PlantUML. There’s Mermaid.js support but it’s a pretty old version that doesn’t support newer diagram types so it’s very limited. They’re being very slow to update to the latest Mermaid.js version, too, so it kind of leaves you stuck. Finally, it doesn’t seem like there’s any traction on getting PlantUML into Azure DevOps, so… we have to bridge that gap.

I bridged it by creating an automatic image generation script for PlantUML files. If you’re super anxious, here’s the code Otherwise, let explain how it works.

First, I made sure my wiki was published from a Git repository. I need to be able to access the files.

I used a combination of node-plantuml for generating PNG files from PlantUML diagrams along with watch to notify me of filesystem changes.

Once that script is running, I can create a .puml file with my diagram. Let’s call it Simple-Diagram.puml:

Bob->Alice : hello

When I save that file, the script will see the new .puml file and kick off the image generator. It will generate a .png file with the same name as the .puml (so Simple-Diagram.png in this case). As the .puml file changes the generated image will update. If you delete the .puml file, the image will also be removed.

Simple diagram example from PlantUML

Now in your wiki page, you just include the image.

![PlantUML Diagram](Simple-Diagram.png)

The drawback to this approach is that you have to render these on your editing client - it’s not something that happens via a build. I didn’t want a build generating something and committing that to the repo so I don’t mind that too much; you can look at integrating it into a build if you like.

The benefit is that it doesn’t require a PlantUML server, it doesn’t require you run things in a container to get it working… it just works. Now, I think under the covers the node-plantuml module is running a PlantUML .jar file to do the rendering, but I’m fine with that.

The editing experience is pretty decent. Using a Markdown preview extension, you can see the diagram update in real-time.

VS Code and PlantUML

I have an example repo here with everything wired up! It has the watcher script, VS Code integration, the whole thing. You could just take that and add it to any existing repo with an Azure DevOps wiki and you’re off to the races.