Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resin for app-3-0 (Chore) #347

Merged
merged 26 commits into from
Oct 6, 2017
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Dockerfile.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# http://docs.resin.io/pages/deployment/docker-templates
FROM resin/raspberrypi3-python:3.5-slim-20170705

WORKDIR /usr/src


COPY ./api/requirements.txt ./requirements.txt
RUN apt-get update
RUN apt-get install gcc make git g++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. because we are using out requirements.txt for installing (though this could change pending other review comments)
  2. Because we need apt-get to be updated so it can find gcc
  3. Because we need gcc, make, git, and g++

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Do you think we can pre-build packages requiring native compilation to reduce image size?
We might want to run apt-get series in a single RUN command: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#run

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great but out of scope for alpha


RUN pip install -r ./requirements.txt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opentrons is a python package, we should install it using setup.py through pip install

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to install the app-3-0 branch using pip?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, pip install <path-to-setup.py> ... Can be pip install api/ or pip install . depending on where you are.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great but out of scope for alpha


COPY ./api ./api
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the two copy calls? I would think it would work if we did

COPY ./api ./api
# ...
RUN pip install -r ./api/requirements.txt
# ...


COPY data-user_storage.mount /etc/systemd/system/
RUN systemctl enable data-user_storage.mount


ENV INITSYSTEM on
RUN echo $PWD
CMD ["/usr/src/api/scripts/compute/start.sh"]
34 changes: 34 additions & 0 deletions RESIN_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
This document provides information on resin.io in the context of Opentrons.
Last updated: 9/24/17 - Jared Greene

Overview:
resin.io is a service that is used for fleet management. Opentrons uses it to update and support our automated pipetting systems.
Resin works upon resin.os which is a custom operating system they build ontop of Yocto linux distro. It is a stripped down version of
linux and, most importantly, runs docker. Two docker containers run within each resin-supported device:
1) the resin supervisor container
2) the opentrons server container

The resin supervisor container monitors the opentrons container and device. It also connects with the resin system
which allows multiple forms for support; including secure remote updating.

The opentrons server container runs the opentrons server and api which accepts incoming client connects and
allows clients to control the robot and upload/run protocols on it.


Getting Started [INTERNAL]:
Let's walk through our first api update / deployment.
For the sake of this walkthrough, we assume that you want to push an updated server image to
all the devices on an existing resin application (a fleet of devices).

1) Make an account on resin.io (make sure you set up an ssh key)
2) Commit your changes
3) then build your docker image and deploy it to all of the devices with:
`git push resin [CURRENT_BRANCH_NAME]:master`

Done! This will push this update out to all devices on this application (as long as the image is successfully built).

If you want to do something more complicated like pushing updates to a single device, creating a new application, or adding
a new device to a new or existing fleet then check out the resin docs at: https://docs.resin.io/introduction/



3 changes: 2 additions & 1 deletion api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pylama
pyserial==3.2.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think we need to align as a team on where dev dependencies go and where prod dependencies go. I'm fine with prod dependencies living here, but I've heard stuff about why pyserial isn't in requirements.txt so I'd like to understand what we're doing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mcous see my comment in Dockerfile above

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pytest
pytest-cov
pytest-aiohttp
Expand All @@ -7,4 +8,4 @@ numpydoc==0.6.0
# June 15 2017 (artyom) : https://github.com/pyinstaller/pyinstaller/issues/2434
git+https://github.com/pyinstaller/pyinstaller.git@7e814646474efc868206beb8fb9dfe45af527109
Sphinx==1.4.8
twine==1.8.1
twine==1.8.1
8 changes: 8 additions & 0 deletions api/scripts/compute/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket
cd /usr/src/api

echo "[BOOT] Starting server"
python /usr/src/api/opentrons/server/main.py '0.0.0.0':8080
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to move from our 31950 default port?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, I'll change it back


95 changes: 95 additions & 0 deletions api/tests/opentrons/util/motion_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import time

import serial

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks specific to our testing environment. Do we need this file here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for andy to be able to test on ot-2


'''
SETUP VARIABLES
'''

robot_portname = '/dev/tty.usbserial-AL0158RY'
robot_baud = 14400
robot_port = None


'''
ROBOT
'''


def robot_read():
data = robot_port.readline()
if b'error' in data or b'ALARM' in data:
raise Exception(data)
return data


def robot_write(data):
global robot_port
while int(robot_port.in_waiting):
robot_port.reset_input_buffer()
time.sleep(0.02)
if isinstance(data, str):
data = data.encode()
data = data + b' M400\r\n'
print(b'-> ' + data)
robot_port.write(data)
print(b' <- ' + robot_read()) # blocking
print(b' <- ' + robot_read()) # blocking

# steps/mm command (M92) always returns current values
if b'M92' in data:
print(b' <- ' + robot_read()) # blocking


def connect_to_robot():
global robot_port
try:
print('Connecting to robot...')
robot_port = serial.Serial(
port=robot_portname, baudrate=robot_baud)
robot_write('')
robot_write('M999')
# current
robot_write('M907 X1.5 Y1.5 Z0.7 A0.7 B0.2 C0.2')
# acceleration
robot_write('M204 S5000 X2500 Y2000 Z2000 A2000 B2000 C2000')
# speeds
robot_write('G0F120000 M203.1 X500 Y300 Z70 A70 B40 C40')
# steps/mm
robot_write('M92 X160 Y160 Z800 A800 B767.38 C767.38 M52 M54')
except Error:
raise RuntimeError('Please connect to robot USB')


def home(axis=''):
if not axis:
return
robot_write('G28.2 ' + axis)


def back_forth():
x_travel = 360
z_step = 180
# robot_write('G90 G0X380B15 G91')
robot_write('G90 G0X380 G91')
for i in range(4):
robot_write('G0X{} G0X{}'.format(-x_travel, x_travel))

for i in range(4):
robot_write('G0X{}Z{}A{} G0X{}Z{}A{}'.format(
-x_travel, -z_step, -z_step, x_travel, z_step, z_step))


'''
RUN
'''


connect_to_robot()

while True:
home('ZA')
home('X')
# home('Y')
back_forth()
11 changes: 11 additions & 0 deletions data-user_storage.mount
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description = USB Stick inserted by user

[Mount]
What = /dev/sda1
Where = /data/user_storage
Type = vfat
Options = rw

[Install]
WantedBy = multi-user.target