Labs

Lab writeups:

  • Week 1 Lab: Pipetting

  • Week 2 Lab: DNA Gel Art

    Design Lane 4 will be left empty. EcoRI is listed here for visual purposes. Restriction Digest Protocol Digest components X uL NFW to 20 uL 2 uL 10X Promega buffer 1.5 ug DNA 15 units restriction enzyme Calculations for 10 uL reactions

  • Week 3 Lab: Opentrons Art

    Design Code Colab File from opentrons import types metadata = { # see https://docs.opentrons.com/v2/tutorial.html#tutorial-metadata 'author': 'Heather Qian', 'protocolName': 'Opentrons Flower', 'description': 'Makes a red and green flower', 'source': 'HTGAA 2026 Opentrons Lab', 'apiLevel': '2.20' } ############################################################################## ### Robot deck setup constants - don't change these ############################################################################## TIP_RACK_DECK_SLOT = 9 COLORS_DECK_SLOT = 6 AGAR_DECK_SLOT = 5 PIPETTE_STARTING_TIP_WELL = 'A1' well_colors = { 'A1' : 'Red', 'B1' : 'Green', 'C1' : 'Orange' } def run(protocol): ############################################################################## ### Load labware, modules and pipettes ############################################################################## # Tips tips_20ul = protocol.load_labware('opentrons_96_tiprack_20ul', TIP_RACK_DECK_SLOT, 'Opentrons 20uL Tips') # Pipettes pipette_20ul = protocol.load_instrument("p20_single_gen2", "right", [tips_20ul]) # Modules temperature_module = protocol.load_module('temperature module gen2', COLORS_DECK_SLOT) # Temperature Module Plate temperature_plate = temperature_module.load_labware('opentrons_96_aluminumblock_generic_pcr_strip_200ul', 'Cold Plate') # Choose where to take the colors from color_plate = temperature_plate # Agar Plate agar_plate = protocol.load_labware('htgaa_agar_plate', AGAR_DECK_SLOT, 'Agar Plate') ## TA MUST CALIBRATE EACH PLATE! # Get the top-center of the plate, make sure the plate was calibrated before running this center_location = agar_plate['A1'].top() pipette_20ul.starting_tip = tips_20ul.well(PIPETTE_STARTING_TIP_WELL) ############################################################################## ### Patterning ############################################################################## ### ### Helper functions for this lab ### # pass this e.g. 'Red' and get back a Location which can be passed to aspirate() def location_of_color(color_string): for well,color in well_colors.items(): if color.lower() == color_string.lower(): return color_plate[well] raise ValueError(f"No well found with color {color_string}") # For this lab, instead of calling pipette.dispense(1, loc) use this: dispense_and_detach(pipette, 1, loc) def dispense_and_detach(pipette, volume, location): """ Move laterally 5mm above the plate (to avoid smearing a drop); then drop down to the plate, dispense, move back up 5mm to detach drop, and stay high to be ready for next lateral move. 5mm because a 4uL drop is 2mm diameter; and a 2deg tilt in the agar pour is >3mm difference across a plate. """ assert(isinstance(volume, (int, float))) above_location = location.move(types.Point(z=location.point.z + 5)) # 5mm above pipette.move_to(above_location) # Go to 5mm above the dispensing location pipette.dispense(volume, location) # Go straight downwards and dispense pipette.move_to(above_location) # Go straight up to detach drop and stay high ### ### YOUR CODE HERE to create your design ### # Center pipette_20ul.pick_up_tip() pipette_20ul.aspirate(18, location_of_color("Green")) cursor = center_location.move(types.Point(x=-4, y=15)) for i in range(9): dispense_and_detach(pipette_20ul, 3, cursor) if i != 8: cursor = cursor.move(types.Point(x=4)) if i % 3 == 2 and i != 8: cursor = cursor.move(types.Point(x=-12, y=-4)) if i == 5: pipette_20ul.aspirate(9, location_of_color("Green")) pipette_20ul.drop_tip() # Right petal pipette_20ul.pick_up_tip() pipette_20ul.aspirate(18, location_of_color("Red")) cursor = cursor.move(types.Point(x=4)) for i in range(6): dispense_and_detach(pipette_20ul, 3, cursor) cursor = cursor.move(types.Point(y=4)) if i % 3 == 2: cursor = cursor.move(types.Point(x=4, y=-12)) pipette_20ul.aspirate(3, location_of_color("Red")) cursor = cursor.move(types.Point(y=4)) dispense_and_detach(pipette_20ul, 3, cursor) # Top petal pipette_20ul.aspirate(18, location_of_color("Red")) cursor = cursor.move(types.Point(x=-12, y=8)) for i in range(6): dispense_and_detach(pipette_20ul, 3, cursor) cursor = cursor.move(types.Point(x=-4)) if i % 3 == 2: cursor = cursor.move(types.Point(x=12, y=4)) pipette_20ul.aspirate(3, location_of_color("Red")) cursor = cursor.move(types.Point(x=-4)) dispense_and_detach(pipette_20ul, 3, cursor) # Left petal pipette_20ul.aspirate(18, location_of_color("Red")) cursor = cursor.move(types.Point(x=-8, y=-12)) for i in range(6): dispense_and_detach(pipette_20ul, 3, cursor) cursor = cursor.move(types.Point(y=-4)) if i % 3 == 2: cursor = cursor.move(types.Point(x=-4, y=12)) pipette_20ul.aspirate(3, location_of_color("Red")) cursor = cursor.move(types.Point(y=-4)) dispense_and_detach(pipette_20ul, 3, cursor) # Bottom petal pipette_20ul.aspirate(18, location_of_color("Red")) cursor = cursor.move(types.Point(x=12, y=-8)) for i in range(6): dispense_and_detach(pipette_20ul, 3, cursor) cursor = cursor.move(types.Point(x=4)) if i % 3 == 2: cursor = cursor.move(types.Point(x=-12, y=-4)) pipette_20ul.aspirate(3, location_of_color("Red")) cursor = cursor.move(types.Point(x=4)) dispense_and_detach(pipette_20ul, 3, cursor) pipette_20ul.drop_tip() # Stem pipette_20ul.pick_up_tip() pipette_20ul.aspirate(18, location_of_color("Green")) for i in range(6): cursor = cursor.move(types.Point(y=-4)) dispense_and_detach(pipette_20ul, 3, cursor) # Right leaf pipette_20ul.aspirate(15, location_of_color("Green")) cursor = cursor.move(types.Point(x=4, y=8)) for i in range(5): dispense_and_detach(pipette_20ul, 3, cursor) if i % 2 == 0: cursor = cursor.move(types.Point(y=4)) else: cursor = cursor.move(types.Point(x=4)) # Left leaf pipette_20ul.aspirate(15, location_of_color("Green")) cursor = cursor.move(types.Point(x=-16, y=-12)) for i in range(5): dispense_and_detach(pipette_20ul, 3, cursor) if i % 2 == 0: cursor = cursor.move(types.Point(y=4)) else: cursor = cursor.move(types.Point(x=-4)) pipette_20ul.drop_tip() Results

Subsections of Labs

Week 1 Lab: Pipetting

cover image cover image

Week 2 Lab: DNA Gel Art

Design

design design
Lane 4 will be left empty. EcoRI is listed here for visual purposes.

Restriction Digest Protocol

Digest components

  • X uL NFW to 20 uL
  • 2 uL 10X Promega buffer
  • 1.5 ug DNA
  • 15 units restriction enzyme

Calculations for 10 uL reactions

  • Kampy DNA concentration: 324 ng/uL
    • Use 4.6 uL DNA

BstXI

  • Stock BstXI concentration: 10 u/uL
    • 1.5 uL enzyme
    • 11.9 uL NFW
  • Buffer: Buffer H
  • Temperature: 37C

SfiI

  • Stock SfiI concentration: 10 u/uL
    • 1.5 uL enzyme
    • 11.9 uL NFW
  • Buffer: Buffer B
  • Temperature: 50C

KpnI

  • Stock KpnI concentration: 12 u/uL
    • 1.25 uL enzyme
    • 12.15 uL NFW
  • Buffer: Multicore buffer
  • Temperature: 37C

Gel Protocol

Gel components

  • 0.50 g agarose
  • 50 mL TAE buffer

Running the Gel

  • Sample order: ladder, BstXI, KpnI, BstXI, empty, BstXI, SfiI, BstXI
  • Add 4 uL 6X loading dye to each restriction digest
  • Run 12 uL digest in each well for 40 min at 150V
  • Stain the gel in 100 mL Millipore water and 3 drops of ethidium bromide

Results: Phage!

gel_image gel_image

Week 3 Lab: Opentrons Art

Design

opentrons_flower opentrons_flower

Code

Colab File

from opentrons import types

metadata = {    # see https://docs.opentrons.com/v2/tutorial.html#tutorial-metadata
    'author': 'Heather Qian',
    'protocolName': 'Opentrons Flower',
    'description': 'Makes a red and green flower',
    'source': 'HTGAA 2026 Opentrons Lab',
    'apiLevel': '2.20'
}

##############################################################################
###   Robot deck setup constants - don't change these
##############################################################################

TIP_RACK_DECK_SLOT = 9
COLORS_DECK_SLOT = 6
AGAR_DECK_SLOT = 5
PIPETTE_STARTING_TIP_WELL = 'A1'

well_colors = {
    'A1' : 'Red',
    'B1' : 'Green',
    'C1' : 'Orange'
}


def run(protocol):
  ##############################################################################
  ###   Load labware, modules and pipettes
  ##############################################################################

  # Tips
  tips_20ul = protocol.load_labware('opentrons_96_tiprack_20ul', TIP_RACK_DECK_SLOT, 'Opentrons 20uL Tips')

  # Pipettes
  pipette_20ul = protocol.load_instrument("p20_single_gen2", "right", [tips_20ul])

  # Modules
  temperature_module = protocol.load_module('temperature module gen2', COLORS_DECK_SLOT)

  # Temperature Module Plate
  temperature_plate = temperature_module.load_labware('opentrons_96_aluminumblock_generic_pcr_strip_200ul',
                                                      'Cold Plate')
  # Choose where to take the colors from
  color_plate = temperature_plate

  # Agar Plate
  agar_plate = protocol.load_labware('htgaa_agar_plate', AGAR_DECK_SLOT, 'Agar Plate')  ## TA MUST CALIBRATE EACH PLATE!
  # Get the top-center of the plate, make sure the plate was calibrated before running this
  center_location = agar_plate['A1'].top()

  pipette_20ul.starting_tip = tips_20ul.well(PIPETTE_STARTING_TIP_WELL)

  ##############################################################################
  ###   Patterning
  ##############################################################################

  ###
  ### Helper functions for this lab
  ###

  # pass this e.g. 'Red' and get back a Location which can be passed to aspirate()
  def location_of_color(color_string):
    for well,color in well_colors.items():
      if color.lower() == color_string.lower():
        return color_plate[well]
    raise ValueError(f"No well found with color {color_string}")

  # For this lab, instead of calling pipette.dispense(1, loc) use this: dispense_and_detach(pipette, 1, loc)
  def dispense_and_detach(pipette, volume, location):
      """
      Move laterally 5mm above the plate (to avoid smearing a drop); then drop down to the plate,
      dispense, move back up 5mm to detach drop, and stay high to be ready for next lateral move.
      5mm because a 4uL drop is 2mm diameter; and a 2deg tilt in the agar pour is >3mm difference across a plate.
      """
      assert(isinstance(volume, (int, float)))
      above_location = location.move(types.Point(z=location.point.z + 5))  # 5mm above
      pipette.move_to(above_location)       # Go to 5mm above the dispensing location
      pipette.dispense(volume, location)    # Go straight downwards and dispense
      pipette.move_to(above_location)       # Go straight up to detach drop and stay high

  ###
  ### YOUR CODE HERE to create your design
  ###

  # Center
  pipette_20ul.pick_up_tip()
  pipette_20ul.aspirate(18, location_of_color("Green"))

  cursor = center_location.move(types.Point(x=-4, y=15))

  for i in range(9):
    dispense_and_detach(pipette_20ul, 3, cursor)
    if i != 8:
      cursor = cursor.move(types.Point(x=4))
    if i % 3 == 2 and i != 8:
      cursor = cursor.move(types.Point(x=-12, y=-4))
    if i == 5: 
      pipette_20ul.aspirate(9, location_of_color("Green"))

  pipette_20ul.drop_tip()

  # Right petal
  pipette_20ul.pick_up_tip()
  pipette_20ul.aspirate(18, location_of_color("Red"))

  cursor = cursor.move(types.Point(x=4))

  for i in range(6):
    dispense_and_detach(pipette_20ul, 3, cursor)
    cursor = cursor.move(types.Point(y=4))
    if i % 3 == 2:
      cursor = cursor.move(types.Point(x=4, y=-12))

  pipette_20ul.aspirate(3, location_of_color("Red"))
  cursor = cursor.move(types.Point(y=4))
  dispense_and_detach(pipette_20ul, 3, cursor)

  # Top petal
  pipette_20ul.aspirate(18, location_of_color("Red"))

  cursor = cursor.move(types.Point(x=-12, y=8))

  for i in range(6):
    dispense_and_detach(pipette_20ul, 3, cursor)
    cursor = cursor.move(types.Point(x=-4))
    if i % 3 == 2:
      cursor = cursor.move(types.Point(x=12, y=4))

  pipette_20ul.aspirate(3, location_of_color("Red"))
  cursor = cursor.move(types.Point(x=-4))
  dispense_and_detach(pipette_20ul, 3, cursor)

  # Left petal
  pipette_20ul.aspirate(18, location_of_color("Red"))

  cursor = cursor.move(types.Point(x=-8, y=-12))

  for i in range(6):
    dispense_and_detach(pipette_20ul, 3, cursor)
    cursor = cursor.move(types.Point(y=-4))
    if i % 3 == 2:
      cursor = cursor.move(types.Point(x=-4, y=12))

  pipette_20ul.aspirate(3, location_of_color("Red"))
  cursor = cursor.move(types.Point(y=-4))
  dispense_and_detach(pipette_20ul, 3, cursor)

  # Bottom petal
  pipette_20ul.aspirate(18, location_of_color("Red"))

  cursor = cursor.move(types.Point(x=12, y=-8))
  
  for i in range(6):
    dispense_and_detach(pipette_20ul, 3, cursor)
    cursor = cursor.move(types.Point(x=4))
    if i % 3 == 2:
      cursor = cursor.move(types.Point(x=-12, y=-4))

  pipette_20ul.aspirate(3, location_of_color("Red"))
  cursor = cursor.move(types.Point(x=4))
  dispense_and_detach(pipette_20ul, 3, cursor)

  pipette_20ul.drop_tip()

  # Stem
  pipette_20ul.pick_up_tip()
  pipette_20ul.aspirate(18, location_of_color("Green"))
  
  for i in range(6):
    cursor = cursor.move(types.Point(y=-4))
    dispense_and_detach(pipette_20ul, 3, cursor)

  # Right leaf
  pipette_20ul.aspirate(15, location_of_color("Green"))

  cursor = cursor.move(types.Point(x=4, y=8))

  for i in range(5):
    dispense_and_detach(pipette_20ul, 3, cursor)
    if i % 2 == 0:
      cursor = cursor.move(types.Point(y=4))
    else:
      cursor = cursor.move(types.Point(x=4))

  # Left leaf
  pipette_20ul.aspirate(15, location_of_color("Green"))

  cursor = cursor.move(types.Point(x=-16, y=-12))

  for i in range(5):
    dispense_and_detach(pipette_20ul, 3, cursor)
    if i % 2 == 0:
      cursor = cursor.move(types.Point(y=4))
    else:
      cursor = cursor.move(types.Point(x=-4))

  pipette_20ul.drop_tip()

Results