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!
+