Mercurial > pony
changeset 5:c1b6dd72fb3c
Add leg.py and add upload to the makefile
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Tue, 10 May 2016 17:56:10 +0200 |
| parents | 1ced6f4ec07d |
| children | 1529d6a90448 |
| files | .hgignore Makefile leg.py tools/webrepl_cli.py tools/websocket_helper.py |
| diffstat | 5 files changed, 342 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Sun May 08 16:34:13 2016 +0200 +++ b/.hgignore Tue May 10 17:56:10 2016 +0200 @@ -2,6 +2,7 @@ *~ .*.swp *.DS_Store +*.pyc doc/_build pony.zip pony.pdf
--- a/Makefile Sun May 08 16:34:13 2016 +0200 +++ b/Makefile Tue May 10 17:56:10 2016 +0200 @@ -1,7 +1,17 @@ FRITZING=fritzing PCBS=pony.zip +PYSRC=leg.py~ servo.py~ +ESP_ADDR=192.168.0.17 -all: $(PCBS) +all: + +upload: $(PYSRC) + +%.py~: %.py + python tools/webrepl_cli.py $< $(ESP_ADDR): + touch $@ + +pcbs: $(PCBS) clean: rm -f $(PCBS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/leg.py Tue May 10 17:56:10 2016 +0200 @@ -0,0 +1,35 @@ +import math +from machine import Pin + +from servo import Servo + + +def _solve_triangle(a, b, c): + a, b, c = abs(a), abs(b), abs(c) + if a + b < c or a + c < b or b + c < a: + raise ValueError("Impossible triangle: %r, %r, %r" % (a, b, c)) + cos = float(a ** 2 + b ** 2 - c ** 2) / (2 * a * b) + return math.acos(cos) + +def _norm(a, b): + return math.sqrt(a ** 2 + b ** 2) + + +class Leg: + femur = 21 # mm + tibia = 27 # mm + + def __init__(self, hip_pin, knee_pin): + self.servos = (Servo(Pin(hip_pin)), Servo(Pin(knee_pin))) + + def inverse_kinematics(self, x, y): + d = _norm(x, y) + if d > self.femur + self.tibia: + raise ValueError("Out of range.") + hip = math.atan2(y, x) + _solve_triangle(self.femur, d, self.tibia) + knee = _solve_triangle(self.femur, self.tibia, d) + return hip, knee + + +class HindLeg(Leg): + tibia = 35 # mm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/webrepl_cli.py Tue May 10 17:56:10 2016 +0200 @@ -0,0 +1,220 @@ +#!/usr/bin/env python +from __future__ import print_function +import sys +import os +import struct +import getpass +try: + import usocket as socket +except ImportError: + import socket +import websocket_helper + +# Define to 1 to use builtin "websocket" module of MicroPython +USE_BUILTIN_WEBSOCKET = 0 +# Treat this remote directory as a root for file transfers +SANDBOX = "" +#SANDBOX = "/tmp/webrepl/" +DEBUG = 0 + +WEBREPL_FILE = "<2sBBQLH64s" + + +def debugmsg(msg): + if DEBUG: + print(msg) + + +if USE_BUILTIN_WEBSOCKET: + from websocket import websocket +else: + class websocket: + + def __init__(self, s): + self.s = s + self.buf = b"" + + def write(self, data): + l = len(data) + if l < 126: + # TODO: hardcoded "binary" type + hdr = struct.pack(">BB", 0x82, l) + else: + hdr = struct.pack(">BBH", 0x82, 126, l) + self.s.send(hdr) + self.s.send(data) + + def recvexactly(self, sz): + res = b"" + while sz: + data = self.s.recv(sz) + if not data: + break + res += data + sz -= len(data) + return res + + def read(self, size, text_ok=False): + if not self.buf: + while True: + hdr = self.recvexactly(2) + assert len(hdr) == 2 + fl, sz = struct.unpack(">BB", hdr) + if sz == 126: + hdr = self.recvexactly(2) + assert len(hdr) == 2 + (sz,) = struct.unpack(">H", hdr) + if fl == 0x82: + break + if text_ok and fl == 0x81: + break + debugmsg("Got unexpected websocket record of type %x, skipping it" % fl) + while sz: + skip = self.s.recv(sz) + debugmsg("Skip data: %s" % skip) + sz -= len(skip) + data = self.recvexactly(sz) + assert len(data) == sz + self.buf = data + + d = self.buf[:size] + self.buf = self.buf[size:] + assert len(d) == size, len(d) + return d + + def ioctl(self, req, val): + assert req == 9 and val == 2 + + +def login(ws): + while True: + c = ws.read(1, text_ok=True) + if c == b":": + assert ws.read(1, text_ok=True) == b" " + break + passwd = getpass.getpass() + ws.write(passwd.encode("utf-8") + b"\r") + +def read_resp(ws): + data = ws.read(4) + sig, code = struct.unpack("<2sH", data) + assert sig == b"WB" + return code + +def put_file(ws, local_file, remote_file): + sz = os.stat(local_file)[6] + dest_fname = (SANDBOX + remote_file).encode("utf-8") + rec = struct.pack(WEBREPL_FILE, b"WA", 1, 0, 0, sz, len(dest_fname), dest_fname) + print(rec, len(rec)) + ws.write(rec[:10]) + ws.write(rec[10:]) + assert read_resp(ws) == 0 + with open(local_file, "rb") as f: + while True: + buf = f.read(1024) + if not buf: + break + ws.write(buf) + assert read_resp(ws) == 0 + +def get_file(ws, local_file, remote_file): + src_fname = (SANDBOX + remote_file).encode("utf-8") + rec = struct.pack(WEBREPL_FILE, b"WA", 2, 0, 0, 0, len(src_fname), src_fname) + print(rec, len(rec)) + ws.write(rec) + assert read_resp(ws) == 0 + with open(local_file, "wb") as f: + while True: + (sz,) = struct.unpack("<H", ws.read(2)) + if sz == 0: + break + while sz: + buf = ws.read(sz) + if not buf: + raise OSError() + f.write(buf) + sz -= len(buf) + assert read_resp(ws) == 0 + + +def help(rc=0): + exename = sys.argv[0].rsplit("/", 1)[-1] + print("%s - Perform remote file operations using MicroPython WebREPL protocol" % exename) + print("Arguments:") + print(" <host>:<remote_file> <local_file> - Copy remote file to local file") + print(" <local_file> <host>:<remote_file> - Copy local file to remote file") + print("Examples:") + print(" %s script.py 192.168.4.1:/another_name.py" % exename) + print(" %s script.py 192.168.4.1:/app/" % exename) + print(" %s 192.168.4.1:/app/script.py ." % exename) + sys.exit(rc) + +def error(msg): + print(msg) + sys.exit(1) + +def parse_remote(remote): + host, fname = remote.rsplit(":", 1) + if fname == "": + fname = "/" + port = 8266 + if ":" in host: + host, port = remote.split(":") + port = int(port) + return (host, port, fname) + +def main(): + + if len(sys.argv) != 3: + help(1) + + if ":" in sys.argv[1] and ":" in sys.argv[2]: + error("Operations on 2 remote files are not supported") + if ":" not in sys.argv[1] and ":" not in sys.argv[2]: + error("One remote file is required") + + if ":" in sys.argv[1]: + op = "get" + host, port, src_file = parse_remote(sys.argv[1]) + dst_file = sys.argv[2] + if os.path.isdir(dst_file): + basename = src_file.rsplit("/", 1)[-1] + dst_file += "/" + basename + else: + op = "put" + host, port, dst_file = parse_remote(sys.argv[2]) + src_file = sys.argv[1] + if dst_file[-1] == "/": + basename = src_file.rsplit("/", 1)[-1] + dst_file += basename + + if 1: + print(op, host, port) + print(src_file, "->", dst_file) + + s = socket.socket() + + ai = socket.getaddrinfo(host, port) + addr = ai[0][4] + + s.connect(addr) + #s = s.makefile("rwb") + websocket_helper.client_handshake(s) + + ws = websocket(s) + + login(ws) + + # Set websocket to send data marked as "binary" + ws.ioctl(9, 2) + + if op == "get": + get_file(ws, dst_file, src_file) + elif op == "put": + put_file(ws, src_file, dst_file) + + s.close() + + +if __name__ == "__main__": + main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/websocket_helper.py Tue May 10 17:56:10 2016 +0200 @@ -0,0 +1,75 @@ +import sys +try: + import ubinascii as binascii +except: + import binascii +try: + import uhashlib as hashlib +except: + import hashlib + +DEBUG = 0 + +def server_handshake(sock): + clr = sock.makefile("rwb", 0) + l = clr.readline() + #sys.stdout.write(repr(l)) + + webkey = None + + while 1: + l = clr.readline() + if not l: + raise OSError("EOF in headers") + if l == b"\r\n": + break + # sys.stdout.write(l) + h, v = [x.strip() for x in l.split(b":", 1)] + if DEBUG: + print((h, v)) + if h == b'Sec-WebSocket-Key': + webkey = v + + if not webkey: + raise OSError("Not a websocket request") + + if DEBUG: + print("Sec-WebSocket-Key:", webkey, len(webkey)) + + respkey = webkey + b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + respkey = hashlib.sha1(respkey).digest() + respkey = binascii.b2a_base64(respkey)[:-1] + + resp = b"""\ +HTTP/1.1 101 Switching Protocols\r +Upgrade: websocket\r +Connection: Upgrade\r +Sec-WebSocket-Accept: %s\r +\r +""" % respkey + + if DEBUG: + print(resp) + sock.send(resp) + + +# Very simplified client handshake, works for MicroPython's +# websocket server implementation, but probably not for other +# servers. +def client_handshake(sock): + cl = sock.makefile("rwb", 0) + cl.write(b"""\ +GET / HTTP/1.1\r +Host: echo.websocket.org\r +Connection: Upgrade\r +Upgrade: websocket\r +Sec-WebSocket-Key: foo\r +\r +""") + l = cl.readline() +# print(l) + while 1: + l = cl.readline() + if l == b"\r\n": + break +# sys.stdout.write(l)
