Gaurav ManekOnline Portfolio and Website.
https://gauravmanek.com
The Pitfalls of Regularization in Off-Policy TD Learning<p>Temporal Difference (TD) learning is ubiquitous in reinforcement learning, where it is often combined with off-policy sampling and function approximation. Unfortunately learning with this combination (known as the deadly triad), exhibits instability and unbounded error. To account for this, modern RL methods often implicitly (or sometimes explicitly) assume that regularization is sufficient to mitigate the problem in practice; indeed, the standard deadly triad examples from the literature can be ``fixed’’ via proper regularization. In this paper, we introduce a series of new counterexamples to show that the instability and unbounded error of TD methods is not solved by regularization. We demonstrate that, in the off-policy setting with linear function approximation, TD methods can fail to learn a non-trivial value function under any amount of regularization; we further show that regularization can induce divergence under common conditions; and we show that one of the most promising methods for mitigating this divergence (emphatic TD algorithms) may themselves diverge under regularization. We also demonstrate such divergence when using neural networks as function approximations. Thus, we argue that the role of regularization in TD methods needs to be reconsidered, given that it is insufficient to prevent divergence and may itself introduce instability. There needs to be much more care, both practically and theoretically, in the application of regularization to RL methods.</p>
<p>On <a href="https://neurips.cc/virtual/2022/poster/55087">NeurIPS</a>, <a href="https://docs.google.com/presentation/d/1fRZKMg3mgksXVmESviGrX5iwEpUsVb6wQS_fQ9VGcuE/">Google Slides</a></p>
Wed, 14 Sep 2022 00:00:00 +0000
https://gauravmanek.com/research/2022/the-pitfalls-of-regularization/
https://gauravmanek.com/research/2022/the-pitfalls-of-regularization/3d Printer Mishaps
<p class="blog-image ">
<a href="wrong_end.jpg"><img src="wrong_end.jpg" alt="" />
</a>
<span></span>
</p>
<p>Anyone who works with 3D printers knows that they fail quite often and sometimes quite spectacularly. This bubble of melted plastic from the wrong end of the hotend was caused by a tiny wisp of plastic from the print skirt detaching from the bed and jamming the hotend fan, which caused the cold side of the hotend to heat up. This not only destroyed the printed parts around the hotend, but also accumulated the fed plastic as a blob on the wrong end. All things considered, this is quite mild compared to the single worst failure of a 3d printer that I have ever owned. 18 hours into a 30 hour print, I came down to see this:</p>
<p class="blog-image ">
<a href="printer_mess.jpg"><img src="printer_mess.jpg" alt="" />
</a>
<span></span>
</p>
<p>I was attempting to print something from a batch of ancient filament I bought in a lot off Facebook Marketplace. Filament that had been left open and exposed for probably a year or so. I got (what I thought was) a fantastic deal on it! 6kg across 9 colors for $50, and most of it printed fine after being dried out in an oven. I didn’t realize that the rolls would be hiding a ticking time-bomb.</p>
<p class="blog-image ">
<a href="hotend_blob.jpg"><img src="hotend_blob.jpg" alt="" />
</a>
<span></span>
</p>
<p>When I removed the print head, I saw the full extent of the damage: a blob of plastic too large to be easily removed. Most extruder blobs can be pulled off with pliers while the hotend is heated, but this was so large that the 40W heater couldn’t melt enough to free itself. I had to use a saw and an angle grinder with a cutting wheel to remove large chunks of plastic from the blob to make the resutant mess manageable. Once I had removed enough of the remaining plastic that subsequent cuts may have damaged the hotend, I suspended the entire assembly in an oven and allowed the plastic to soften and slough off.</p>
<p class="blog-image ">
<a href="melt_in_oven.jpg"><img src="melt_in_oven.jpg" alt="" />
</a>
<span></span>
</p>
<p>Ultimately, some part of the original clog or my subsequent attempt to resolve it damaged the nozzle and hotend throat, and that cheap filament suddenly cost me an additional $100, wiping out any savings. Good filament is worth the money, especially at the $20/kg price point.</p>
Sun, 17 Jul 2022 00:00:00 +0000
https://gauravmanek.com/blog/2022/printer-mishaps/
https://gauravmanek.com/blog/2022/printer-mishaps/The Home Lab II<p>Here’s a new pictue of my basement lab.</p>
<p class="blog-image ">
<a href="full-view.jpg"><img src="full-view.jpg" alt="" />
</a>
<span></span>
</p>
<p>As of taking this picture, the lab has a new tool shelf, a new CNC enclosure with coolant, and three 3d printers: some FlashForge IDEX printer, a Creality CR200, and, of course, the workhorse: a Voron 2.4.</p>
<p class="blog-image ">
<a href="workhorse-voron.jpg"><img src="workhorse-voron.jpg" alt="" />
</a>
<span></span>
</p>
<p>The pegboard is covered in tools. I’m intending to print specialized pegs for my voltmeter, etc. and move some tools to the currently bare left quarter.</p>
<p class="blog-image ">
<a href="pegboard.jpg"><img src="pegboard.jpg" alt="" />
</a>
<span></span>
</p>
Sat, 02 Jul 2022 00:00:00 +0000
https://gauravmanek.com/blog/2022/the-lab-ii/
https://gauravmanek.com/blog/2022/the-lab-ii/DIY Wrench
<p class="blog-image ">
<a href="wrench.jpg"><img src="wrench.jpg" alt="" />
</a>
<span></span>
</p>
<p>I’m writing this in large part to justify the enormous expense of building my own CNC machine. I needed a wrench the day before flying off for a dive trip. The wrench needed to be sufficiently thin to slip between the body of the AI transmitter and the first stage of the regulator, and so I could not run down to Home Depot to buy one. With all other alternatives closed to me, I thought about the problem. Thirty minutes in CAD and CAM and six minutes of making chips, and I had the perfect little wrench for the job.</p>
<p class="blog-image ">
<a href="milling.jpg"><img src="milling.jpg" alt="" />
</a>
<span></span>
</p>
Fri, 10 Jun 2022 00:00:00 +0000
https://gauravmanek.com/blog/2022/diving-wrench/
https://gauravmanek.com/blog/2022/diving-wrench/Toolhead Board Design
<p class="blog-image ">
<a href="board.jpg"><img src="board.jpg" alt="" />
</a>
<span></span>
</p>
<p>I attempted to extend the popular <a href="https://github.com/gauravmm/TurboCAN">TurboCAN</a> toolhead board to support the (then) new <a href="https://vorondesign.com/voron_stealthburner">StealthBurner toolhead</a> for Voron printers. It was ultimately unsuccessful, but an interesting project nonetheless.</p>
<p>The purpose of this project was to modify the original TurboCAN board to support additional GPIO pins, which would be used to control the LEDs. A simple change, but it required a full change in the board layout. I took advantage of this to straighten out traces, fix some minor errata in the previous board, and switch to cheaper components where possible. The updated design would have cost about US$30 each, including the STM32 processor, which alone accounted for a quarter of the total price.</p>
<p class="blog-image ">
<a href="pcb.png"><img src="pcb.png" alt="" />
</a>
<span></span>
</p>
<p>I sent off a batch of five boards to be manufactured, and two to be populated by JLCPCB. About six weeks later, when they arrived, they were defective. Manually testing connectivity nets suggested that the manufacturing was accurate, and the USB connectivity worked when tested. However, I was not able to power these off the 24V inlet, and any attempt to do so released magic smoke from the 5V regulator assembly. Despite further testing (and consulting with some other hobbyists in CMU), I was unable to track this error down. The most interesting test we tried was to cut traces on the board, power it up section-by-section (for a second at a time!), and attempt to bisect the error. Unfortunately, this failed when the regulator caught fire. I still haven’t figured out the underlying issue with the design.</p>
<p>Luckily, Mellow released their <a href="https://www.aliexpress.us/item/3256803862666085.html">FLY-SHT42</a> at around that time, so I just purchased one and used it for my Voron.</p>
Tue, 12 Apr 2022 00:00:00 +0000
https://gauravmanek.com/blog/2022/toolhead-board/
https://gauravmanek.com/blog/2022/toolhead-board/Hough and Cover
<p class="blog-image full-width">
<a href="toy_intro.svg"><img src="toy_intro.svg" alt="" />
</a>
<span></span>
</p>
<p>The 2d-Bin Packing Problem (2d-BPP) is a venerable optimization problem that is very simple to state but difficult to solve. We flesh out our idea in <a href="#TODO: ARXIV LINK">this</a> unpublished paper, but this post will give a brief overview of the most interesting insight in the paper.</p>
<p>Stated simply the 2d-BPP is: given identical rectangular bins of integer size and rectangular objects of (potentially) different integer sizes, the 2D-BPP is to, using as few bins as possible, to assign objects to bins and positions such that no two bins overlap. Figure 1 illustrates a toy example where five objects are correctly packed into a single bin.</p>
<p>2d-BPP is a great way to abstract the problem of packing objects into a container, cutting a sheet of material into rectangular units, laying out the occupancy of a 3d printer bed, or even allocating CPU and memory resources to virtual machines. Simple variants allow objects to be rotated or to be arbitrary polygons. More complex variants include the 2D stock cutting problem, which minimizes the sum of material and cutting costs, motivated by industry needs. Because of the importance of the applications, 2d-BPP has been extensively explored and many approximate and exact solutions have been proposed. The approximate approaches are typically based on heuristics and can be very fast, but they are not guaranteed to find the optimal solution; in contrast, the exact approaches are typically based on Integer Linear Programming (ILP) and are generally limited to small instance sizes.</p>
<p>The current state-of-the-art exact method is based on the <a href="https://pubsonline.informs.org/doi/abs/10.1287/ijoc.2020.1014">Combinatorial Benders Decomposition</a> (CBD). It splits the problem into two parts: assigning objects to bins, and arranging objects within bins. Its speed comes from the way that it quickly discovers which sets objects cannot share a single bin and intelligently generalizing this knowledge to other sets of objects. At each step, it creates and solves sub-problems corresponding to arranging objects within each bin using a very simple method.</p>
<p>Instead, we’ll look at the erstwhile state-of-the-art approach <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7135247/">Positions and Covering</a> (P&C), and show how we can greatly improve it by recognizing that a key step can be rewritten using convolutions. The resultant algorithm is called Hough and Cover (H&C), and it is faster than CBD on a range of standard bin-packing datasets. Let’s begin by understanding the geometry behind P&C.</p>
<h2 id="the-geometry-of-pc">The Geometry of P&C</h2>
<p>P&C is an ILP-based method, meaning we don’t directly solve the problem. Instead, we encode our problem with linear constraints, and then hand it over to a black-box solver. The solver then returns a solution, which we can then decode into a solution to the original problem.</p>
<p><strong>For simplicity, we’ll assume that we have a single bin, and we are looking for any non-overlapping packing.</strong> We are given a bin of finite size \(\text{bin}_h \times \text{bin}_w\) and \(k\) objects to pack into that bin. Each object \(p\) has height \(h_p\) and width \(w_p\). We wish to assign the top-left corner of each object to some position such that no two objects overlap. All ILP-based methods must have some way to express the following constraints:</p>
<ol>
<li>Each object must appear exactly once.</li>
<li>Each object must lie entirely within the bin.</li>
<li>No two objects may overlap.</li>
</ol>
<p>Positions and Covering is named because it encodes the problem with two transformations: first <em>positions</em>, then <em>coverings</em>. (In a more general sense, any geometry-inspired ILP-based method can be thought of as transforming the representation of the problem to efficiently express constraints.)</p>
<p class="blog-image full-width">
<a href="pos_coverings.svg"><img src="pos_coverings.svg" alt="" />
</a>
<span></span>
</p>
<h3 id="positions">Positions</h3>
<p>For every object \(p\) we create a matrix of \({0, 1}\)-decision variables the same size as the bin: \(A_p : \mathbb B^{bin_h \times bin_w}\). Each matrix should contain a single \(1\), corresponding to the top-left corner of the object. That is:
\[
A_{p}[i, j] = \begin{cases}
1 & \text{if object $p$ is at $(i, j)$} \\<br />
0 & \text{otherwise}
\end{cases}
\]</p>
<p>For this matrix to be valid, we need to encode the first two of the three constraints. We do this by setting the sum of all positions in the matrix that correspond to valid top-left corners to be \(1\), and the remaining cells to be \(0\). You can see an example of this in the left side of Figure 2, where the object D is represented by a \(1\) at its top-left corner and zeros otherwise.</p>
<h3 id="coverings">Coverings</h3>
<p>To address the third constraint they then introduce the <em>coverings</em> transformation, which expands the 1s in the positions matrices to cover all the cells the object would cover. You can see this in right side of Figure 2, where the object D is represented by a \(1\) in every cell it covers.</p>
<p>For every object \(p\), we construct a coverings matrix \(C_p : \mathbb B^{bin_h,bin_w}\). where:
\[
C_{p}[i, j] = \begin{cases}
1 & \text{if object $p$ occupies cell $(i, j)$} \\<br />
0 & \text{otherwise}
\end{cases}
\]
We can generate this from the coverings matrix by applying a sliding window of size \(h_p \times w_p\) to the positions matrix. Note that the construction of the coverings matrix from the positions matrix is a convolution operation, which is exactly what we’ll later exploit to speed up the algorithm.</p>
<p>To complete the description of P&C, we need to add the constraint that no two objects may overlap, which we do by creating a single overlap matrix \(O : \mathbb B^{bin_h,bin_w}\) that counts the number of objects that cover each position in the bin.
\[
O[i, j] = \sum_{p} C_{p}[i, j] \qquad \forall i, \forall j
\]
We add the constraint that the overlap matrix is no more than 1 in each position, guaranteeing that objects do not overlap. This completes the description of P&C.</p>
<h4 id="pc-complexity">P&C Complexity</h4>
<p>We observe that the coverings matrix is a very expensive operation, requiring one constraint for the outer product of each possible position in each object and the size of the bin. This corresponds to $\mathcal O(k \times b_h \times b_w \times \max_p(h_p) \times \max_p(w_p)) \subset \mathcal O(k \times b \times b_h^2 \times b_w^2)$ constraints. This is despite the number of variables being similar to the positions stage at $\mathcal O(k \times b \times b_h \times b_w)$. While the number of constraints is not always related to the time to solve these problems, we conjecture that a more compact representation will greatly speed up computation. We present a method that uses a much more compact representation and achieves greater speed.</p>
<h2 id="hough-and-cover">Hough and Cover</h2>
<p>The positions stage of Positions and Covering is a parameter-space transform that is better known as the <a href="https://en.wikipedia.org/wiki/Hough_transform">Hough transform</a>, a cornerstone of classic computer vision patented in the 1960s. We name our technique in honor of this venerable technique. H\&C uses the same positions stage as P\&C, and our main contribution is speeding up the coverings stage.</p>
<p>We begin by observing that the covering matrix in P\&C can be constructed using this peculiar matrix pattern and the cumulative sum operation:
\[
\textrm{CumSum}\left(
\begin{array}{rrrr}
1 & 0 & 0 & -1 \\<br />
0 & 0 & 0 & 0 \\<br />
0 & 0 & 0 & 0 \\<br />
-1 & 0 & 0 & 1 \\<br />
\end{array}\right)
=
\left(
\begin{array}{rrrr}
1 & 1 & 1 & 0 \\<br />
1 & 1 & 1 & 0 \\<br />
1 & 1 & 1 & 0 \\<br />
0 & 0 & 0 & 0 \\<br />
\end{array}\right)
\]</p>
<p>The delta matrix \(D : \mathbb Z^{k \times b \times h_b \times w_b}\) is constructed from a positions matrix $A$ using this pattern. There are two key features of this matrix: first, that all values are in \(\{-1,0,1\}\), and second that it only has non-zero values in 4 positions.
\[
D_{p}[i, j] = \begin{array}{ll}
\phantom{+} A_{p,i,j} & \text{(top-left}) \\<br />
+ A_{p,i-h_p,j-w_p} & \text{(bottom-right)} \\<br />
- A_{p,i-h_p,j} & \text{(bottom-left)} \\<br />
- A_{p,i,j-w_p} & \text{(top-right)} \\<br />
\end{array}
\qquad\forall p, \forall i, \forall j \label{eqn:makedelta} \\<br />
\]</p>
<p>The cumulative sum operation computes, for each cell in an input delta matrix, the sum of all values that are above it, to the left of it, or in the cell itself. Same as in <code class="language-plaintext highlighter-rouge">numpy</code>, <code class="language-plaintext highlighter-rouge">pandas</code>, or <code class="language-plaintext highlighter-rouge">MatLab</code>. We can implement this operation in a straightforward way:
\[
C_{p}[i, j] = \sum_{g=1}^{i} \sum_{h=1}^{j} D_{p}[g, h] \qquad \forall p, \forall q
\]
Or, we can specify \(C\) recursively, <a href="https://en.wikipedia.org/wiki/Summed-area_table">as explained here</a>:
\[
C_{p}[i,j] =
C_{p}[i-1, j] + C_{p}[i, j-1] - C_{p}[i-1, j-1] + D_{p}[i, j]
\qquad \forall p, \forall i, \forall j
\]</p>
<p>Representing the cumulative sum operation as the latter instead of the former allows us to significantly reduce the number of constraints needed to express them.</p>
<p>Now, for the <strong>key insight</strong> that speed up this algorithm. So far, we have written the overlap matrix as:
\[
O = \sum_{p=1}^k \text{CumSum}(D_{p})
\]
instead, we can write this as:
\[
O = \text{CumSum}(\sum_{p=1}^k D_{p})
\]
This does not change the meaning of the overlap matrix, but it does change the number of constraints needed to express it. This is key to the speedup of H\&C. Given this insight, we can now describe the H\&C algorithm:</p>
<p class="blog-image full-width">
<a href="sum_delta.svg"><img src="sum_delta.svg" alt="" />
</a>
<span></span>
</p>
<h3 id="hc-algorithm">H&C Algorithm</h3>
<p>We first convert the positions matrix \(A_p\) to a delta matrix \(D_p\) for each object \(p\). We then compute the sum of all delta matrices \(E : \mathbb Z^{b\times h_b\times w_b}\), taking the sum over all objects as illustrated in Figure 3:
\[
E[i, j] = \sum_{p=1}^k D_{p}[i, j] \qquad \forall i, \forall j
\]
We then construct the overlap matrix by taking the cumulative sum of this:
\[
O = \textrm{CumSum}(E)
\]
Now \(O[i, j]\) contains the number of objects occupying position \((i, j)\). We now add the constraint that no objects can overlap:
\[
O[i, j] \leq 1 \qquad \forall i, \forall j
\]
And this completes the H\&C construction.</p>
<h4 id="hc-complexity">H&C Complexity</h4>
<p>This re-ordering of operations greatly reduces the size of the optimization problem. Counting the constraints needed to encode this:</p>
<ul>
<li>the delta matrix incurs a constant number of constraints per element of the positions matrix for a total of \(\mathcal O(k \times bin_h \times bin_w)\) constraints;</li>
<li>the summation step applies to each variable exactly once to incur \(\mathcal O(k \times bin_h \times bin_w)\) constraints;</li>
<li>the cumulative-sum step touches each element in the overlap matrix a fixed number of times, leading to \(\mathcal O(b \times bin_h \times bin_w)\).</li>
</ul>
<p>The dominating term is \(\mathcal O(k \times bin_h \times bin_w)\), which is a tremendous improvement over P\&C, which has \(\mathcal O(k \times bin_h^2 \times bin_w^2)\) constraints.</p>
<p>In the paper we conduct experiments to show that H&C creates smaller problems than P&C in practice, and that these problems solve faster. We’ll skip that here, instead lets talk about why this works:</p>
<h2 id="why-does-this-work">Why does this work?</h2>
<p>Thus far, we have introduced the delta matrix without providing theoretical justification for its construction. This relies heavily on some key properties of linear operations, which we briefly review.</p>
<h3 id="properties-of-linear-operations">Properties of Linear Operations</h3>
<p>Linear operations are operations over vectors that preserve vector addition and scalar multiplication; that is, some function \(f\) is linear if and only if \(f(\vec a + \vec b) = f(\vec a) + f(\vec b)\) and if \(f(c \times \vec a) = c \times f(\vec a)\) for any vectors \(\vec a\) and \(\vec b\) and scalar \(c\). We rely on three key properties:</p>
<ol>
<li>Any operation that can be written as matrix multiplication (i.e., \(f(\vec b) = A \vec b\)) is linear. This also means that the sum of a vector, the sum of arbitrary subsets of a vector, and the convolution between two vectors are all linear operations.</li>
<li>Matrix operations are associative and distributive. Convolution operations are also commutative, a fact that makes it possible for us to re-order the formation of delta matrices.</li>
<li>If some function can be written as a matrix multiplication or convolution with a non-negative matrix, then it preserves convexity which is necessary to solve our ILP.</li>
</ol>
<h3 id="delta-matrix-explained">Delta Matrix Explained</h3>
<p>Now that we have these key properties, we can derive the structure of the delta matrix. Consider the one-dimensional mapping from positions to coverings:
\[
(0, 1, 0, …, 0, 0, 0) \rightarrow (0, 1, 1, …, 1, 0, 0)
\]
We note that for an object \(m\)-elements long in an $n$-element sequence, this will require $\mathcal{O}(mn)$ constraints to express. At each of $n$ positions in the sequence, the value is determined by the value at up to $m$ possible starting positions.</p>
<p>We observe that we can use the one-dimensional \(\text{CumSum}\) operation here as well:
\[
\text{CumSum}((0, 1, 0, …, 0, -1, 0)) \rightarrow (0, 1, 1, …, 1, 0, 0)
\]
This has the property that only two values are needed to specify an object of any length, and so the number of constraints needed is reduced to \(\mathcal{O}(n)\) from \(\mathcal{O}(mn)\).</p>
<p>Connecting this insight to the 2-dimensional case begins with observing that generating the coverings matrix is a convolution operation. That is, for some object $p$:
\[
C_p = A_p * \mathbb 1^{h_p \times w_p} = A_p * (\mathbb 1^{h_p \times 1} * \mathbb 1^{1 \times w_p})
\]
Where \(*\) denotes convolution, and \(\mathbb 1\) denotes a vector or matrix of ones.) We replace each of the one-vectors with the delta equivalent:
\[
= A_p * (\textrm{CumSum}(\text{delta}(h_p \times 1)) * \textrm{CumSum}(\text{delta}(1 \times w_p)))
\]
Since the cumulative sum is a linear operation, we can apply the distributive property:
\[
= A_p * \textrm{CumSum}(\text{delta}(h_p \times 1) * \text{delta}(1 \times w_p))
\]
And since the cumulative sum operation can be written as a convolution, we can invoke the associative property and move the positions matrix inside the operation:}
\[
= \textrm{CumSum}(A_p * \text{delta}(h_p \times 1) * \text{delta}(1 \times w_p))
= \textrm{CumSum}\left(A_p *
\left(\begin{array}{r}\phantom- 1 \\<br />
\phantom- 0 \\<br />
\phantom- \vdots \\<br />
\phantom- 0 \\<br />
-1
\end{array}\right)
* \left(\begin{array}{rrrrr} 1 & 0 & \cdots & 0 & -1\end{array}\right)\right)
\]
Our two-dimensional delta function is the convolution of each one-dimensional vector, so we can write the delta matrix as:
\[
= \textrm{CumSum}\left(A_p *
\left(\begin{array}{rrrrr}
\phantom- 1 & 0 & \cdots & 0 & -1 \\<br />
\phantom- 0 & 0 & & 0 & \phantom- 0 \\<br />
& \vdots & & \vdots \\<br />
\phantom- 0 & 0 & & 0 & \phantom- 0 \\<br />
-1 & 0 & \cdots & 0 & \phantom- 1
\end{array}\right)\right)
\]
This is the rearrangement that allows us to reduce the number of constraints in H&C.</p>
<p>The delta matrix extends one additional row and column past the original object. That is, when convolving with the bottom-right-most position of \(A_p\), the delta matrix extends out past the rightmost column and lowest row of \(C_p\). We observe that the value in those cells in \(C_p\) after the cumulative sum operation must always be zero, which means they can be safely truncated.</p>
<h2 id="preprocessing-cbd-and-future-work">Preprocessing, CBD, and Future Work</h2>
<p>CBD, the current state-of-the-art method, uses a much less sophisticated technique for arranging objects in bins than H&C. In the CBD paper, the authors credit the performance of their method with two key factors: first, that they solve as few arranging problems as possible by generalizing effectively from one infeasible arrangement to as many as possible; and second, their suite of preprocessing techniques. The preprocessing techniques alone are sufficient to solve some types of bin-packing problems (such as most of Class 9 of the Unibo dataset.)</p>
<p>In principle, we could use H&C to solve the sub-problems and see if the resulting method is faster than CBD. However, the source code for CBD is not available, and there is a huge amount of engineering overhead in recreating the entire pipeline. Instead of expending that effort, I’ll just post this on the internet and hope that someone finds the basic technique behind H&C as cool as I do.</p>
Wed, 26 Jan 2022 00:00:00 +0000
https://gauravmanek.com/projects/2022/hough-and-cover/
https://gauravmanek.com/projects/2022/hough-and-cover/Printer Air Filter
<p class="blog-image ">
<a href="filter_types.png"><img src="filter_types.png" alt="" />
</a>
<span></span>
</p>
<p>If you have a Voron, and you want to somehow filter volatile organic compounds released when printing some materials, everyone will point you towards the <a href="https://github.com/nevermore3d/Nevermore_Micro">Nevermore Micro</a>, which fits below the print bed. Unfortunately, the volume of the carbon filter material is limited by the gap between the print bed and the bottom, and the bed fans mod requires sufficient space for the air to circulate under the bed, so I needed a better design. Also, the full-size Nevermore is way too large (and would block the view from the top of the printer).</p>
<p>So, as any good maker would do, I made my own. The general goal is to provide a sufficiently long path through the filter media to maximize the amount of VOCs filtered out. The material provides resistance to flow, and so the allowable path length is limited by the desired flow rate, and increased by the maximum static pressure of the fan. We could calculate it, but its easier to just build the thing and measure it afterwards.</p>
<p>We’ve shown the exteriors of the first and second versions above, and you can see that it is in two parts, a head containing fans in black and a removable cartridge in red. The removable cartridge has this internal geometry, shown with the expected airflow pattern below. The fans are positioned in the middle of the head drawing air in from the cartridge and out into the printer. This was chosen so that the pressure in the cartridge is lower than ambient, which prevents air from leaking out around where the cartridge meets the body. (We avoid the complexity of needing some kind of rubber seal between the parts.)</p>
<p class="blog-image ">
<a href="filterpath.png"><img src="filterpath.png" alt="" />
</a>
<span></span>
</p>
<p>The trade-off in this sort of design is that the fans extend past the rear wall of the printer. They don’t extend all that much into the body, as pictured here. Since we’re attaching these to the back of the printer, and the maximum thickness of the assembly is limited by the height of the <a href="https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/ommy/roller_brackets">roller brackets</a>, this design was the best compromise on the geometry. It is high up enough that it does not interfere with the rear of the Z-assembly.</p>
<p class="blog-image ">
<a href="fans_inside.jpg"><img src="fans_inside.jpg" alt="" />
</a>
<span></span>
</p>
<p>Here is the first version printed and installed on my printer. It is much more printable – the cartridge prints as a single piece (instead of having a screw-on panel), and the internal geometry of the head is parallel to the print orientation so it can be printed with bridging instead of internal supports.</p>
<p class="blog-image ">
<a href="filter_outside.jpg"><img src="filter_outside.jpg" alt="" />
</a>
<span></span>
</p>
<p>The second version doesn’t have an inlet for the filament yet – once that is figured out, I’ll install it on my printer, take pretty pictures, and submit it to the Voron mods directory.</p>
Fri, 12 Nov 2021 00:00:00 +0000
https://gauravmanek.com/blog/2021/printer-air-filter/
https://gauravmanek.com/blog/2021/printer-air-filter/Voron 2.4
<p class="blog-image ">
<a href="printed_parts.jpg"><img src="printed_parts.jpg" alt="" />
</a>
<span></span>
</p>
<p>This printer is fast and makes beautiful parts. It is everything you could possibly want in a single-material FDM 3D printer, except that it requires a lot of time and effort to assemble and calibrate. I have always had an interest in 3d printer design, and I was eyeing this model for almost two years before giving in and buying. This was built from a kit, with parts printed on an Ender 3 and a Longer LK4 in a cabinet.</p>
<p>Assembly was a meticulous process but relatively quick, thanks to the quality of the manual. The real time-sink was the modding process. After a year of use, I’d recommend the following mods:</p>
<ul>
<li><a href="https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/JosAr/Klicky-Probe">Klicky magnetic probe</a>, for more repeatable measurements than the PL-08N.</li>
<li><a href="https://github.com/protoloft/klipper_z_calibration">Z-calibration plugin</a>, to eliminate first-layer offset issues.</li>
<li><a href="https://github.com/VoronDesign/VoronUsers/tree/2ba235ae2c5cee2dd955e68dc31eaf306a8c54cf/orphaned_mods/printer_mods/edwardyeeks/Decontaminator_Purge_Bucket_%26_Nozzle_Scrubber">Purge bucket</a>, for obvious reasons</li>
<li><a href="https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/Ellis/Bed_Fans">Bed Fans</a>, to use the bed to keep the chamber warm as well</li>
<li><a href="https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/ommy/roller_brackets">Roller Brackets</a>, to make it easier to change the electronics.</li>
<li><a href="https://github.com/VoronDesign/VoronUsers/tree/master/printer_mods/ElPoPo/RemovableDoors">Removable Doors</a>, for ease of maintenance</li>
<li><a href="https://www.aliexpress.us/item/3256803862666085.html">Toolhead Board</a>, which really simplifies the wiring</li>
<li><a href="/blog/2021/printer-air-filter">Quoth Air Filter</a>, of my own design</li>
</ul>
<p>It took a lot of tinkering to get working at first, but the community is very friendly and I got plenty of help in the Discord. Once it gets dialled, it prints quickly, reliably, and over a range of exotic filaments.</p>
<p class="blog-image">
<video preload="auto" autoplay="autoplay" loop="loop" muted="">
<source src="printing.webm" type="video/webm" /></source>
</video>
<span></span>
</p>
Fri, 15 Oct 2021 00:00:00 +0000
https://gauravmanek.com/blog/2021/voron/
https://gauravmanek.com/blog/2021/voron/IDEX Printer
<p class="blog-image ">
<a href="idex_printer.jpg"><img src="idex_printer.jpg" alt="" />
</a>
<span></span>
</p>
<p>I embarked on this project because I wanted to use my CNC machine for something practical, and what better to use a machine for than to build another?</p>
<p>Setting up CNC toolpaths is also a lot more complicated than 3D printing, and the cost scales considerably with each unique design and with each unique set-up. To make matters more interesting, I don’t have an automatic tool-changer on my machine, so each tool change adds further complexity. All this makes for a very interesting design constraint: to design things with as few unique parts as possible, and using as few tools as possible. This is why you’ll find that many parts have key features on only one side (which makes for fewer set-ups) or are designed to be symmetric (so I need to design toolpaths for fewer unique parts).</p>
<h2 id="overall-design">Overall Design</h2>
<p>The design is a fairly standard belt-and-rail IDEX, following the same overall geometry as the . The print envelope (approximately 300mm x 300mm x 200mm) was set by the spare parts I had on hand. I believe the only parts I had to purchase for this printer were the Y-axis linear rail and a power supply.</p>
<h2 id="independent-dual-extruder-x-axis">Independent Dual Extruder X-Axis</h2>
<p class="blog-image ">
<a href="motor_plate.jpg"><img src="motor_plate.jpg" alt="" />
</a>
<span></span>
</p>
<p>The hardest part of designing an IDEX printer is compressing the belt paths into a reasonable space, a challenge made more difficult by my requirement to make parts as symmetric as possible. To meet that requirement, I designed a pair of symmetric motor plates that hold the X-axis to the Z-axis, the X-axis motor for one hotend, and the X-axis idler gear for the other hotend. Using a pair of idler gears is key to this design: not only does this allow for the two sides of a belt to be routed closer together, but it also allows for the same motor plate, when flipped, to be used to drive either axis without modification.</p>
<p class="blog-image ">
<a href="x_belt_attachment.png"><img src="x_belt_attachment.png" alt="" />
</a>
<span></span>
</p>
<p>To reduce design complexity, this also extends to the way that the belts are attached to the X carriages. Both left and right carriages are designed to be identical and the belt clamping mechanism is also symmetric, so it can be mounted to attach to either belt. A key drawback of the belt layout in this printer is that the length of the belt for one motor is much longer than the other, so the axes have different resonances and potentially different print qualities.</p>
<p>Other minor design details include the motors holes being slotted so the motor can act as a belt tensioner, which saves on designing a separate component. Also shown is the red X-endstop mount. The plan was to eventually remove that separate part and instead also mount that to the motor plate where it would trigger off the extruder motor instead of the extruder body, but that was a minor enough improvement that I deferred that to later.</p>
<h2 id="the-simple-y-axis">The Simple Y-Axis</h2>
<p class="blog-image ">
<a href="y_axis.jpg"><img src="y_axis.jpg" alt="" />
</a>
<span></span>
</p>
<p>This is the simplest possible Y-axis design, with a carriage riding on two bearing blocks. The most interesting part of the design is the aluminum baseplate is assembled from six machined parts (only two unique designs!) with a small length of 2020 extrusion to hold the parts together. The design could be simplified further, but I was constrained by the size of aluminum stock I had access to.</p>
<p>The belt forms a continuous loop passing through the hollow center of the extrusion, as is done in virtually every cheap bedslinger 3d printer. 3D printed clamps hold it to an aluminum carriage, and the green part is used to trigger the fixed Y-endstop. The bed itself would be mounted to the outsides of the carriage using the usual levelling springs and hand-wheel nuts.</p>
<p>The original Y-axis design used mini V-wheels and V-slot extrusions to provide linear motion, but motion was not sufficiently smooth. After some experimentation, I figured out the reason for that is that and the heavy weight of the bed was applied to the wheels axially. The wheels and bearings are much better suited to bearing weight radially, and the only reason that the Ender 3 gets away with that design is the bed is extremely light. Rather than redesign the entire assembly to rotate the wheels, I purchased a cheap linear rail and kept the original design.</p>
<h2 id="test-print">Test Print</h2>
<p class="blog-image ">
<a href="print_samples.jpg"><img src="print_samples.jpg" alt="" />
</a>
<span></span>
</p>
<p>All this lead to a pair of test prints: my first-ever print (left), and the ability of the printer after some tuning (right). The quality is acceptable, but not great, and the speed was painfully slow. The small 10mm cube took about 30 minutes to print, including a three-minute bed probing routine.</p>
<h2 id="performance">Performance</h2>
<p>This printer is not exactly performant. There were two chief technical problems with it: a very slow, heavy, and resonant Y-axis, and poor probing performance. In retrospect, the first should have been obvious from the start: the 350mm glass bed is much heavier than most commercial bed-slinger design, and the specified motor is clearly struggling to accelerate that much mass. The size of the bed also makes heating much slower and getting a consistent first layer harder (it warps much more as it expands). The BL-touch probe used was inconsistent, and I could never figure out why. Probing would fail maybe one time every twenty, which is just enough to make every other print fail.</p>
<p>What ultimately killed my interest in the project is that I realized that don’t actually need an open-frame IDEX printer. The open-frame nature means it is only suitable for PLA. Since most of my interest is in single-material ABS
parts, so this printer lay unused for a year before I disassembled it. I ended up building a <a href="/blog/2021-10-15-voron/">Voron 2.4</a> instead.</p>
Sun, 01 Aug 2021 00:00:00 +0000
https://gauravmanek.com/blog/2021/idex-printer/
https://gauravmanek.com/blog/2021/idex-printer/Taig Flood Coolant System
<p class="blog-image">
<video preload="auto" autoplay="autoplay" loop="loop" muted="">
<source src="flood.webm" type="video/webm" /></source>
</video>
<span></span>
</p>
<p>To improve cutting performance with the mill, I built a minimum viable flood coolant system for under $200. This system can be turned on and off from G-code, and its pressure can be set manually. The system layout is pretty simple, and I will add a system diagram here when time permits.</p>
<h2 id="coolant-delivery">Coolant Delivery</h2>
<p>Coolant from the sump is pumped through the system using a submersible pump rated to 400 Gal/h pump (420 ml/s). The power to this pump is controlled using a solid state relay and can be switched from gcode. The actual flow rate through the system is substantially less, about half that. The ratings assume ideal conditions and we’ll be introducing a lot of losses by forcing the fluid through narrow tubing and a filtration system.</p>
<p>This goes through 3/4” tubing to a canister water filter with a 40-micron sediment filter. This removes fine swarf from the system – the coarse swarf (> 400 micron) is filtered as part of the sump return path. When milling aluminum, there should be very little swarf in the sub-400 micron range, so these filters remain good for months.</p>
<p>After this, there is a manually actuated ball valve that provides an optional return path. This overpressure valve is used to control the pressure at the nozzle without damaging the pump. As the speed of the pump motor cannot be controlled through PWM, and since the motor needs some minimum flow rate for internal cooling, the use of a continuously flowing overpressure valve is necessary.</p>
<p>To help with the velocity of the coolant, the pipe diameter is reduced from 3/4” to 1/4”, which makes the coolant flow fast enough to blow aluminum chips away from the cutting zone.</p>
<h2 id="sump-design">Sump Design</h2>
<p>The first time you run the coolant, be sure to check that the return rate is sufficient to keep the pump immersed. A lot of fluid will remain in circulation (in the filter body, in the tubes, trapped in the swarf and slowly percolating down, etc.) and can starve the motor of fluid.</p>
<p>Other than that, the return design is simple: there is a bucket with a 400-micron paint filter to catch the swarf, and this bucket is fed by a funnel-and-spout system to direct coolant down through the drain hole at the bottom of the enclosure. This design allows the entire tank to be mounted on a dolly so it can be wheeled in and out for cleaning. Here it is, pictured without a 3d-printed spout extender:</p>
<p class="blog-image ">
<a href="sump.jpg"><img src="sump.jpg" alt="" />
</a>
<span></span>
</p>
<p>With this design, cleaning the sump is easy, especially if you remember to wait until the spout stops dripping.</p>
<h2 id="fittings">Fittings</h2>
<p>Having done a little recreational plumbing, I was expecting that finding the right fittings at a store would be a challenge. I didn’t expect that none of the local stores would stock every item that I needed. Instead, I went to McMaster-Carr, who sorted me out for $40 including shipping. Through what I can only assume is witchcraft they got the parts to me in under 24 hours.</p>
Thu, 13 May 2021 00:00:00 +0000
https://gauravmanek.com/blog/2021/taig-coolant/
https://gauravmanek.com/blog/2021/taig-coolant/