diff --git a/project-words.txt b/project-words.txt index f62be8a..35da1ce 100644 --- a/project-words.txt +++ b/project-words.txt @@ -3,6 +3,7 @@ Altium ASSEM astrojs Atmel +automations barebones beaglebone Bitwarden @@ -25,6 +26,8 @@ ELMI fhhs flowbite flowrate +gcode +gerbers Gitea HDFS headshot @@ -39,11 +42,15 @@ leconte Loctite luxon MGMT +microcontroller +microcontroller's Micropumps Millis +modbus Mokai Multimeters nixos +nvme offroad Onshape OSSM @@ -60,8 +67,10 @@ RFID Rito RSSI SARL +SCARA showerheads Shuttlebox +simplemotion sinnhuber sitemapindex Smartsheet @@ -77,6 +86,7 @@ touchoff triaging trivago Truong +Ubiquiti Unstow uuidv vaapi diff --git a/src/assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse-converted.mp4 b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse.mp4 similarity index 100% rename from src/assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse-converted.mp4 rename to src/assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse.mp4 diff --git a/src/assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test-converted.mp4 b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test.mp4 similarity index 100% rename from src/assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test-converted.mp4 rename to src/assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test.mp4 diff --git a/src/assets/experience/osu-robotics-club/mars-rover-software-lead/senior-design-fair.jpg b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/senior-design-fair.jpg new file mode 100644 index 0000000..b43d158 Binary files /dev/null and b/src/assets/experience/osu-robotics-club/mars-rover-software-lead/senior-design-fair.jpg differ diff --git a/src/components/PopoverWordDefinition.astro b/src/components/PopoverWordDefinition.astro index 271fa90..a2e392f 100644 --- a/src/components/PopoverWordDefinition.astro +++ b/src/components/PopoverWordDefinition.astro @@ -11,6 +11,7 @@ const keys: { [key: string]: string } = { GUI: "Graphical user interface", NUC: "A small and low-power computer made by Intel", PCBs: "Printed circuit boards", + SCARA: "Selective Compliance Assembly Robot Arm", TDD: "Test driven development", UPS: "Uninterruptible power supply", VISA: "Virtual instrument software architecture", diff --git a/src/components/PrintedCircuitBoard.astro b/src/components/PrintedCircuitBoard.astro index 34d54fb..a36991f 100644 --- a/src/components/PrintedCircuitBoard.astro +++ b/src/components/PrintedCircuitBoard.astro @@ -47,7 +47,7 @@ const semanticPcbRevisionSort = ( /> {revision.notes && revision.notes.length > 0 && ( -
+
)} diff --git a/src/pages/experience/osu-robotics-club/mars-rover-software-team-lead.astro b/src/pages/experience/osu-robotics-club/mars-rover-software-team-lead.astro index 57aa706..f8ca1ac 100644 --- a/src/pages/experience/osu-robotics-club/mars-rover-software-team-lead.astro +++ b/src/pages/experience/osu-robotics-club/mars-rover-software-team-lead.astro @@ -11,20 +11,34 @@ import type { videoConfig } from "@interfaces/video.ts"; import { roverSubTitles } from "./osu-robotics-club.ts"; +import H3 from "@components/H3.astro"; +import Li from "@components/Li.astro"; + +import Video from "@components/Media/Video.astro"; +import Paragraph from "@components/Paragraph.astro"; +import Paragraphs from "@components/Paragraphs.astro"; +import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro"; +import Timeline from "@components/Timeline/Timeline.astro"; +import Ul from "@components/Ul.astro"; +import type { categorySkills } from "@interfaces/skill-matrix.ts"; +import type { timelineEntry } from "@interfaces/timeline.ts"; +import { DateTime } from "luxon"; + import circ_champions from "@assets/experience/osu-robotics-club/mars-rover-software-lead/circ-champions.jpg"; import corwin_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/corwin-at-competition.jpg"; import drumheller_team_photo from "@assets/experience/osu-robotics-club/mars-rover-software-lead/drumheller-team-photo.jpg"; import final_ground_station_gui from "@assets/experience/osu-robotics-club/mars-rover-software-lead/final-ground-station-gui.png"; import ground_station_at_competition from "@assets/experience/osu-robotics-club/mars-rover-software-lead/ground-station-at-competition.jpg"; -import iris_pcb_assembly_timelapse_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse-converted.mp4"; +import iris_pcb_assembly_timelapse_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-assembly-timelapse.mp4"; import iris_pcb_working from "@assets/experience/osu-robotics-club/mars-rover-software-lead/iris-pcb-working.jpg"; import rover_at_competition_from_above from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-from-above.jpg"; import rover_at_competition_pickup_test from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-at-competition-pickup-test.jpg"; -import rover_gimbal_test_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test-converted.mp4"; +import rover_gimbal_test_converted from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-gimbal-test.mp4"; import rover_pose_with_dinosaur from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-pose-with-dinosaur.jpg"; import rover_with_arm_pose_in_desert from "@assets/experience/osu-robotics-club/mars-rover-software-lead/rover-with-arm-pose-in-desert.jpg"; +import senior_design_fair from "@assets/experience/osu-robotics-club/mars-rover-software-lead/senior-design-fair.jpg"; import silly_poke from "@assets/experience/osu-robotics-club/mars-rover-software-lead/silly-poke.gif"; -import Video from "@components/Media/Video.astro"; +import LinkButton from "@components/LinkButton.astro"; const headerCarouselGroup: carouselGroup = { animation: "slide", @@ -36,6 +50,7 @@ const headerCarouselGroup: carouselGroup = { corwin_at_competition, rover_at_competition_from_above, rover_at_competition_pickup_test, + senior_design_fair, final_ground_station_gui, ground_station_at_competition, iris_pcb_working, @@ -43,17 +58,253 @@ const headerCarouselGroup: carouselGroup = { ], }; +const timeline: timelineEntry[] = [ + { + event: "Project Started", + eventDetail: "Design Work Begins", + date: DateTime.fromISO("2017-09-01"), + }, + { + event: "Senior Design Presentation", + eventDetail: "Senior Design Fair", + date: DateTime.fromISO("2018-05-18"), + }, + { + event: "Won 1st Place!", + eventDetail: "CIRC", + date: DateTime.fromISO("2018-08-13"), + }, + { + event: "Project Finished", + eventDetail: "Final Documentation Complete", + date: DateTime.fromISO("2018-08-31"), + }, +]; + +const categorizedSkills: categorySkills[] = [ + { + category: "Software & Environments", + skills: [ + { + item: "Version Control", + subItems: [{ item: "Git" }], + }, + { + item: "Programming", + subItems: [ + { + item: "Languages", + subItems: [ + { item: "Python 2" }, + { item: "C++" }, + { item: "Bash Shell Scripting" }, + { item: "High-Level Embedded C/C++ (Arduino/Teensy)" }, + ], + }, + { + item: "Frameworks", + subItems: [{ item: "OpenCV" }, { item: "Qt" }], + }, + ], + }, + { + item: "Operating Systems", + subItems: [ + { + item: "Linux", + subItems: [{ item: "Ubuntu" }], + }, + ], + }, + ], + }, + { + category: "Electrical", + skills: [ + { + item: "Schematic & PCB Design", + subItems: [ + { + item: "Software", + subItems: [{ item: "Altium Designer" }], + }, + { + item: "PCB Assembly & Rework", + subItems: [ + { item: "Handheld Soldering" }, + { item: "Handheld Hot-Air Reflow" }, + { item: "Oven Reflow" }, + ], + }, + ], + }, + { + item: "Electrical Diagnostics", + subItems: [ + { item: "Multimeters" }, + { item: "Electronic Loads" }, + { item: "Oscilloscopes" }, + { item: "Logic Analyzers" }, + ], + }, + { + item: "Harnessing Fabrication", + subItems: [{ item: "DC Power & Signal" }], + }, + ], + }, +]; + const videos: videoConfig[] = [ { videoPath: iris_pcb_assembly_timelapse_converted }, { videoPath: rover_gimbal_test_converted }, { videoPath: "https://www.youtube-nocookie.com/embed/ZjGW-HWapVA" }, - { videoPath: "https://www.youtube-nocookie.com/embed/sceA2ZbEV8Y0" }, + { videoPath: "https://www.youtube-nocookie.com/embed/sceA2ZbEV8Y" }, ]; --- - +
+ +
+ +

Summary

+ +

Timeline

+ +
+ +

Key Takeaways

+
    +
  • Wrote software in Python and C++ for the Rover's onboard computer
  • +
  • Wrote firmware in embedded C/C++ for the Rover's distributed + microcontroller sub-systems
  • +
  • Hand-assembled most of the custom PCBs for the Rover's distributed + microcontroller sub-systems
  • +
  • Hand-fabricated much of the custom harnessing on the Rover
  • +
  • Piloted the Rover during some competition events
  • +
+
+ +
+ +

Details

+ +

My Experience

+ + + I had not originally planned to be software lead for this Rover year, + as I was already working two part time jobs and going to school + full-time, but after my best friend Nick decided to become team and + electrical lead, and my other best friend Dylan would create the + rover's arm for his senior design project, I just couldn't say no. + This also came hot off the heels of me being the emergency software + lead for Rover the previous year, writing enough code in the nine days + before competition to at least give them a fighting chance, which they + had, so I was even more prepped and ready. I only had one hard + requirement, joining as the software lead, and it was that we would + have to create a serious ground station setup. When I first joined the + robotics club in 2011, I did so because I was enraptured by the rover, + but especially its ground station, which was a full-screen display + full of stats, indicators, and buttons that got the nerd in me + excited. If I was going to go all-in, I was going to do the same, and + ended up making the ground station software my university senior + design project. + + + The upcoming year of work turned out to be some of the most intense I + ever had at OSU, mostly self-inflicted due to not wanting to let this + opportunity get wasted. It's worth noting, that not only was I writing + the ground station software, but also the software running on the + rover's onboard Jetson TX2 computer, all the firmware for each of the + many distributed systems, on top of also hand-assembling/debugging + most of the rover's PCBs, and creating many of its electrical wiring + harnesses. In total, I put in over 2000 hours of work on this project, + while working two part-time jobs and taking classes. It was a lot, + but, it also turned out to be my proudest achievement while at OSU, so + I'd argue it was worth it! + + + After these countless hours, what resulted was some incredibly robust + hardware and software, which didn't crash, and which allowed us to + absolutely crush the competition at the Canadian International Rover + Challenge in Drumheller, Alberta, Canada. We won first place, with a + final score of 287 points. The second best team got 159, so it wasn't + even close! On top of doing that well, the software was also feature + complete by halfway through the competition, which was no small feat + considering the amount of scope creep a project like this tends to + encounter. I was particularly proud of the ground station by this + point as well. Not only was it a treasure trove of information about + the Rover's state, but included live GPS mapping, multiple switchable + camera views with pan/tilt capabilities and quality-switching, + artificial speed limiting, and automations to automatically complete + some of the tasks from the competition with just a few button presses. + Considering the robotics team hadn't placed over 3rd since before I'd + started in 2011, finally getting a first place win was a breath of + fresh air, and made it much more cathartic when graduating the + following year. + + +
+ +

Technical Overview

+ + + The ground station itself contained an Intel NUC with a Core i5, 16GB + ram, nvme ssd, and was connected to two 23″ 1080p monitors. I chose + two so we would be able to see all primary Rover systems without + having to swap between tabs or pages, which I’d had to do on some + other software I’d written and knew wouldn’t be efficient when we were + in the middle of a timed event. The desktop ran Ubuntu 16.04 with the + ROS2 stack. For the UI, PyQt was used, allowing for easy tweaking + using QtCreator, and which provided access to QtSignals, a feature + that made simple cross-thread communication much easier in Python. The + Python code itself was Python 2, which was a limitation of the ROS2 + stack. Control of the rover was done via USB xbox controllers, plus a + keyboard and mouse. + + + The Rover itself ran on an NVidia Jetson TX2 single-board computer + powered from a 500Wh li-on battery. The electronics box also contained + a fuse box, power cutoff, network switch, battery backup, composite to + network video converter, usb hub, FrSky controller receiver, and + custom usb->RS485 adapter board. The TX2 ran Ubuntu 16.04 with the + ROS2 stack, just like the ground station. All remote control boards on + the Rover were communicated to using the modbus protocol over RS485. + Interfacing with the arm was achieved via RS485 as well, but using the + custom simplemotion control library provided by the motor controller + company. Using linux UDEV rules, usb->serial and cameras were + symlinked to custom, repeatable names at /dev/rover/name so that + devices could be accessed identically after reboots. Custom ROS nodes + were written for each system to be controlled, and the whole Rover ROS + package set to start automatically at boot. The Rover could be + controlled with an FrSky X9D controller whether the ground station was + running or not. The controller could also override all other control + inputs on-the-fly by flipping a switch on the controller. This was a + safety feature to ensure runaway ground station or autonomy code + wouldn’t allow the Rover to take off on its own. Conversely, the Rover + would also work without the controller powered on, but would + immediately allow for this override if turned on at any time. + Communication with the ground station was done using two Ubiquiti + Rocket M2 long-range wifi radios, along with their 10dB + omnidirectional antennas. This simple setup allowed for a transparent + ethernet link to be made between the two systems, allowing for useful + features such as remote debugging and code upload. The radios were + tested to work at roughly a kilometer away, when mostly line-of-sight. + + +
+

Videos

diff --git a/src/pages/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate.astro b/src/pages/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate.astro index 6e31308..9d87756 100644 --- a/src/pages/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate.astro +++ b/src/pages/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate.astro @@ -9,6 +9,7 @@ import Video from "@components/Media/Video.astro"; import PageGroup from "@components/PageGroup.astro"; import Paragraph from "@components/Paragraph.astro"; import Paragraphs from "@components/Paragraphs.astro"; +import PopoverWordDefinition from "@components/PopoverWordDefinition.astro"; import PrintedCircuitBoard from "@components/PrintedCircuitBoard.astro"; import SkillMatrix from "@components/SkillMatrix/SkillMatrix.astro"; import Timeline from "@components/Timeline/Timeline.astro"; @@ -50,6 +51,7 @@ import on_touchoff_block_isometric from "@assets/experience/osu-sinnhuber-aquati import pick_and_placing from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/pick-and-placing.mp4"; import precision_homing from "@assets/experience/osu-sinnhuber-aquatic-research-laboratory/zebrafish-embryo-pick-and-plate/precision-homing.mp4"; +import InlineLink from "@components/InlineLink.astro"; import { DateTime } from "luxon"; const headerCarouselGroup: carouselGroup = { @@ -93,37 +95,85 @@ const timeline: timelineEntry[] = [ ]; const categorizedSkills: categorySkills[] = [ + { + category: "Software & Environments", + skills: [ + { + item: "Version Control", + subItems: [{ item: "Git" }], + }, + { + item: "Programming", + subItems: [ + { + item: "Languages", + subItems: [ + { item: "Python 2" }, + { item: "Bash Shell Scripting" }, + { item: "Low-Level Embedded C/C++ (Atmel Studio)" }, + ], + }, + { + item: "Frameworks", + subItems: [{ item: "OpenCV" }, { item: "Qt" }], + }, + ], + }, + { + item: "Operating Systems", + subItems: [ + { + item: "Linux", + subItems: [{ item: "Debian" }], + }, + { item: "Microsoft Windows" }, + ], + }, + ], + }, { category: "Electrical", skills: [ { item: "Schematic & PCB Design", subItems: [ - { item: "Mentor Graphics PADS" }, - { item: "Altium Designer" }, - ], - }, - { - item: "PCB Assembly & Rework", - subItems: [ - { item: "Handheld Soldering" }, - { item: "Handheld Hot-Air Reflow" }, - { item: "Oven Reflow" }, + { + item: "Software", + subItems: [ + { item: "Altium Designer" }, + { item: "Mentor Graphics PADS" }, + ], + }, + { + item: "Manufacturing", + subItems: [ + { item: "Gerber Export" }, + { item: "BOM Management" }, + { item: "In-House Assembly" }, + ], + }, ], }, { item: "Electrical Diagnostics", - subItems: [{ item: "Multimeters" }, { item: "Oscilloscopes" }], + subItems: [ + { item: "Multimeters" }, + { item: "Electronic Loads" }, + { item: "Oscilloscopes" }, + ], + }, + { + item: "Harnessing Fabrication", + subItems: [{ item: "DC Low-Power & Signal" }], }, ], }, { - category: "Software & Environments", + category: "Mechanical", skills: [ - { item: "Git" }, { - item: "Programming", - subItems: [{ item: "Low-Level Embedded C/C++ (Atmel Studio)" }], + item: "Fabrication", + subItems: [{ item: "CNC" }, { item: "Hand Tools" }], }, ], }, @@ -143,7 +193,15 @@ const videos: string[] = [pick_and_placing, precision_homing];

Key Takeaways

    -
  • Placeholder
  • +
  • Delivered a design, and multiple built units, of a custom embryo + pick-and-plate machine
  • +
  • Reduced cost from ~$150,000 for previous generation to ~$10,000
  • +
  • Reduced the size from 4.5'x4.5'x8' for previous generation to + 1'x1'x1.5'
@@ -151,7 +209,88 @@ const videos: string[] = [pick_and_placing, precision_homing];

Details

- Placeholder + + For some quick context on why such a machine was even needed, the + Sinnhuber Aquatic Research Lab performs toxicology research using + Zebrafish. This means tha the lab is also a breeding facility, + generating a few thousand eggs a day, which need to be processed and + isolated prior to being introduced to experimental conditions. At one + point in time, these processes were done by hand, with all researchers + spending a significant portion of their day simply prepping the embryos. + Later on, they hired a contractor to design an automated solution to the + isolation problem, and while they delivered, the units were industrial + overkill, using massive arms and enclosures + to pick up embryos which were roughly half a millimeter in diameter. They + were also very expensive, costing around $150k per machine, and the lab had + four installed. Thus, the engineering team was tasked with cost and size reducing + them so that more could fit in the same space and throughput could be higher. + + + My coworker, Dylan Thrush, and I got to work. He focussed on the mechanical side, while I worked + on electrical and software. I had recently been learning PCB design + after becoming more familiar with it through the OSU robotics club, and + decided that a good place to start would be to create a motion + controller. Dylan and I had already landed on a simple stepper-motor + based system to more than meet the needs of a task like this, and both + of us already had experience with stepper-based CNC machines, making it + a great jumpoff point. My first PCB was unfortunately a massive failure, + because while I did include a quad stepper motor driver, + microcontroller, general purpose I/O, and usb to serial interface, I + failed to export the gerbers correctly. This resulted in a PCB with no + drills, making it completely useless (outside of a good learning + experience)! It was also just a poor layout overall, which isn't + surprising considering it was my first ever PCB design. If you want to + see this embarrassing result, check out the PCB section at the end of + this page! + + + For the second revision, we'd made some progress in other places, but + most importantly had decided that we would use a Beaglebone Black single-board-computer to run the whole system. In an effort to simplify + the assembly, I decided that the next revision would include headers to directly + mount the Beaglebone to the unit, providing power and a serial interface over + those pins. This version actually worked as expected, with only a few very + minor bodges to the microcontroller's crystal, and some bulk capacitance on + the power input. Since things were working, I began writing embedded C to + control motion through some higher-level interfaces. Not long into this process, + I realized I might have bitten off more than I could chew. Not only was I + having to learn the deep ins and outs of microcontroller programming, kinematics, + and serial interfaces, but I would still have to greatly improve my Python + skills, learn to create graphical user interfaces, and figure out how to detect + embryos using a camera and computer vision. While I was sad to scrap this, + we decided to fall back on a motion controller called TinyG, which would simply require gcode to be sent over serial to function. + + + Dylan built up a mechanical testbed, which we could mount a camera to, + and I began to focus on embryo detection. I was relatively new to + Python, but quickly found the Qt framework for building decent-looking + interfaces, and OpenCV for providing generic detection capabilities via + webcams. Over the next few years (remember, we were students doing this + part time, and working on other projects simultaneously), I eventually + created a fairly comprehensive user interface that would allow + researchers to tune detection and motion parameters on-the-fly. This was + shown on a touchscreen that the beaglebone plugged into, making it quite + intuitive. Dylan had also created a mechanical foundation providing + repeatable alignment for a petri dish with embryos, the 96-well plate + for placement, and a waste container to get rid of extra water in our + metal pipette tip that would be used to pick up the embryos. I'd also + created some very bright lighting boards to mount to the unit's + extrusion, illuminating the embryos from the side, something that was + absolutely required for consistent detection with the camera. After a + long journey, we finally delivered multiple units to the lab! Seeing + such small devices performing the same task next to the behemoths which + were the prior versions was quite amusing. You could easily fit a two by + two grid of these in the working area of each of those machines. + Overall, this was a highly ambitious project, but it developed some of + my most successful skills I gained while at OSU while accelerating the + research at the lab! +