added up to 2020 posts
@ -2,12 +2,12 @@
|
|||||||
title: MMSim
|
title: MMSim
|
||||||
date: 2019-12-12
|
date: 2019-12-12
|
||||||
categories: projects school
|
categories: projects school
|
||||||
excerpt: Just for fun, I wrote a simulator for the flood fill algorithm for the MicroMouse DeCal I helped teach this semester.
|
excerpt: Just for fun, I wrote a simulator for the flood fill algorithm for the Micromouse DeCal I helped teach this semester.
|
||||||
header:
|
header:
|
||||||
teaser: /assets/img/2019/mmsim_0.png
|
teaser: /assets/img/2019/mmsim_0.png
|
||||||
---
|
---
|
||||||
|
|
||||||
Out of the blue, I decided to write a simulator in Python for the MicroMouse DeCal I helped teach this semester. Past semesters of MicroMouse never got around to doing the actual maze solving and I felt that part of the reason was not having a good explanation or reference implementation of the algorithm. Flood fill is the de facto standard when it comes to this thing so I decided to learn it and implement it. Due to all the power outages and midterms, we ended up not getting to maze solving yet again but we’ll definitely do it next semester.
|
Out of the blue, I decided to write a simulator in Python for the Micromouse DeCal I helped teach this semester. Past semesters of Micromouse never got around to doing the actual maze solving and I felt that part of the reason was not having a good explanation or reference implementation of the algorithm. Flood fill is the de facto standard when it comes to this thing so I decided to learn it and implement it. Due to all the power outages and midterms, we ended up not getting to maze solving yet again but we’ll definitely do it next semester.
|
||||||
|
|
||||||
Here’s a [link](https://github.com/dragonlock2/MMSim) to my repo.
|
Here’s a [link](https://github.com/dragonlock2/MMSim) to my repo.
|
||||||
|
|
||||||
|
29
_posts/2020-01-15-server-upgrade.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
title: Server Upgrade!
|
||||||
|
date: 2020-01-15
|
||||||
|
categories: projects
|
||||||
|
excerpt: I started off my winter break by finally upgrading the Pi 3 that had been powering my website to a proper x86-64 server.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/server_1.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/server_1.jpg
|
||||||
|
- image_path: /assets/img/2020/server_2.jpg
|
||||||
|
- image_path: /assets/img/2020/server_4.jpg
|
||||||
|
- image_path: /assets/img/2020/server_5.jpg
|
||||||
|
- image_path: /assets/img/2020/server_6.jpg
|
||||||
|
- image_path: /assets/img/2020/server_7.jpg
|
||||||
|
- image_path: /assets/img/2020/server_3.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
To kick off the start of my winter break, I finally replaced the Raspberry Pi 3 that had been powering my website for the last couple months with a proper x86-64 server. The Pi 3 was simply too slow to complete basic tasks on a WordPress site with reasonable speed.
|
||||||
|
|
||||||
|
The main thing I considered when speccing out the server was the cost of upkeep. Once hosting a website gets to about $10 a month it starts to become more economical to find a third party host. The Pi 3 very conservatively draws about 5W continuously, which running 24/7 puts it at about $6 a year to run. So a sub-50W draw was roughly what I was aiming for.
|
||||||
|
|
||||||
|
Initially I looked into old Xeon processors which are dirt cheap, but I’d be trading price for higher energy consumption. Then I considered buying a refurbished Dell PC, which did have its merits. At the end of the day, I decided to splurge a little and buy all new components, centering around an ASRock DeskMini A300 and Ryzen 3 3200G. Native support for NVME drives which I’ve been hearing about for so long was the cherry on top. After ordering everything on Black Friday and surviving finals week, I was finally able to put the computer together.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
Measuring the power draw when idle puts it at about 15W, which is about $18 a year to run. Not too shabby. Considering my website doesn’t get that many visitors, it’ll be running idle a great deal of the time. Even pinning one core to a 100% put power draw at about 30W. Despite the initial ~$350 investment, this server was well worth it. And it’ll provide something to tinker around with when I’m bored.
|
||||||
|
|
||||||
|
Backing up the site takes seconds instead of minutes. Experimenting with new themes and settings is no longer such a chore. Saving a post happens just like that. I can actually watch images being uploaded in real time. The performance difference is absolutely beautiful.
|
20
_posts/2020-01-16-attiny10-tiny-low-cost-mcu.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: ATtiny10 - Tiny, Low-Cost MCU
|
||||||
|
date: 2020-01-16
|
||||||
|
categories: cool-chips
|
||||||
|
excerpt: Curiosity about the cheapest Atmel MCU led to the ATtiny10. Despite what at first may seem like severe limitations, it's pretty capable.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/attiny10.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/pcb_7.jpg
|
||||||
|
- image_path: /assets/img/2020/pcb_6.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
A couple years ago when I was placing my first order on Digi-Key, I wondered what the cheapest Atmel microcontroller there was. Turns out it was the ATtiny10 for about $0.35. This little microcontroller really packs quite the punch with 1KB of flash and an astounding 32 bytes of SRAM. It even has a single 16-bit timer with 2 PWM channels and a 4 channel 8 bit ADC. Including the reset pin, it has 4 I/O lines. Even more, it has an internal 8MHz oscillator. Despite its limitations people have done quite interesting things with these chips. One of the first things I noted when looking at this chip was that it had the perfect number of pins to control an RGB LED. Years later and wanting a really simple circuit to test out making double-sided PCBs, I decided to go through with the idea.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
The ATtiny10 uses a TPI programming interface. Not as cool as UPDI, but pretty cool nevertheless. In order to get a 3rd PWM pin, for fun I took the less conventional route of using an interrupt every time the timer overflowed to decide what to do with the 3rd pin. This way I could use the native PWM functionality of the other 2 pins. Surprisingly, I didn’t need to worry about using up too much SRAM at all because most of the code just did register operations.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/attiny10.jpg" %}
|
80
_posts/2020-01-16-bswelder-v1.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
---
|
||||||
|
title: BSWelder v1
|
||||||
|
date: 2020-01-16
|
||||||
|
categories: projects
|
||||||
|
excerpt: It's about time I stop soldering wires directly to lithium batteries so I salvaged a microwave transformer to make a cheap battery spot welder.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/bswelder_11.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/bswelder_2.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_3.jpg
|
||||||
|
|
||||||
|
gallery2:
|
||||||
|
- image_path: /assets/img/2020/bswelder_4.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_5.jpg
|
||||||
|
|
||||||
|
gallery3:
|
||||||
|
- image_path: /assets/img/2020/bswelder_6.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_7.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_8.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_9.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_10.jpg
|
||||||
|
|
||||||
|
gallery4:
|
||||||
|
- image_path: /assets/img/2020/bswelder_11.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_12.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_13.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_14.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_15.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_17.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_16.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
When it comes to working with lithium batteries such as the 18650s I used in my lightsabers, it’s never really a good idea to solder wires directly to them. Prolonged exposure to high heat is a no go for their chemistry. The proper way is to spot weld nickel strips to them and then solder wires where necessary. Nickel is really easy to get solder to stick to compared to 18650 battery terminals. However a decent battery spot welder can easily be upwards of $150, which is a bit much for something I’d seldom use. Considering the plethora of people online making their own battery spot welders, I decided to take the DIY route.
|
||||||
|
|
||||||
|
Generally speaking, a battery spot welder works by using a very high current – 100s of amps – to quickly heat and weld two pieces of metal together. The brevity and localization of the heat is what makes it perfectly safe for batteries. Producing and controlling this current pulse is the difficult part. A common way is to use high power batteries and a giant relay. Typically a car battery is used but those cost about a $100 which meant I wasn’t taking that route. Another popular way is to modify a microwave transformer. After finally finding a broken microwave off the street, I was in business.
|
||||||
|
|
||||||
|
## Salvaging a Microwave Transformer
|
||||||
|
|
||||||
|
Note that taking apart a microwave is incredibly dangerous due to the high voltages it uses. Even unplugged, the high voltage capacitor inside can still pack a lethal punch so be careful if you do this. Make sure to discharge it before handling it. Also careful with the magnetron because the beryllium oxide in it is carcinogenic if airborne.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/bswelder_1.jpg" %}
|
||||||
|
|
||||||
|
## Modifying the Transformer
|
||||||
|
|
||||||
|
After removing the transformer, I needed to remove the secondary coil so I could rewind my own. There’s two main approaches to this. The first and probably what I should’ve done is to take an angle grinder to the secondary to get the ends off and a screwdriver and mallet to get the rest out. The second is to take an angle grinder to the weld that connects the top block and remove the secondary that way. What I found strange is that the weld actually shorts all the laminations together, but turns out there’s a reason for [that](https://electronics.stackexchange.com/questions/262187/why-there-is-welding-on-some-iron-transformers-core).
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
Make sure to also remove the magnetic shunts and small middle coil. Just keep the primary. To make the new secondary, I used some 4 gauge welding cable, barely squeezing in just over a turn. Then I used a lot of Kapton tape to somewhat reconnect the top half. I get about 1.5V AC out.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
Next up is actually generating the pulses of current, which meant finding a way to quickly turn on and off a highly inductive load. If I learned anything from making my PCB laminator, it’s that TRIACs without a good snubber can have trouble turning off inductive loads. To make my life easier and to try something new, I bought an SCR. They can also have issues with inductive loads since internally they basically have a TRIAC with some control circuitry. I was prepared to spec out a snubber circuit, but to my surprise the SCR worked without one. To do viability testing I used some timing numbers from [here](https://www.avdweb.nl/popular/spotwelder/diy-spot-welder) and 3D printed an electrode holder to jerry-rig a little setup.
|
||||||
|
|
||||||
|
{% include gallery id="gallery2" %}
|
||||||
|
|
||||||
|
To my surprise, it worked really well. Not pretty since both the battery and the nickel strip were salvaged, but usable. The welds were stronger than the metal itself, which is a good sign. With that I proceeded to making rest of the electronics. I’m the type of person that likes UI, so I used this as an opportunity to use an EC-11 encoder I got off eBay and experiment a bit with the code. It was also my first attempt at a double-sided PCB.
|
||||||
|
|
||||||
|
{% include gallery id="gallery3" %}
|
||||||
|
|
||||||
|
## Code
|
||||||
|
|
||||||
|
The code was pretty interesting to write. Nothing too complicated as I banged it out in about an hour including all the testing. I really liked the UI I developed for it, which was inspired by what’s commonly used in 3D printers. Scrolling through different options is quite satisfying. One thing to note is that EC-11 encoders go through a full cycle with each detent, which corresponds to 4 ticks per detent using the common X4 encoding. It was also the first time I used EEPROM on Arduino. To reduce wear on it, I only save settings when a user selects the save option. Also note that uploading code to a standard Arduino erases its EEPROM, so I changed the fuse to stop that. Anyway, here’s the [code](https://gist.github.com/dragonlock2/6870f7ceb84fbee1c6bae093452540c4).
|
||||||
|
|
||||||
|
## Case
|
||||||
|
|
||||||
|
With the electronics done, I put together a really simple case. Forgetting to bring home my caliper was certainly a problem but I got through it with solid estimations using a ruler. I also designed a proper electrode holder since PLA melts under the heat of the welder. Since I didn’t have any good machining tools nor the stock, I bought some metal parts from Home Depot that work pretty well as holders.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/bswelder_11.jpg" %}
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
With everything finalized, I tried to make a little battery pack. Taking apart a friend’s broken battery bank to get some cells, I noted that all the terminals were scratched by a grinder of some sort. This is really clever since a clean metal surface is much easier to weld to, so I made sure to do this when I made my pack. To make a weld, simply place the nickel strip on the battery along with the electrodes. Apply a good amount of pressure and then press the trigger. I even made a foot switch, which I somehow didn’t get a picture of before heading back to school, to help out with this.
|
||||||
|
|
||||||
|
{% include gallery id="gallery4" %}
|
||||||
|
|
||||||
|
To ensure thorough testing, I went a bit overkill with the number of welds for each strip. I’ve noticed that one of two things happen with each weld. Most of the time the nickel strip gets red hot but sometimes there’s only sparks which in my experience result in cleaner and just as strong welds. It’ll take some more practice and tweaking to get this thing working perfectly.
|
||||||
|
|
||||||
|
Overall the welder cost about $40 to make, which was an absolute win. And the pack turned out perfect!
|
108
_posts/2020-01-16-diy-double-sided-pcbs-w-soldermask.md
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
title: DIY Double-Sided PCBs w/ Soldermask
|
||||||
|
date: 2020-01-16
|
||||||
|
categories: how-to projects
|
||||||
|
excerpt: After much trial and error, I've refined my simple and cost effective process for making PCBs w/ soldermask at home.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/pcb_6.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/bswelder_8.jpg
|
||||||
|
- image_path: /assets/img/2020/bswelder_7.jpg
|
||||||
|
|
||||||
|
gallery2:
|
||||||
|
- image_path: /assets/img/2020/pcb_3.jpg
|
||||||
|
- image_path: /assets/img/2020/pcb_4.jpg
|
||||||
|
|
||||||
|
gallery3:
|
||||||
|
- image_path: /assets/img/2020/pcb_5.jpg
|
||||||
|
- image_path: /assets/img/2020/pcb_8.jpg
|
||||||
|
|
||||||
|
gallery4:
|
||||||
|
- image_path: /assets/img/2020/pcb_7.jpg
|
||||||
|
- image_path: /assets/img/2020/pcb_6.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
Over the years, I’ve tried pretty much every trick in the book to make PCBs at home, but to no avail. It’s brought nothing but frustration and inconsistent results. If all you’re making are boards that use through-hole and large SMD components, feel free to use any method you come across. In my opinion, trying to use as many SMD components as possible is cheaper, smaller, and overall just easier to work with. However, to make routing easier, this necessitates sub-10mil trace and space boards, which means milling is no longer a reliable option. The toner transfer method offers the best balance of cost and effectiveness.
|
||||||
|
|
||||||
|
Cost and time are the two big things to consider when deciding to make your own PCBs. If you need same day turnaround or only one copy of a board, it’s economical to make boards yourself. Single sided boards are also good candidates for the DIY route. However in most cases, I’d say it’s best to just the send the board off to a manufacturer if you can wait. Once boards get to above 70mm in size and need sub-8mil trace/space and start needing more vias, I’d say it’s pretty much necessary to let someone else do the manufacturing. Nowadays, including shipping you can get 5 pieces of a 100mm x 100mm 6mil trace/space board for about $25.
|
||||||
|
|
||||||
|
Availability and cost of materials are big factors I considered when developing my own style of making PCBs. If it’s too expensive or materials are hard to come by, I’d rather just send the boards off to a manufacturer. I’ve heard of a photoresist method, but in my experience it’s a bit expensive and hard to come by so while I’m certain it works very well, it’s not something I’ve tried yet.
|
||||||
|
|
||||||
|
## Design Considerations
|
||||||
|
|
||||||
|
In my experience, 10mil trace/space boards are really easy to make and are suitable for most projects. 8mil boards are more difficult but with practice I’m getting better and better at them. It’s more of a timing thing than anything. I’ve pushed 6mil before but I honestly haven’t had much experience with those since 8mil is usually good enough.
|
||||||
|
|
||||||
|
For vias, the optimal way would be plated through holes but that’s a bit hard. I’ve heard of using PCB rivets which I really want to try one day. The trouble is finding a good cheap source for them. For now, to balance consistency and size, I use 1.5mm outer diameter, 0.5mm inner diameter for vias. Any standard component lead fits perfectly in the 0.5mm hole.
|
||||||
|
|
||||||
|
Also, the less copper there is to remove, the faster the whole etching process is later. Still, in the consideration of noise, don’t leave behind copper islands. Anyway onto the actual PCB making process.
|
||||||
|
|
||||||
|
## PCB Laminator
|
||||||
|
|
||||||
|
The problem with the toner transfer method is that people tend to use a clothes iron to do it. That works very poorly and takes a lot of effort. The human factor is a huge source of inconsistency so I desired some way to do toner transfer with as little interference as possible from my end. To that end I built a PCB laminator, which I’ve made a [post](https://matthewtran.dev/2019/06/pcb-laminator/) about. With this tool I can simply put the board in and let it do all the work. Perfect results almost every time.
|
||||||
|
|
||||||
|
In all honesty, your PCB laminator doesn’t need to be as complex as mine. Or it could be more complex. To each their own. In fact, some people have gotten this method to work without modifying the laminator at all.
|
||||||
|
|
||||||
|
## Toner Transfer
|
||||||
|
|
||||||
|
The gist of the toner transfer method is to print your PCB design (make sure to mirror it if you need to) onto some paper. Then apply heat and pressure to transfer the toner onto a clean copper clad board. The toner used in laser printers is a polymer with a glass transition temperature of about 132°C, so it’s the temperature to aim for when using this method.
|
||||||
|
|
||||||
|
### Preparing the Design
|
||||||
|
|
||||||
|
To start off we need to get our design onto paper. Everyone always talks about finding the perfect special paper that lets go of the toner so easily. In all honesty, that’s not necessary and just adds cost. I’ve found that standard magazine paper works exceptionally well. Good thing I have an endless stack of Time magazines at home. Since my laser printer doesn’t take too kindly to irregularly shaped, flimsy paper I have to tape it to another sheet of paper before sending it through. If you can, make sure toner density and resolution are at their highest settings.
|
||||||
|
|
||||||
|
Now cut out your design, making sure to leave some extra on the edges. For a double-sided board, you’re going to need to make a sort of sleeve with the front and back. Alignment of the two sides is pretty critical, so I use a flashlight to make sure all the vias line up.
|
||||||
|
|
||||||
|
### Prepping the Copper Clad Board
|
||||||
|
|
||||||
|
It is crucial that the copper is clean and free of oils or else the toner won’t stick well. I start by using one of those green abrasive dish scrubbers to scuff up the surface of the board. Sometimes I wash the board with soap and water to remove the copper particles. I always follow up with a quick wipe with acetone. Be careful not to touch the copper surface after this.
|
||||||
|
|
||||||
|
Now slide your copper clad board into your sleeve from earlier, keeping an eye on alignment. It should look something like this.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/pcb_1.jpg" %}
|
||||||
|
|
||||||
|
### Removing the Paper
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/pcb_2.jpg" %}
|
||||||
|
|
||||||
|
After sending it through the laminator for about 8 minutes, it’s time to remove the paper. I’ve heard of soaking it in soapy water for an hour and then just peeling the paper away, but that takes too long. If the transfer is good, just place the board under running water and peel off the paper. A lot will be left, but a good amount of vigorous rubbing removes the rest of the paper without much damage to the toner. If all goes well, your transfer will look something like this.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
I like to use a microscope to double check that toner covers everywhere I need it to.
|
||||||
|
|
||||||
|
## Etching
|
||||||
|
|
||||||
|
Now we’re ready to dunk our board in a vat of acid. The etchant I use is really easy to make and very popular. Just make a 50-50 mixture of muriatic acid (aka pool acid from Home Depot) and off the shelf hydrogen peroxide. This solution lasts pretty much forever and apparently gets stronger with use, although in my experience it gets subjectively weaker. Occasionally, it’s useful to bubble air through the solution to rejuvenate it. To make sure both sides etch at the same time, I tape on little plastic bits to the bottom of the board to elevate it. Dunk the board. Agitating it is useful but I’m lazy so usually I just let the board soak for an hour. I come out every 20 minutes or so to shake the solution around.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2019/pcb-lam-v1.5-etch.jpg" %}
|
||||||
|
|
||||||
|
It’s a good idea not to leave the container of etchant open since it’s so corrosive. All my tools have a layer of rust now just by placing them overnight near the open container.
|
||||||
|
|
||||||
|
You can tell the board is done etching by shining a flashlight under it. Keep in mind not to leave the board in too long. When the copper next to a trace is gone, the etchant starts eating underneath it. Right when the large copper areas are gone is the perfect time to remove the board. Keep in mind that once you can see through parts of the board, it’s a good sign the board is almost done. Wipe off the toner with acetone. It should look a little something like this.
|
||||||
|
|
||||||
|
{% include gallery id="gallery2" %}
|
||||||
|
|
||||||
|
It’s a good idea to go under the microscope to double check that there’s no shorts or broken traces.
|
||||||
|
|
||||||
|
## Soldermask
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/pcb_9.jpg" %}
|
||||||
|
|
||||||
|
It can get a bit annoying when solder flows all over your copper traces, so soldermask is a really nice touch to add. I’m still perfecting my technique, but I have a general process that works pretty well. You’re gonna need some of that cheap UV curable soldermask you can get on eBay. Transparency sheets too. I have some old inkjet transparency sheets but they still work well in a laser printer. Start by printing the soldermask onto a transparency sheet. Cut it out and layer at least two of them together since the toner usually isn’t perfectly solid.
|
||||||
|
|
||||||
|
Now squeeze out some liquid soldermask onto your board and use some transparency sheet scraps to spread out a thin layer over the whole board. The thinner the better, but not to the point that there’s nothing there. Place your transparency with the soldermask pattern over it. I like to press down the transparency against the board with some acrylic. Now shine a UV light over your whole board. The flashlight I use works, but I think a stronger one would work better. I’m pretty sure sunlight works too but I tend to do things under the cover of night.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/pcb_10.jpg" %}
|
||||||
|
|
||||||
|
## Cutouts and Drilling Holes
|
||||||
|
|
||||||
|
I like to drill holes after the soldermask because it’s annoying to clean out soldermask that flows into the holes. This is the most stressful part because of the human factor there’s much room for error. This is also the time to see how well aligned your vias are. There’s not much to say about drilling holes except make sure they’re aligned. You will end up breaking multiple drill bits so don’t worry too much.
|
||||||
|
|
||||||
|
As for cutouts, I usually use a bandsaw to get the rough shape and then sandpaper the rest of the way. For really precise cuts like with my [Nunchuk remote](https://matthewtran.dev/2019/07/wireless-arduino-nunchuk/), I use a Dremel. One of these days I’ll incorporate my CNC mill back into this process to remove this human factor.
|
||||||
|
|
||||||
|
{% include gallery id="gallery3" %}
|
||||||
|
|
||||||
|
At the end of the day, you’ll end up with something like this.
|
||||||
|
|
||||||
|
{% include gallery id="gallery4" %}
|
155
_posts/2020-01-16-setting-up-the-can-bus-on-stm32.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
---
|
||||||
|
title: Setting Up the CAN Bus on STM32
|
||||||
|
date: 2020-01-16
|
||||||
|
categories: how-to
|
||||||
|
excerpt: A little how-to on the basics of getting the CAN bus up and running on an STM32 microcontroller using Mbed or STM32CubeIDE.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/stm32can.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
<sub>Updated 2-1-2021</sub>
|
||||||
|
|
||||||
|
The ubiquitous CAN bus is found in just about every car today and in more places than you’d expect. It’s extremely robust, reasonably fast, uses only two wires, and can connect many different nodes. After receiving samples of a TCAN332G CAN transceiver from TI, I decided to figure out how to use it.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
When it comes to necessary hardware, the most important thing is the CAN transceiver which converts the TX and RX lines from the microcontroller to the differential CANH and CANL lines. The wiring should be a 120Ω characteristic differential impedance with 120Ω terminating resistors on both ends to prevent signal reflections. In practice for getting something basic working on the bench, you can get away with random wires.
|
||||||
|
|
||||||
|
It’s actually possible to not use a transceiver by using some diodes and following [this](https://www.mikrocontroller.net/attachment/28831/siemens_AP2921.pdf) schematic instead, That’s what I used to do a sanity check using a Teensy 3.6 while I was making breakout boards for the TCAN332G.
|
||||||
|
|
||||||
|
## Mbed
|
||||||
|
|
||||||
|
When it comes to working with ARM microcontrollers, Mbed provides a very low barrier to entry. It’s not quite as easy as Arduino, but it’s definitely easier than STM32CubeIDE. As is usually the case, the simplicity does come at the cost of flexibility when doing certain things. Mbed Studio has made huge improvements since I first made this post so I’d recommend it for anyone especially if they’re just starting out. That and I’m also not a fan of needing Internet connectivity for software development.
|
||||||
|
|
||||||
|
Not every STM32 chip is supported in Mbed, but most of the popular ones are. Also note that as long as you keep an eye on flash size and memory usage, code amongst any one family is intercompatible. For example, code for the target NUCLEO-F103RB also works for the popular STM32F103C8T6.
|
||||||
|
|
||||||
|
To show just how simple Mbed is, let’s start by initializing CAN.
|
||||||
|
|
||||||
|
{% highlight C++ %}
|
||||||
|
CAN can(PA_11, PA_12, 1000000); // RX, TX, baud rate
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Let’s send a CAN message.
|
||||||
|
|
||||||
|
{% highlight C++ %}
|
||||||
|
char data[] = "Hello!"; // 6 chars
|
||||||
|
|
||||||
|
// verbose way
|
||||||
|
CANMessage msg;
|
||||||
|
msg.id = 127; // 11-bit ID (can be changed to extended 29-bit)
|
||||||
|
msg.data = data; // points to char array with data to send
|
||||||
|
msg.len = 6; // number of bytes to transfer, up to 8 for normal CAN
|
||||||
|
can.write(msg);
|
||||||
|
|
||||||
|
// one-liner way
|
||||||
|
can.write(CANMessage(127, data, 8));
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Receiving messages in a polling fashion is just as easy, so I’ll leave that as an exercise for the reader. Let’s spice things up by doing it with interrupts instead. As of Mbed OS 6.5, the CAN implementation tries to acquire a lock before actually reading a message, but locks can’t be acquired in an interrupt context. As a result, the cleanest fix I found was to make a subclass of CAN that doesn’t acquire this lock and use that instead.
|
||||||
|
|
||||||
|
{% highlight C++ %}
|
||||||
|
class IRQ_CAN : public CAN {
|
||||||
|
using CAN::CAN;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int read(CANMessage &msg, int handle=0) {
|
||||||
|
int ret = can_read(&_can, &msg, handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Now we can attach a function to be called every time we receive a CAN message.
|
||||||
|
|
||||||
|
{% highlight C++ %}
|
||||||
|
void rxIrq() {
|
||||||
|
CANMessage msg;
|
||||||
|
can.read(msg);
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
|
||||||
|
can.attach(rxIrq); // place this somewhere like main()
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Keep in mind this is an interrupt context, so if you don’t want the rest of your program to stop for too long while servicing it you should keep the computation to a minimum. Setting a flag and having a message queue is probably the simplest option. Offloading it to a Thread and EventQueue is another option. If you still want to keep everything in the interrupt, you can even use the NVIC to ensure other interrupts are prioritized.
|
||||||
|
|
||||||
|
Recently, Mbed Studio expanded support for the STLINK programmers, so we can actually compile, upload, and even debug code all inside Mbed Studio. However, if you have an unsupported programmer, the compiled binaries are available in the BUILD folder.
|
||||||
|
|
||||||
|
## STM32CubeIDE
|
||||||
|
|
||||||
|
STM32CubeIDE is my go-to IDE for using features of STM32 chips that Mbed doesn’t make as easy. The history of ST’s recommended IDE is quite interesting and I still remember switching from SW4STM32 to Atollic TrueSTUDIO to STM32CubeIDE 1.0.0.
|
||||||
|
|
||||||
|
### STM32CubeMX
|
||||||
|
|
||||||
|
Nowadays STM32CubeMX is builtin to STM32CubeIDE which is really convenient. After making a new project and choosing your microcontroller, you’ll get a menu to configure many aspects of the boilerplate code generation. The things I usually start out with are configuring the clock under “System Core > RCC” and “Clock Configuration”, and enabling debugging under “System Core > SYS”.
|
||||||
|
|
||||||
|
Next let’s enable CAN under “Connectivity > CAN”. The prescaler divides the APB1 peripheral clock before it gets input to the CAN peripheral. Every bit period in CAN is divided up into time quanta and we sample partway through. Check out this [website](http://www.bittiming.can-wiki.info/) for a better explanation and a calculator for the values. Essentially we want to pick our Segment 1 and Segment 2 time quanta such that the total bit time matches our baud rate. Note that STM32CubeIDE might say a valid configuration is invalid due to floating point rounding error.
|
||||||
|
|
||||||
|
If you’re using receive interrupts, make sure to also enable it under the “NVIC Settings” tab. Also enable CAN callback registration in “Project Manager > Advanced Settings”. As with before, reading CAN messages without interrupts is left as an exercise for the reader. The libraries are well documented with comments.
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
After saving and generating the boilerplate code, we can initialize CAN. In order to receive messages, we need to setup a CAN filter which controls what messages are allowed through and to which FIFO they’re stored. The following code lets all messages through and puts them in FIFO 0. It also starts the CAN peripheral and attaches the receive interrupt to call `can_irq()`. Place this in `MX_CAN_Init()`. Note that hcan might be hcan0 if your chip has two CAN peripherals.
|
||||||
|
|
||||||
|
{% highlight C %}
|
||||||
|
/* USER CODE BEGIN CAN_Init 2 */
|
||||||
|
|
||||||
|
CAN_FilterTypeDef sf;
|
||||||
|
sf.FilterMaskIdHigh = 0x0000;
|
||||||
|
sf.FilterMaskIdLow = 0x0000;
|
||||||
|
sf.FilterFIFOAssignment = CAN_FILTER_FIFO0;
|
||||||
|
sf.FilterBank = 0;
|
||||||
|
sf.FilterMode = CAN_FILTERMODE_IDMASK;
|
||||||
|
sf.FilterScale = CAN_FILTERSCALE_32BIT;
|
||||||
|
sf.FilterActivation = CAN_FILTER_ENABLE;
|
||||||
|
if (HAL_CAN_ConfigFilter(&hcan, &sf) != HAL_OK) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_CAN_RegisterCallback(&hcan, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, can_irq)) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_CAN_Start(&hcan) != HAL_OK) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* USER CODE END CAN_Init 2 */
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Now let’s transmit a message.
|
||||||
|
|
||||||
|
{% highlight C %}
|
||||||
|
uint32_t mb;
|
||||||
|
CAN_TxHeaderTypeDef msg;
|
||||||
|
uint8_t data[] = "Hello!";
|
||||||
|
|
||||||
|
msg.StdId = 127;
|
||||||
|
msg.IDE = CAN_ID_STD;
|
||||||
|
msg.RTR = CAN_RTR_DATA;
|
||||||
|
msg.DLC = 6;
|
||||||
|
msg.TransmitGlobalTime = DISABLE;
|
||||||
|
|
||||||
|
if (HAL_CAN_AddTxMessage(&hcan, &msg, data, &mb) != HAL_OK) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Now we’ll write the message received callback, equivalent to rxIrq from above. I placed the following in “USER CODE BEGIN 4”.
|
||||||
|
|
||||||
|
{% highlight C %}
|
||||||
|
void can_irq(CAN_HandleTypeDef *pcan) {
|
||||||
|
CAN_RxHeaderTypeDef msg;
|
||||||
|
uint8_t data[8];
|
||||||
|
HAL_CAN_GetRxMessage(pcan, CAN_RX_FIFO0, &msg, data);
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
{% endhighlight %}
|
||||||
|
|
||||||
|
Explore the HAL CAN library if you want to learn about other settings and what not. Like Mbed Studio, we can build, program, and debug our code from within the IDE. It searches for an STLINK by default, but you can also setup a J-Link or even OpenOCD.
|
||||||
|
|
||||||
|
And that’s about it. The basics of what you need to know to get CAN up and running on STM32. I haven’t gotten my hands on a CAN FD enabled chip yet so that’s next.
|
112
_posts/2020-01-17-concept-micromouse-v1.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
---
|
||||||
|
title: Concept Micromouse v1
|
||||||
|
date: 2020-01-17
|
||||||
|
categories: projects school
|
||||||
|
excerpt: With a week of winter break left, I tried my hand at designing a concept Micromouse to inspire our next generation of Micromouses for the DeCal.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/mmv2_15.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/mmv2_3.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_2.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_1.jpg
|
||||||
|
|
||||||
|
gallery2:
|
||||||
|
- image_path: /assets/img/2020/mmv2_4.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_5.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_6.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_7.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_8.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_9.jpg
|
||||||
|
|
||||||
|
gallery3:
|
||||||
|
- image_path: /assets/img/2020/mmv2_10.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_11.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_12.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_13.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_14.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2_15.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
After taking the Micromouse DeCal and helping teach it for a semester, I decided it was time to try my hand at designing a Micromouse myself. There were a few things about our current Micromouse that I thought could be improved and some design decisions that I didn’t really understand the rationale behind. I grabbed a bunch of parts that we use in our current Micromouse and gave myself a week of winter break to put something together.
|
||||||
|
|
||||||
|
Since I’d want this design or something like it to eventually replace our current Micromouse, I set the overarching focus for this design to be cost-effective, easy to manufacture, and easy to develop code for. From a systems perspective, we can divide the Micromouse into several key sections: Power, Compute, Sensors, Effectors. I’ll go over several of the changes I made along with the rationale behind them.
|
||||||
|
|
||||||
|
## Power
|
||||||
|
|
||||||
|
### Battery
|
||||||
|
|
||||||
|
In our original Micromouse, we used a rechargeable 9v battery, which in my opinion had little to offer. I decided to switch to a 1S 3.7v LiPo battery which offers a slightly larger capacity, much higher discharge capability, fast charge rates, and a flat form factor all for about the same weight. The new form factor allowed me to flatten the design by a lot, improving maneuverability. Despite the lower voltage, my Micromouse still achieved speeds of ~500mm/s which is on par with what the 9v could do. I’d imagine using a 2S 7.4v LiPo pack would boast even higher speeds.
|
||||||
|
|
||||||
|
### Regulator
|
||||||
|
|
||||||
|
Since I was trying to move to ARM-based microcontrollers, I had to switch to a 3.3v regulator. For my design, I used a TPS63001 that I had lying around. This section doesn’t really matter too much as long as it can supply at >100mA. An LDO would work just as well while being easier to solder and using fewer components.
|
||||||
|
|
||||||
|
## Compute
|
||||||
|
|
||||||
|
Perhaps the biggest change I made to this Micromouse was the decision to switch from the Arduino Nano (ATmega328P) to a STM32F103CBT6, which is commonly found in those popular STM32 Blue Pill boards. Along with the far higher clock speed, the STM32F103CBT6 boasts 128KB of flash, 20KB of SRAM, and 32-bit computing. Even more, the STM32F103CBT6 offers external interrupts on all pins and a 12-bit ADC, opening up more interesting possibilities for sensors. Flexibility in development is the real key here.
|
||||||
|
|
||||||
|
Cost-wise, this chip is about $1 each on AliExpress, making it competitive with the Arduino Nano. The only issue is having to get a programmer, but it’s possible to use USB DFU to do that job. Soldering an LQFP chip can be a bit difficult, so I’m considering just using a full size STM32 Blue Pill board which costs about $2 each. Still, with some pointers and lots of solder wick, I think soldering an LQFP chip is achievable for even someone who hasn’t soldered before.
|
||||||
|
|
||||||
|
From a development perspective, it’s very easy to develop and program the STM32F103CBT6 using Arduino. However, I think that using Mbed can be even easier, as well as opening up the possibility of using an RTOS. In fact, I developed all the code I used for my concept using Mbed, applying object oriented principles and threads to clean up and organize everything. This makes it easier to keep the main focus on just the algorithm.
|
||||||
|
|
||||||
|
## Sensors
|
||||||
|
|
||||||
|
### IR
|
||||||
|
|
||||||
|
Doing research into other Micromouses, I found that most of them tend to use some sort of IR sensor to detect walls. After some testing, I noted that they don’t work well on angled surfaces, especially reflective ones. Head on, they do a great job for anything <10cm away. Overall, they’re not particularly consistent and are only really good enough to detect if a wall is there or not. I decided to place two IR sensors onto my Micromouse, one on the left and one on the right. This doesn’t affect maze solving much, but should help with realigning the Micromouse’s sense of which square it’s in.
|
||||||
|
|
||||||
|
### VL53L0X
|
||||||
|
|
||||||
|
When I was writing [MMSim](https://matthewtran.dev/2019/12/mmsim/), I finally understood why our Micromouse had distance sensors that were angled. We can use them to detect walls further than the square we are currently in. I wanted to keep this functionality so I kept 3 VL53L0X sensors on my Micromouse like the original design. For mainly aesthetic reasons, I didn’t want to angle the sensors inward so instead I did some CAD drawings to find the optimal angle of 22° to place the left and right sensors. For fun, I decided to also plot the placement of our original sensor and to my surprise, it’s field of vision perfectly matched the center of the walls to the front right and left. That’s what I was going for when I chose the angle for my sensors.
|
||||||
|
|
||||||
|
Doing some testing, I noted that these sensors were real nice. They are good for distances >1cm and still work on angled, even reflective, surfaces. They’re also pretty cheap and have many libraries already written for them. A great choice to keep in the Micromouse.
|
||||||
|
|
||||||
|
### Magnetometer/Compass
|
||||||
|
|
||||||
|
I originally wanted to also add the LSM9DS1 to my Micromouse since I had some samples. However, lacking the materials, I wasn’t able to get it soldered. In order to keep ourselves going straight and turns at crisp right angles, we do wall following and use our encoders to measure distance traveled. In my opinion, this method seems prone to error especially on certain mazes that have few opportunities to wall follow and many turns. Some kind of compass would be pretty useful to help out with this. This means that we’ll pretty much just need a magnetometer such as an LSM303 but LGA packages can be difficult to solder without the right tools. I think I’ll end up using an MPU-9250 in the next revision due to its QFN package and widely available breakout boards and libraries.
|
||||||
|
|
||||||
|
## Effectors
|
||||||
|
|
||||||
|
Motors are the only effectors to worry about. Just something to get the robot from one position to another and quickly. These are actually the most expensive part of the whole thing, but I couldn’t find much info on any alternatives, so I stuck to the motor encoder combo units we use in our current design.
|
||||||
|
|
||||||
|
As for the motor driver, there was nothing wrong with the DRV8833 so I stuck with it. The only issue is that the bare SMD component has a thermal pad underneath that must be soldered. To solder mine I used my [reflow oven](https://matthewtran.dev/2018/01/pcb-reflow-oven/) but I’m pretty sure I could use a large via to make one solderable without an oven.
|
||||||
|
|
||||||
|
## Build Process
|
||||||
|
|
||||||
|
### PCB Layout
|
||||||
|
|
||||||
|
With all the components chosen, I started by getting most of the software working. I initially tried to use STM32CubeIDE, but Mbed ended up being far easier to work with. Since there’s so many things to connect, I used STM32CubeMX to map out which pins I’d connect components to and ensure an easier PCB layout later. Something to note is that external interrupts are shared among pins with the same number, such as PA5 and PB5, so only one can be enabled at a time. Also, not all pins support native PWM functionality. After the pin mappings were chosen, I headed straight to KiCad.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
Aesthetically, I was going for a very symmetric look. Electrically, in testing I ran into issues with the VL53L0X failing after random amounts of time, which I at first attributed to noise. Thus I did my best to isolate the motor driver and reduce noise as much as possible. By placing the connector for the VL53L0X sensors directly on the PCB, I eliminated the need for much of the bulky wiring.
|
||||||
|
|
||||||
|
{% include gallery id="gallery2" %}
|
||||||
|
|
||||||
|
It took 3 tries, but I was finally able make the PCB. Due to its large size and double-sided nature, it is by far the most complex board I’ve made to date. The soldermask leaves a lot to be desired, but it works. As a one-off, this board is what I’d consider borderline between still making the PCB at home versus sending it off to a manufacturer.
|
||||||
|
|
||||||
|
### Some Bugs
|
||||||
|
|
||||||
|
Even with the noise reduction, the VL53L0X sensors still failed, marking the start of a long and tedious debugging process. First I tried removing the onboard LDO which actually turned out to be a 3.3v not 2.8v one, which could be a source of instability. These sensors can [run on 3.3v](https://community.st.com/s/question/0D50X0000Awa6k6SQA/vl53l0x-avdd-voltage) so its fine. Then I noticed that turning off the encoder improved stability, so I heavily optimized my encoder library and that helped somewhat. By connecting an OLED display, I learned that when the sensors fail, the whole I2C bus is disabled. Unplugging the sensors made the I2C bus work again so I isolated the problem to the sensors. Then I found this [website](https://alexnld.com/product/m5stack-tof-module-vl53l0x-time-of-flight-laser-ranging-sensor-laser-distance-sensor-module-grove-i2c/) which advised removing the level shifter and that helped a lot but wasn’t perfect. Finally, I dropped the I2C speed to 125kHz again and everything worked perfectly. These sensors are cheap knockoffs from China, so I wouldn’t be surprised if they can’t handle 400kHz I2C.
|
||||||
|
|
||||||
|
To get the IR sensors to work, I used a 1MΩ pull-up resistor on the photodetector, resulting in a very high impedance output. When switching quickly between reading the left and right IR sensors, this results in one reading affecting the [other](https://forum.arduino.cc/index.php?topic=597103.0). A simple fix is to just discard the first few readings.
|
||||||
|
|
||||||
|
A small issue I ran into was that the velocity readings from the encoder were very noisy. I was using X4 encoding which looks at every rising and falling edge of both channels. Switching to X1 encoding completely solved the issue. I guess this is because the A and B channels of these encoders are not a perfect 90° apart.
|
||||||
|
|
||||||
|
### Putting It All Together
|
||||||
|
|
||||||
|
With all the electronics done and tested, I put together a CAD model to mount the motors and everything. Not having a caliper certainly did not help, but I got a decent fit.
|
||||||
|
|
||||||
|
{% include gallery id="gallery3" %}
|
||||||
|
|
||||||
|
Overall, I really liked the design of my concept Micromouse and anticipate adopting a lot of its characteristics into our next generation of Micromouses when we get to it. There are quite a lot of things I’d like to change for the next revision. Here’s a somewhat exhaustive list:
|
||||||
|
|
||||||
|
- Professionally made PCBs w/ mounting holes and test points
|
||||||
|
- Add tactile switch for user to start maze finding
|
||||||
|
- Add MPU-9250 (Note it’s hand-solderable bc ground pad underneath is [unnecessary](https://github.com/kriswiner/MPU9250/issues/43))
|
||||||
|
- Switch to right angle female headers to make VL53L0X easier to mount
|
||||||
|
- Add vertical micro-USB port to open up DFU programming possibility
|
||||||
|
- Switch to 2S 7.4v LiPo and new regulator
|
||||||
|
|
||||||
|
Ready for the next revision!
|
12
_posts/2020-09-21-latex-resume-template.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: LaTeX Résumé Template
|
||||||
|
date: 2020-09-21
|
||||||
|
categories: other
|
||||||
|
excerpt: My friend wanted to use the template I wrote for my résumé so here it is.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/latex_logo.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
Way back last November I decided to rewrite my résumé in LaTeX because I got tired of trying to use Word. I got a template off the internet and modified it heavily to my liking, learning quite a bit about LaTeX in the process. Let me know what you think!
|
||||||
|
|
||||||
|
Here’s a link to the [files](https://gist.github.com/dragonlock2/8ed97a7b79193b9bd6dbc1167a7a927f). Note you need both files for this to work.
|
50
_posts/2020-10-10-mmv2.md
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: MMv2
|
||||||
|
date: 2020-10-10
|
||||||
|
categories: projects school
|
||||||
|
excerpt: The logical next step to Concept Micromouse v1. I still haven't gotten to full maze solving, but it's a step forward.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/mmv2r2_1.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_sch.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_pcb.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_3d.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_2.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_4.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_5.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_1.jpg
|
||||||
|
- image_path: /assets/img/2020/mmv2r2_3.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
Way back in January, after finishing [Concept Micromouse v1](https://matthewtran.dev/2020/01/concept-micromouse-v1/), it was time to head back to Berkeley. There, I set about finalizing my design into something other students could potentially manufacture. It would also be an interesting opportunity to make use of campus resources to bring a project from start to finish.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
Considering the various modifications I wanted to make to the previous design, I essentially started the whole PCB design process over from scratch. Well, I did get heavy inspiration from the previous design. Here’s a somewhat exhaustive list of changes.
|
||||||
|
|
||||||
|
- Changing VL53L0X side sensor angle from 22° to 27°. I experimentally determined this to be the optimal angle to center the cone of detection within two walls.
|
||||||
|
- Professionally made PCBs from JLCPCB (not sponsored). The quality is definitely not as good as Bay Area Circuits or OSH Park but certainly not bad for the price. My intent was to eventually get boards sponsored by Bay Area Circuits, so I designed the board to maximize panel yield.
|
||||||
|
- Added a tactile switch in my favorite PTS810 style package to have some kind of user input.
|
||||||
|
- Added an MPU-9250 IMU which aids positioning. However I might’ve damaged it while soldering.
|
||||||
|
- Switched to right angle female headers to make the VL53L0X sensors easier to mount.
|
||||||
|
- Added a micro-USB port to enable use of a DFU bootloader. I didn’t end up using this as it’s less convenient than an ST-Link.
|
||||||
|
- Switched to a 2S 7.4v LiPo. This doubled the max speed to 1000mm/s but that was only because the motors were undervolted in the previous design.
|
||||||
|
- Switched to JST-XH connectors for the motors to match the batteries. Ultimately this was a poor decision as the connector is bulky and overkill for the purpose.
|
||||||
|
- New 3D-printed frame which I designed with a caliper this time.
|
||||||
|
|
||||||
|
As usual, pics!
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
This was the first personal project I carried out from start to finish entirely within Berkeley and I’d say it went pretty well. Since I lived in Southside, I had to walk across campus every time I wanted to assemble anything. Other than that, the resources available at the Jacobs Makerspace were excellent and the staff are so nice, supportive, and experienced. However, I do still have a slight preference to my tools at home which are just a few steps away and open at 4am.
|
||||||
|
|
||||||
|
## Firmware
|
||||||
|
|
||||||
|
After finishing the hardware, I headed straight to writing the firmware (which is the more technically correct term than software?). Since I just came off the whole actually starting to learn C++ train from doing CS170, I took a very object oriented approach to the whole thing. At the end of the day, I had a set of libraries that handled all of the sensor reading and motor control inside of interrupts and threads. This way all the user needs to do is provide the maze solving algorithm. [MMSim](https://matthewtran.dev/2019/12/mmsim/) is decent but I’ll need to add support for 45° turns.
|
||||||
|
|
||||||
|
The biggest thing I still haven’t done is also arguably the most difficult and tedious. It’s the positioning algorithms. Since I don’t have a physical maze I can test on yet, I’ve been putting it off to work on other projects.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
While I certainly would not call this project a success because I still haven’t gotten to physical maze solving, it’s certainly a step forward. It boasts various improvements over the current design used to teach the DeCal while maintaining the same cost. The firmware design is a great starting point to build off of to finally finish maze solving. Just a great experience all around.
|
36
_posts/2020-10-11-urb-battery-pack.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
title: UR@B Battery Pack
|
||||||
|
date: 2020-10-11
|
||||||
|
categories: projects school
|
||||||
|
excerpt: For a first try, not a terrible attempt at designing my own battery pack for UR@B. It did save quite a bit of money.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/batt_1.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/batt_3.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_4.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_5.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_6.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_7.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_8.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_9.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_10.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_14.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_2.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_11.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_13.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_15.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_16.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_17.jpg
|
||||||
|
- image_path: /assets/img/2020/batt_1.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
Note Autonomous Underwater Vehicles at Berkeley (AUVs) has been renamed Underwater Robotics at Berkeley (UR@B). Does this cause confusion? Yes. Did we do it to better reflect the changing goals of the team? Yes.
|
||||||
|
|
||||||
|
Way back in March after heading home because of the pandemic, I immediately got to work on my projects. After doing power requirement planning to specify a battery for the Robosub, I realized that the Blue Robotics battery is just about right. However, it costs $300. As far as considering development costs go, it’s perfectly worth it, but given we are a new team with little funding (@Berkeley pls give us more funding) I decided to go the DIY route which ended up having more capacity and only cost $120.
|
||||||
|
|
||||||
|
Incoming collage of assembly pics. Man this thing took quite awhile to build.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
At the end of the day I had to ask myself several questions. Is it a 4S7P 21Ah Li-ion battery pack? Yes. Was it worth it? Sure. Should I have used a better spot welder? Definitely. Should I have used nickel strips with the right thickness and width for the current I want to push? Again yes. Is it stiff enough? Nope. Would heatshrinking the whole battery improve that? Yup. Would I rely on this battery for competition? Absolutely not. Is the team going to buy a new Blue Robotics battery instead? Yes thankfully we have a little more funding this semester. Can this be used as backup? Yeah batteries are expensive. Does it look like a stick of dynamite? Why yes it does.
|
44
_posts/2020-10-12-custom-st-link-v2-1.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
title: Custom ST-Link V2-1
|
||||||
|
date: 2020-10-12
|
||||||
|
categories: projects
|
||||||
|
excerpt: After my ST-Link V2 clone broke, I scoured the web for a way to build one from scratch. I ended up with a custom ST-Link with built-in UART VCP.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/stlinkv2_11.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_2.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_3.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_4.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_5.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_6.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_7.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_8.jpg
|
||||||
|
|
||||||
|
gallery2:
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_9.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_10.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_11.jpg
|
||||||
|
- image_path: /assets/img/2020/stlinkv2_12.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
After my ST-Link V2 that I bought from Amazon decided to break at the worst time, I decided to look into building my own programmers. Much like how I built an [AVRISP mkII](https://make.kosakalab.com/make/electronic-work/avrisp-mk2/uno-r3_avrisp-mk2_en/), I wanted to do the same for STM32. Looking around the web for a bit, I found out that it’s actually possible to create an ST-Link V2-1 (which has a VCP!) completely from scratch because someone managed to download the firmware from secure flash. I certainly don’t trust installing software I just find randomly online so I ran it in a VM to hopefully be safe. To my surprise, it worked. It’s even updatable through the normal ST-Link update utility.
|
||||||
|
|
||||||
|
{% include figure image_path="/assets/img/2020/stlinkv2_1.jpg" %}
|
||||||
|
|
||||||
|
As with any project, I had to turn it into a PCB. I based the design off a Nucleo schematic.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
Once the DIY PCB route worked, I decided this would be the programmer I’d use for UR@B which I’d affectionately name NOGPROG. I recently heard of OSH Park so I gave them a try. Definitely impressive quality and service. As always, I took great pride in making 3D-printed cases to cover up my imperfect soldering.
|
||||||
|
|
||||||
|
{% include gallery id="gallery2" %}
|
||||||
|
|
||||||
|
Was the LQFP package out of stock the first time around? Yes that’s why I used a QFN one instead. Did I accidentally buy the AZ1117CR2 instead of the AZ1117CR at first? Yes that’s why one of them doesn’t look like the others. Did I buy the wrong crystal the second time? Yes that’s why the soldering is a little janky from the Kapton tape I put underneath.
|
||||||
|
|
||||||
|
Next up I have to figure out how someone could pull the firmware off a secured chip. It looks like lujji was the one who figured out a clever way pull the bootloader. I’ll try to follow their work one day and make step by step instructions but for now it’s just more worth my time to buy an ST-Link V3.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- <https://sudonull.com/post/32259-Making-ST-Link-V21-from-Chinese-ST-Link-V2>
|
||||||
|
- <https://lujji.github.io/blog/reverse-engineering-stlink-firmware/>
|
53
_posts/2020-10-12-diy-tag-connect-cable.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
title: DIY Tag-Connect Cable
|
||||||
|
date: 2020-10-12
|
||||||
|
categories: projects
|
||||||
|
excerpt: While browsing through KiCad, I learned about the clever Tag-Connect system. Given the high cost, I decided to replicate the design for myself.
|
||||||
|
header:
|
||||||
|
teaser: /assets/img/2020/tagconn_8.jpg
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
- image_path: /assets/img/2020/tagconn_1.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_2.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_6.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_4.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_3.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_5.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_23.jpg
|
||||||
|
|
||||||
|
gallery2:
|
||||||
|
- image_path: /assets/img/2020/tagconn_17.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_18.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_19.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_20.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_21.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_22.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_15.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_16.jpg
|
||||||
|
|
||||||
|
gallery3:
|
||||||
|
- image_path: /assets/img/2020/tagconn_7.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_9.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_10.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_11.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_12.jpg
|
||||||
|
- image_path: /assets/img/2020/tagconn_13.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
**Disclaimer:** The original design is [patented](https://patents.google.com/patent/US8057248B1/en?inventor=Neil+S.+Sherman). This post is meant as a purely educational exploration into the manufacturing process of a clever invention. By no means should my method be used in any commercial capacity. Even personal use is of questionable legality. Please support the original inventor.
|
||||||
|
|
||||||
|
While looking through KiCad footprints, I came across the curious Tag-Connect ones. Upon further research, I found out they were an extremely clever alternative to bulky and expensive programming headers on PCBs. However, each cable costs around $40. The basic concept was rather simple, so I figured I’d try my hand at making one.
|
||||||
|
|
||||||
|
The basic design involves using two PCBs to maintain the proper spacing between the pogo pins. Since I needed maximum accuracy, I dusted off my CNC router which I hadn’t used in probably a year.
|
||||||
|
|
||||||
|
{% include gallery %}
|
||||||
|
|
||||||
|
After building my custom [ST-Link V2-1’s](https://matthewtran.dev/2020/10/custom-st-link-v2-1/), I decided to build a slimmer one. I’d also use an unbroken 1.0mm drill bit this time.
|
||||||
|
|
||||||
|
{% include gallery id="gallery2" %}
|
||||||
|
|
||||||
|
I even built a 6-pin one for AVR programming. I also use it for SWD when I don’t need the UART.
|
||||||
|
|
||||||
|
{% include gallery id="gallery3" %}
|
||||||
|
|
||||||
|
Over the summer, I was able to get my hands on a legitimate Tag-Connect cable to do a comparison. The real thing is much bulkier but of higher quality, precision, and durability. It uses ~0.9mm rods instead of 1.0mm and has better pogo pins with what I believe are crown heads. For $2 in materials but an absurd 2 hour manufacturing time, I’d say this was a pretty successful project but not worth doing for the average maker.
|
BIN
assets/img/2020/attiny10.jpg
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
assets/img/2020/batt_1.jpg
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
assets/img/2020/batt_10.jpg
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
assets/img/2020/batt_11.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
assets/img/2020/batt_12.jpg
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
assets/img/2020/batt_13.jpg
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
assets/img/2020/batt_14.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
assets/img/2020/batt_15.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/batt_16.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
assets/img/2020/batt_17.jpg
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
assets/img/2020/batt_2.jpg
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
assets/img/2020/batt_3.jpg
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
assets/img/2020/batt_4.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
assets/img/2020/batt_5.jpg
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
assets/img/2020/batt_6.jpg
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
assets/img/2020/batt_7.jpg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
assets/img/2020/batt_8.jpg
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
assets/img/2020/batt_9.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
assets/img/2020/bswelder_1.jpg
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
assets/img/2020/bswelder_10.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
assets/img/2020/bswelder_11.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
assets/img/2020/bswelder_12.jpg
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
assets/img/2020/bswelder_13.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
assets/img/2020/bswelder_14.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
assets/img/2020/bswelder_15.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
assets/img/2020/bswelder_16.jpg
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
assets/img/2020/bswelder_17.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
assets/img/2020/bswelder_2.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
assets/img/2020/bswelder_3.jpg
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
assets/img/2020/bswelder_4.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/bswelder_5.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
assets/img/2020/bswelder_6.jpg
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
assets/img/2020/bswelder_7.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
assets/img/2020/bswelder_8.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/bswelder_9.jpg
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
assets/img/2020/latex_logo.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
assets/img/2020/mmv2_1.jpg
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
assets/img/2020/mmv2_10.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
assets/img/2020/mmv2_11.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
assets/img/2020/mmv2_12.jpg
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
assets/img/2020/mmv2_13.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
assets/img/2020/mmv2_14.jpg
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
assets/img/2020/mmv2_15.jpg
Normal file
After Width: | Height: | Size: 137 KiB |
BIN
assets/img/2020/mmv2_2.jpg
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
assets/img/2020/mmv2_3.jpg
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
assets/img/2020/mmv2_4.jpg
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
assets/img/2020/mmv2_5.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
assets/img/2020/mmv2_6.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
assets/img/2020/mmv2_7.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
assets/img/2020/mmv2_8.jpg
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
assets/img/2020/mmv2_9.jpg
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
assets/img/2020/mmv2r2_1.jpg
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
assets/img/2020/mmv2r2_2.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
assets/img/2020/mmv2r2_3.jpg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
assets/img/2020/mmv2r2_3d.jpg
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
assets/img/2020/mmv2r2_4.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
assets/img/2020/mmv2r2_5.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
assets/img/2020/mmv2r2_pcb.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
assets/img/2020/mmv2r2_sch.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
assets/img/2020/pcb_1.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
assets/img/2020/pcb_10.jpg
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
assets/img/2020/pcb_2.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/pcb_3.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
assets/img/2020/pcb_4.jpg
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/img/2020/pcb_5.jpg
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
assets/img/2020/pcb_6.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
assets/img/2020/pcb_7.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
assets/img/2020/pcb_8.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/img/2020/pcb_9.jpg
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
assets/img/2020/server_1.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
assets/img/2020/server_2.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/server_3.jpg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
assets/img/2020/server_4.jpg
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
assets/img/2020/server_5.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
assets/img/2020/server_6.jpg
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
assets/img/2020/server_7.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
assets/img/2020/stlinkv2_1.jpg
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
assets/img/2020/stlinkv2_10.jpg
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
assets/img/2020/stlinkv2_11.jpg
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
assets/img/2020/stlinkv2_12.jpg
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
assets/img/2020/stlinkv2_2.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
assets/img/2020/stlinkv2_3.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/img/2020/stlinkv2_4.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
assets/img/2020/stlinkv2_5.jpg
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
assets/img/2020/stlinkv2_6.jpg
Normal file
After Width: | Height: | Size: 137 KiB |
BIN
assets/img/2020/stlinkv2_7.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
assets/img/2020/stlinkv2_8.jpg
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
assets/img/2020/stlinkv2_9.jpg
Normal file
After Width: | Height: | Size: 53 KiB |