diff --git a/rocolib/api/Function.py b/rocolib/api/Function.py index 8024cdb56f60588e33f29411bab2e65dc3c556c9..b0d8d076ea91266d71f6ede932157146d13be02c 100644 --- a/rocolib/api/Function.py +++ b/rocolib/api/Function.py @@ -21,7 +21,6 @@ class Function: def eval(self, parameterizable): import rocolib.utils.numsym as np - from rocolib.utils.dimensions import getDim function = eval("lambda x : " + self.fnstring, locals()) if isinstance(self.params, (list, tuple)): output = function([parameterizable.getParameter(x) for x in self.params]) diff --git a/rocolib/api/Parameterized.py b/rocolib/api/Parameterized.py index b3d3632d80beb0f416c2b62e9697b9be63b9cd30..fb70d20e2aa7daedb02ceb36ed98c4b14417511f 100644 --- a/rocolib/api/Parameterized.py +++ b/rocolib/api/Parameterized.py @@ -1,7 +1,8 @@ import re -from rocolib.utils.dimensions import isDim from rocolib.utils.numsym import Dummy +import logging +import yaml ### XXX "." is used to separate subcomponent parameters when inherited @@ -29,10 +30,6 @@ PARAM_TYPES = { "valueType": "int", "minValue": 0, }, - "dimension": { - "valueType": "str", - #"isValid": isDim, - }, } class Parameter: @@ -78,7 +75,21 @@ class Parameter: self.symbol = None self.value = None + def resolveValue(self, value): + if "values" not in self.spec: + return value + sanitize = lambda x : yaml.safe_load(yaml.safe_dump(x)) + vtest = sanitize(value) + v = sanitize(self.spec["values"]) + if isinstance(v, dict) and vtest not in list(v.keys()): + ks = list(v.keys()) + vs = list(v.values()) + if vtest in vs: + return ks[vs.index(vtest)] + return value + def setValue(self, value, validate=True): + value = self.resolveValue(value) if validate: self.assertValid(value) self.value = value @@ -95,8 +106,7 @@ class Parameter: def assertValid(self, value): if value is None: if self.spec.get("overrides", False): - self.value = value - return + return True else: raise ValueError(f"Parameter {self.name} is not optional (via overrides) and cannot be set to None") @@ -107,12 +117,19 @@ class Parameter: check("valueType", lambda x : isinstance(value, eval(x)), "is not of type") check("minValue", lambda x : value >= x, "is less than") check("maxValue", lambda x : value <= x, "is greater than") - check("isValid", lambda x : x(value), "is invalid") + check("values", lambda x : value in x, "is not in") + check("isValid", lambda x : x(self, value), "is invalid") return True + def validate(self): + return self.assertValid(self.value) + def getValue(self): if self.value is not None: - return self.value + if "values" in self.spec: + return self.spec["values"][self.value] + else: + return self.value else: return self.symbol @@ -209,7 +226,7 @@ class Parameterized(object): def validate(self): for p in self.parameters.values(): - p.assertValid(p.getValue()) + p.validate() def getParameter(self, name): """ diff --git a/rocolib/builders/ESPBrainsBuilder.py b/rocolib/builders/ESPBrainsBuilder.py deleted file mode 100644 index 272317a7add8fa2a96a0a9f1ac77f57570a97fa1..0000000000000000000000000000000000000000 --- a/rocolib/builders/ESPBrainsBuilder.py +++ /dev/null @@ -1,46 +0,0 @@ -from rocolib.api.components.Component import Component -from rocolib.api.Function import Function - - -self = Component() - -self.addSubcomponent("beam", "SimpleRectBeam") -self.addSubcomponent("header", "Header") -self.addSubcomponent("servoPins", "Cutout") - -self.addParameter("brain", "nodeMCU", paramType="dimension") -self.addParameter("length", 90, paramType="length") -self.addParameter("width", 50, paramType="length") -self.addParameter("depth", 20, paramType="length") - -### Set specific relationships between parameters -def getBrainParameter(p): - return "brain", "getDim(x, '%s')" % p - -self.addConstraint(("beam", "width"), "depth") -self.addConstraint(("beam", "depth"), "width") -self.addConstraint(("beam", "length"), "length") - -self.addConstraint(("beam", "width#minValue"), *getBrainParameter("height")) -self.addConstraint(("beam", "depth#minValue"), *getBrainParameter("width")) -self.addConstraint(("beam", "length#minValue"), *getBrainParameter("length")) - -self.addConstraint(("header", "nrows"), *getBrainParameter("nrows")) -self.addConstraint(("header", "ncols"), *getBrainParameter("ncols")) -self.addConstraint(("header", "rowsep"), *getBrainParameter("rowsep")) -self.addConstraint(("header", "colsep"), *getBrainParameter("colsep")) - -self.addConstConstraint(("servoPins", "dy"), 8) -self.addConstConstraint(("servoPins", "dx"), 27) - -self.addConnection(("beam", "face1"), - ("header", "decoration"), - mode="hole", offset=Function(params=("length", "brain"), fnstring="(7.5, -4.5 + 0.5*(x[0]-getDim(x[1], 'length')))")) - -self.addConnection(("beam", "face1"), - ("servoPins", "decoration"), - mode="hole", rotate=True, offset=Function(params=("length", "brain"), fnstring="(-17.25, (0.5 * (x[0]-getDim(x[1], 'length')))-14)")) - -self.inheritAllInterfaces("beam", prefix=None) - -self.toLibrary("ESPBrains") diff --git a/rocolib/builders/ESPSegBuilder.py b/rocolib/builders/ESPSegBuilder.py index 1928fc693aab60d524800cf249c35a37ae97c8a2..177a765cca2c38a461285d19c8dbb559da9e9da2 100644 --- a/rocolib/builders/ESPSegBuilder.py +++ b/rocolib/builders/ESPSegBuilder.py @@ -1,3 +1,4 @@ +from rocolib.library import getComponent from rocolib.api.components.Component import Component from rocolib.api.Function import Function @@ -9,10 +10,9 @@ c.addParameter("height", 40, paramType="length") c.addParameter("tire_thickness", 0, paramType="length") -c.addParameter("controller", "nodeMCU", paramType="dimension") -c.addParameter("driveservo", "fs90r", paramType="dimension") +c.addParameter("driveservo", "fs90r", values=getComponent("ServoMotor").dims) -c.addSubcomponent("brain", "ESPBrains") +c.addSubcomponent("brain", "MountedBrains", inherit="brain", prefix=None) c.addSubcomponent("right", "Wheel", invert=True, inherit="angle") c.addSubcomponent("left", "Wheel", invert=True, inherit="angle") @@ -23,18 +23,17 @@ c.addConstraint(("left", "tire_thickness"), "tire_thickness") def depthfn(params = None, fnmod = None): if params is None: params = [] if fnmod is None: fnmod = "%s" - return ["controller", "driveservo"] + params, \ - fnmod % "max(getDim(x[0],'height'), getDim(x[1],'motorwidth'))" + return ["brain", "driveservo"] + params, \ + fnmod % "max(x[0].get('height'), x[1].get('motorwidth'))" # Set microcontroller c.addConstraint(("brain", "depth"), *depthfn()) c.addConstraint(("brain", "length"), "width") -c.addConstraint(("brain", "brain"), "controller") for servo in ("right", "left"): c.addConstraint((servo, "length"), - ("length", "controller"), - "x[0] - getDim(x[1],'width')") + ("length", "brain"), + "x[0] - x[1].get('width')") c.addConstConstraint((servo, "center"), False) c.addConstraint((servo, "servo"), "driveservo") c.addConstraint((servo, "radius"), "height") @@ -61,9 +60,9 @@ c.addConstraint(("sheath","width"), *depthfn(["battery"], "%s + x[2]")) c.addSubcomponent("sheathsplit", "SplitEdge") c.addConstraint(("sheathsplit","toplength"), "width", "(x,)") c.addConstraint(("sheathsplit","botlength"), ("driveservo", "width"), - "(getDim(x[0],'motorheight'), \ - x[1] - 2*getDim(x[0],'motorheight'), \ - getDim(x[0],'motorheight'))") + "(x[0].get('motorheight'), \ + x[1] - 2*x[0].get('motorheight'), \ + x[0].get('motorheight'))") c.addConnection(("left", "topedge1"), ("sheathsplit", "botedge2"), diff --git a/rocolib/builders/MountedBrainsBuilder.py b/rocolib/builders/MountedBrainsBuilder.py new file mode 100644 index 0000000000000000000000000000000000000000..e60d51215fcd04ed251134b920d9149aa614afdf --- /dev/null +++ b/rocolib/builders/MountedBrainsBuilder.py @@ -0,0 +1,29 @@ +from rocolib.api.components.Component import Component +from rocolib.api.Function import Function + + +self = Component() + +self.addSubcomponent("beam", "SimpleRectBeam") +self.addSubcomponent("brain", "Brains", inherit="brain", prefix=None) + +self.addParameter("length", 90, paramType="length") +self.addParameter("width", 50, paramType="length") +self.addParameter("depth", 20, paramType="length") +self.addParameter("offset", (0,0)) + +self.addConstraint(("beam", "width"), "depth") +self.addConstraint(("beam", "depth"), "width") +self.addConstraint(("beam", "length"), "length") + +self.addConstraint(("beam", "width#minValue"), "brain", 'x.get("height")') +self.addConstraint(("beam", "depth#minValue"), "brain", 'x.get("width")') +self.addConstraint(("beam", "length#minValue"), "brain", 'x.get("length")') + +self.addConnection(("beam", "face1"), + ("brain", "decoration"), + mode="hole", offset=Function(params=("offset"))) + +self.inheritAllInterfaces("beam", prefix=None) + +self.toLibrary("MountedBrains") diff --git a/rocolib/builders/ServoMountBuilder.py b/rocolib/builders/ServoMountBuilder.py index 900cde2bee26aaca5763731e18ebf5de336e79c1..1fff49b20056d8369096177ddb87589fcb7b3c10 100644 --- a/rocolib/builders/ServoMountBuilder.py +++ b/rocolib/builders/ServoMountBuilder.py @@ -1,10 +1,10 @@ +from rocolib.library import getComponent from rocolib.api.components.Component import Component from rocolib.api.Function import Function c = Component() -c.addParameter("servo", "fs90r", paramType="dimension") - +c.addParameter("servo", "fs90r", values=getComponent("ServoMotor").dims) c.addParameter("flip", False, valueType="bool") c.addParameter("center", True, valueType="bool") c.addParameter("shift", 0, paramType="length") @@ -15,12 +15,12 @@ c.addParameter("offset", 0) c.addSubcomponent("beam", "SimpleRectBeam", inherit=("length", "addTabs"), prefix=None) c.addSubcomponent("mount", "Cutout") -c.addConstraint(("mount", "dx"), "servo", 'getDim(x, "motorwidth") * 0.99') -c.addConstraint(("mount", "dy"), "servo", 'getDim(x, "motorlength")') +c.addConstraint(("mount", "dx"), "servo", 'x.get("motorwidth") * 0.99') +c.addConstraint(("mount", "dy"), "servo", 'x.get("motorlength")') -c.addConstraint(("beam", "width"), "servo", 'getDim(x, "motorwidth")') -c.addConstraint(("beam", "depth"), "servo", 'getDim(x, "motorheight")') -c.addConstraint(("beam", "length#minValue"), "servo", 'getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")') +c.addConstraint(("beam", "width"), "servo", 'x.get("motorwidth")') +c.addConstraint(("beam", "depth"), "servo", 'x.get("motorheight")') +c.addConstraint(("beam", "length#minValue"), "servo", 'x.get("motorlength") + 2 * x.get("shoulderlength")') c.inheritAllInterfaces("beam", prefix=None) c.inheritAllInterfaces("mount") diff --git a/rocolib/library/Brains.py b/rocolib/library/Brains.py new file mode 100644 index 0000000000000000000000000000000000000000..dfc5b9841a6909ba3e102b02f01de438fc617480 --- /dev/null +++ b/rocolib/library/Brains.py @@ -0,0 +1,58 @@ +from rocolib.library import getComponent +from rocolib.api.composables.graph.Face import Face + + +ThruHole = getComponent("ThruHole").__class__ + +class Brains(ThruHole): + + brains = dict( + proMini = dict( + length = 39, + width = 19, + height = 9, + nrows = 12, + ncols = 2, + rowsep = 0.1 * 25.4, + colsep = 0.6 * 25.4, + origin = (0,0), + extras = (), + ), + nodeMCU = dict( + length = 59.5, + width = 44, + height = 13, + nrows = 15, + ncols = 2, + rowsep = 0.1 * 25.4, + colsep = 0.9 * 25.4, + origin = (7.5, -4.5), + extras = dict( + servoPins = dict(center = (-17.25, -14), size = (8, 27)), + ), + ), + ) + + def define(self): + ThruHole.define(self) + self.addParameter("brain", "nodeMCU", values=self.brains, overrides = dict( + nrows = 'c.getParameter("brain").get("nrows")', + ncols = 'c.getParameter("brain").get("ncols")', + rowsep = 'c.getParameter("brain").get("rowsep")', + colsep = 'c.getParameter("brain").get("colsep")', + )) + + def assemble(self): + ThruHole.assemble(self) + brain = self.getParameter("brain") + self.graph.dotransform(origin = brain.get("origin")) + for n, e in brain.get("extras").items(): + x, y = e.get("center", (0,0)) + dx, dy = e.get("size", (1,1)) + self.addFace(Face(n, + ((x-dx/2, y-dy/2), (x+dx/2, y-dy/2), (x+dx/2, y+dy/2), (x-dx/2, y+dy/2)), + recenter=False + )) + +if __name__ == "__main__": + Brains.test() diff --git a/rocolib/library/Cutout.py b/rocolib/library/Cutout.py index feb51f78d409d19cf57763e17717436a0a12d479..c639c89354d2b131f50a2ce1cc245641e8d780c3 100644 --- a/rocolib/library/Cutout.py +++ b/rocolib/library/Cutout.py @@ -6,8 +6,8 @@ class Cutout(DecorationComponent): self.addParameter("dx", 10, paramType="length") self.addParameter("dy", 20, paramType="length") self.addParameter("d", overrides={ - "dx": lambda c : c.getParameter("d"), - "dy": lambda c : c.getParameter("d"), + "dx": 'c.getParameter("d")', + "dy": 'c.getParameter("d")', }) def assemble(self): diff --git a/rocolib/library/ESPSeg.yaml b/rocolib/library/ESPSeg.yaml index 8c941477d9bbc53a4d2aff93979cafe1e5086d10..7de2c228fb1aaf9a34c2dc9021f3a9d6f39def98 100644 --- a/rocolib/library/ESPSeg.yaml +++ b/rocolib/library/ESPSeg.yaml @@ -50,9 +50,9 @@ connections: - botedge1 - angle: 90 tabWidth: - function: max(getDim(x[0],'height'), getDim(x[1],'motorwidth'))+x[2] + function: max(x[0].get('height'), x[1].get('motorwidth'))+x[2] parameter: - - controller + - brain - driveservo - battery connection7: @@ -61,10 +61,10 @@ connections: - decoration - mode: hole offset: - function: (4-(max(getDim(x[0],'height'), getDim(x[1],'motorwidth'))+x[3])/2, - 0.5 * x[2] - 15) + function: (4-(max(x[0].get('height'), x[1].get('motorwidth'))+x[3])/2, 0.5 * + x[2] - 15) parameter: - - controller + - brain - driveservo - length - battery @@ -90,14 +90,86 @@ parameters: minValue: 0 units: mm valueType: (float, int) - controller: + brain: defaultValue: nodeMCU spec: - valueType: str + overrides: + colsep: c.getParameter("brain").get("colsep") + ncols: c.getParameter("brain").get("ncols") + nrows: c.getParameter("brain").get("nrows") + rowsep: c.getParameter("brain").get("rowsep") + values: + nodeMCU: + colsep: 22.86 + extras: + servoPins: + center: + - -17.25 + - -14 + size: + - 8 + - 27 + height: 13 + length: 59.5 + ncols: 2 + nrows: 15 + origin: + - 7.5 + - -4.5 + rowsep: 2.54 + width: 44 + proMini: + colsep: 15.239999999999998 + extras: [] + height: 9 + length: 39 + ncols: 2 + nrows: 12 + origin: + - 0 + - 0 + rowsep: 2.54 + width: 19 driveservo: defaultValue: fs90r spec: - valueType: str + values: + ds2g: + horndepth: 1 + hornheight: 9 + hornlength: 11 + hornoffset: 4 + motorheight: 11 + motorlength: 17 + motorwidth: 8.5 + shoulderlength: 3.5 + fs90r: + horndepth: 2 + hornheight: 16 + hornlength: 10 + hornoffset: 8 + motorheight: 19 + motorlength: 23 + motorwidth: 13 + shoulderlength: 5 + s4303r: + horndepth: 2 + hornheight: 14 + hornlength: 38 + hornoffset: 7 + motorheight: 29 + motorlength: 31 + motorwidth: 17 + shoulderlength: 10 + tgy1370a: + horndepth: 2 + hornheight: 10 + hornlength: 7 + hornoffset: 4 + motorheight: 14 + motorlength: 20 + motorwidth: 9 + shoulderlength: 4 flapwidth: defaultValue: 0.2 spec: @@ -151,15 +223,15 @@ parameters: source: ../builders/ESPSegBuilder.py subcomponents: brain: - classname: ESPBrains + classname: MountedBrains kwargs: {} parameters: brain: - parameter: controller + parameter: brain depth: - function: max(getDim(x[0],'height'), getDim(x[1],'motorwidth')) + function: max(x[0].get('height'), x[1].get('motorwidth')) parameter: - - controller + - brain - driveservo length: parameter: width @@ -172,10 +244,10 @@ subcomponents: parameter: left.angle center: false length: - function: x[0] - getDim(x[1],'width') + function: x[0] - x[1].get('width') parameter: &id002 - length - - controller + - brain radius: parameter: height servo: @@ -192,7 +264,7 @@ subcomponents: center: false flip: true length: - function: x[0] - getDim(x[1],'width') + function: x[0] - x[1].get('width') parameter: *id002 radius: parameter: height @@ -209,9 +281,9 @@ subcomponents: length: parameter: length width: - function: max(getDim(x[0],'height'), getDim(x[1],'motorwidth')) + x[2] + function: max(x[0].get('height'), x[1].get('motorwidth')) + x[2] parameter: - - controller + - brain - driveservo - battery sheathsplit: @@ -219,7 +291,7 @@ subcomponents: kwargs: {} parameters: botlength: - function: (getDim(x[0],'motorheight'), x[1] - 2*getDim(x[0],'motorheight'), getDim(x[0],'motorheight')) + function: (x[0].get('motorheight'), x[1] - 2*x[0].get('motorheight'), x[0].get('motorheight')) parameter: - driveservo - width @@ -231,17 +303,17 @@ subcomponents: kwargs: {} parameters: depth: - function: max(getDim(x[0],'height'), getDim(x[1],'motorwidth'))+x[2] + function: max(x[0].get('height'), x[1].get('motorwidth'))+x[2] parameter: - - controller + - brain - driveservo - battery flapwidth: parameter: flapwidth height: - function: max(getDim(x[0],'height'), getDim(x[1],'motorwidth'))/2.+x[2] + function: max(x[0].get('height'), x[1].get('motorwidth'))/2.+x[2] parameter: - - controller + - brain - driveservo - height tailwidth: diff --git a/rocolib/library/Header.py b/rocolib/library/Header.py deleted file mode 100644 index 22827533dcc68707f52de3d36bb541fd5c2bb9f9..0000000000000000000000000000000000000000 --- a/rocolib/library/Header.py +++ /dev/null @@ -1,34 +0,0 @@ -from rocolib.api.components import DecorationComponent -from rocolib.api.composables.graph.Face import Face - - -class Header(DecorationComponent): - def define(self): - self.addParameter("nrows", 3, paramType="count") - self.addParameter("ncols", 1, paramType="count") - self.addParameter("rowsep", 2.54, paramType="length") - self.addParameter("colsep", 2.54, paramType="length") - self.addParameter("diameter", 1, paramType="length") - - def assemble(self): - diam = self.getParameter("diameter")/2. - nr = self.getParameter("nrows") - nc = self.getParameter("ncols") - - def hole(i, j, d): - dx = (j - (nc-1)/2.)*self.getParameter("colsep") - dy = (i - (nr-1)/2.)*self.getParameter("rowsep") - return Face("r-%d-%d" % (i,j), - ((dx-d, dy-d), (dx+d, dy-d), (dx+d, dy+d), (dx-d, dy+d)), - recenter=False) - - for i in range(nr): - for j in range(nc): - d = diam - if (i == 0 and j == 0) or \ - (i == nr-1 and j == nc-1): - d = diam*3 - self.addFace(hole(i,j,d), prefix="r-%d-%d" % (i,j)) - -if __name__ == "__main__": - Header.test() diff --git a/rocolib/library/ESPBrains.yaml b/rocolib/library/MountedBrains.yaml similarity index 58% rename from rocolib/library/ESPBrains.yaml rename to rocolib/library/MountedBrains.yaml index 36578232d530a1b44f683ed3831bffd26e929b49..aff7f4571405a33c673fc786fd3de74012fa9a7b 100644 --- a/rocolib/library/ESPBrains.yaml +++ b/rocolib/library/MountedBrains.yaml @@ -1,25 +1,12 @@ connections: connection0: - - &id001 - - beam + - - beam - face1 - - - header + - - brain - decoration - mode: hole offset: - function: (7.5, -4.5 + 0.5*(x[0]-getDim(x[1], 'length'))) - parameter: &id002 - - length - - brain - connection1: - - *id001 - - - servoPins - - decoration - - mode: hole - offset: - function: (-17.25, (0.5 * (x[0]-getDim(x[1], 'length')))-14) - parameter: *id002 - rotate: true + parameter: offset interfaces: botedge0: interface: botedge0 @@ -67,7 +54,43 @@ parameters: brain: defaultValue: nodeMCU spec: - valueType: str + overrides: + colsep: c.getParameter("brain").get("colsep") + ncols: c.getParameter("brain").get("ncols") + nrows: c.getParameter("brain").get("nrows") + rowsep: c.getParameter("brain").get("rowsep") + values: + nodeMCU: + colsep: 22.86 + extras: + servoPins: + center: + - -17.25 + - -14 + size: + - 8 + - 27 + height: 13 + length: 59.5 + ncols: 2 + nrows: 15 + origin: + - 7.5 + - -4.5 + rowsep: 2.54 + width: 44 + proMini: + colsep: 15.239999999999998 + extras: [] + height: 9 + length: 39 + ncols: 2 + nrows: 12 + origin: + - 0 + - 0 + rowsep: 2.54 + width: 19 depth: defaultValue: 20 spec: @@ -80,13 +103,18 @@ parameters: minValue: 0 units: mm valueType: (float, int) + offset: + defaultValue: + - 0 + - 0 + spec: {} width: defaultValue: 50 spec: minValue: 0 units: mm valueType: (float, int) -source: ../builders/ESPBrainsBuilder.py +source: ../builders/MountedBrainsBuilder.py subcomponents: beam: classname: SimpleRectBeam @@ -95,37 +123,21 @@ subcomponents: depth: parameter: width depth#minValue: - function: getDim(x, 'width') + function: x.get("width") parameter: brain length: parameter: length length#minValue: - function: getDim(x, 'length') + function: x.get("length") parameter: brain width: parameter: depth width#minValue: - function: getDim(x, 'height') + function: x.get("height") parameter: brain - header: - classname: Header + brain: + classname: Brains kwargs: {} parameters: - colsep: - function: getDim(x, 'colsep') - parameter: brain - ncols: - function: getDim(x, 'ncols') + brain: parameter: brain - nrows: - function: getDim(x, 'nrows') - parameter: brain - rowsep: - function: getDim(x, 'rowsep') - parameter: brain - servoPins: - classname: Cutout - kwargs: {} - parameters: - dx: 27 - dy: 8 diff --git a/rocolib/library/MountedServo.yaml b/rocolib/library/MountedServo.yaml index 2bcbbe856c365fb6e99e765ce77c4e9eb30eb08d..59533eae6be6fd4f0ed49668b961fc6a7479407d 100644 --- a/rocolib/library/MountedServo.yaml +++ b/rocolib/library/MountedServo.yaml @@ -138,7 +138,43 @@ parameters: servo: defaultValue: fs90r spec: - valueType: str + values: + ds2g: + horndepth: 1 + hornheight: 9 + hornlength: 11 + hornoffset: 4 + motorheight: 11 + motorlength: 17 + motorwidth: 8.5 + shoulderlength: 3.5 + fs90r: + horndepth: 2 + hornheight: 16 + hornlength: 10 + hornoffset: 8 + motorheight: 19 + motorlength: 23 + motorwidth: 13 + shoulderlength: 5 + s4303r: + horndepth: 2 + hornheight: 14 + hornlength: 38 + hornoffset: 7 + motorheight: 29 + motorlength: 31 + motorwidth: 17 + shoulderlength: 10 + tgy1370a: + horndepth: 2 + hornheight: 10 + hornlength: 7 + hornoffset: 4 + motorheight: 14 + motorlength: 20 + motorwidth: 9 + shoulderlength: 4 shift: defaultValue: 0 spec: diff --git a/rocolib/library/RectBeam.py b/rocolib/library/RectBeam.py index 12a323d930b73a635beb4066cf622199345bec8b..d61abc6d2f72e09967ae8763a4cd7799a17bbdb3 100644 --- a/rocolib/library/RectBeam.py +++ b/rocolib/library/RectBeam.py @@ -10,11 +10,11 @@ class RectBeam(FoldedComponent): self.addParameter("phase", 0, valueType="int") - self.addParameter("angle", optional=True, overrides=("tangle", "bangle")) + self.addParameter("angle", overrides=("tangle", "bangle")) self.addParameter("tangle", 80, paramType="angle", maxValue=180) self.addParameter("bangle", 135, paramType="angle", maxValue=180) - self.addParameter("root", 0, valueType="int", minValue=0) + self.addParameter("root", 0, values=[0,1,2,3]) self.addParameter("addTabs", True, valueType="bool") for i in range(4): @@ -25,17 +25,10 @@ class RectBeam(FoldedComponent): self.addEdgeInterface("slotedge", "r0.e3", "length") def assemble(self): - if self.getParameter("angle") is not None: - bangle = 90 - self.getParameter("angle") - tangle = 90 - self.getParameter("angle") - else: - bangle = 90 - self.getParameter("bangle") - tangle = 90 - self.getParameter("tangle") + bangle = 90 - self.getParameter("bangle") + tangle = 90 - self.getParameter("tangle") - try: - root = self.getParameter("root") - except KeyError: - root = None + root = self.getParameter("root") length = self.getParameter("length") width = self.getParameter("width") @@ -66,7 +59,7 @@ class RectBeam(FoldedComponent): fromEdge = None for i in range(4): - self.attachEdge(fromEdge, rs[i], "e3", prefix="r%d"%i, angle=90, root=((i == root) if root is not None else False)) + self.attachEdge(fromEdge, rs[i], "e3", prefix="r%d"%i, angle=90, root=((i == root))) fromEdge = 'r%d.e1' % i self.setFaceInterface("face%d" % i, "r%d" % ((i-phase)%4)) diff --git a/rocolib/library/ServoMotor.py b/rocolib/library/ServoMotor.py index 954d2a97de209b5d2389449824e6c18022b3f4ab..dafdd4ed9a30dbd859e7b27751bfd5749b61a5b8 100644 --- a/rocolib/library/ServoMotor.py +++ b/rocolib/library/ServoMotor.py @@ -2,28 +2,99 @@ from rocolib.api.components import FoldedComponent from rocolib.api.composables.graph.Face import Rectangle as Shape from rocolib.api.ports import AnchorPort from rocolib.utils.utils import decorateGraph -from rocolib.utils.dimensions import getDim from rocolib.utils.transforms import Translate, RotateZ from rocolib.utils.numsym import dot class ServoMotor(FoldedComponent): - def define(self): - self.addParameter("angle", 0, paramType="angle", minValue=None, maxValue=None) - self.addParameter("servo", "fs90r", paramType="dimension") - self.addInterface("mount", AnchorPort(self, self.getGraph(), "horn", Translate([0,0,0]))) - self.addFaceInterface("horn", "horn") - - def assemble(self): - s = self.getParameter("servo") - a = self.getParameter("angle") - dz = getDim(s, "hornheight") - dy = getDim(s, "motorlength") / 2 - getDim(s, "hornoffset") - - f = Shape("horn", 0, 0) - decorateGraph(f, Shape("hole", 1, 1)) - self.addFace(f) - self.setInterface("mount", AnchorPort(self, self.getGraph(), "horn", dot(RotateZ(a), Translate([0,-dy,dz])))) + def define(self): + self.addParameter("angle", 0, paramType="angle", minValue=None, maxValue=None) + self.addParameter("servo", "fs90r", values=ServoMotor.dims) + self.addInterface("mount", AnchorPort(self, self.getGraph(), "horn", Translate([0,0,0]))) + self.addFaceInterface("horn", "horn") + + def assemble(self): + s = self.getParameter("servo") + a = self.getParameter("angle") + dz = s.get("hornheight") + dy = s.get("motorlength") / 2 - s.get("hornoffset") + + f = Shape("horn", 0, 0) + decorateGraph(f, Shape("hole", 1, 1)) + self.addFace(f) + self.setInterface("mount", AnchorPort(self, self.getGraph(), "horn", dot(RotateZ(a), Translate([0,-dy,dz])))) + + + ''' + Servo dimension parameters: + + |<-G->| + ^ =====v===== { H + E _I_ + v ________| | |_____ + ^ | |<-F->|<> D + | | | + B | <--- A ---> | + | | (X) C | + v |_____________| + + A : motorlength + B : motorheight + C : motorwidth + D : shoulderlength + + E : hornheight + F : hornoffset + + G : hornlength + H : horndepth + + ''' + + dims = dict( + ds2g = dict( + motorlength = 17, + motorwidth = 8.5, + motorheight = 11, + shoulderlength= 3.5, + hornlength = 11, + hornheight = 9, + hornoffset = 4, + horndepth = 1, + ), + s4303r = dict( + motorlength = 31, + motorwidth = 17, + motorheight = 29, + shoulderlength= 10, + hornlength = 38, + hornheight = 14, + hornoffset = 7, + horndepth = 2, + ), + tgy1370a = dict( + motorlength = 20, + motorwidth = 9, + motorheight = 14, + shoulderlength= 4, + hornlength = 7, + hornheight = 10, + hornoffset = 4, + horndepth = 2, + ), + fs90r = dict( + motorlength = 23, + motorwidth = 13, + motorheight = 19, + shoulderlength= 5, + hornlength = 10, + hornheight = 16, + hornoffset = 8, + horndepth = 2, + ), + ) + if __name__ == "__main__": ServoMotor.test() + print(ServoMotor.dims) diff --git a/rocolib/library/ServoMount.py b/rocolib/library/ServoMount.py index 88bc3127a65d5ac36794ee92577399a05a7ff299..0c88010a1f4e2f536622348aa8162c3a548a925a 100644 --- a/rocolib/library/ServoMount.py +++ b/rocolib/library/ServoMount.py @@ -1,6 +1,5 @@ from rocolib.api.components.Component import Component from rocolib.api.ports.EdgePort import EdgePort -from rocolib.utils.dimensions import getDim from rocolib.api.Function import Function @@ -13,9 +12,9 @@ class ServoMount(Component): l = self.getParameter("length") - ml = getDim(servo, "motorlength") - sl = getDim(servo, "shoulderlength") - ho = getDim(servo, "hornoffset") + ml = servo.get("motorlength") + sl = servo.get("shoulderlength") + ho = servo.get("hornoffset") s = self.getParameter("shift") diff --git a/rocolib/library/ServoMount.yaml b/rocolib/library/ServoMount.yaml index 9aa85d0a9c0343683df7bf9cd76862ac8c6781bf..45d9c9e63ebbef06b611ffa8755129071419b4df 100644 --- a/rocolib/library/ServoMount.yaml +++ b/rocolib/library/ServoMount.yaml @@ -78,7 +78,43 @@ parameters: servo: defaultValue: fs90r spec: - valueType: str + values: + ds2g: + horndepth: 1 + hornheight: 9 + hornlength: 11 + hornoffset: 4 + motorheight: 11 + motorlength: 17 + motorwidth: 8.5 + shoulderlength: 3.5 + fs90r: + horndepth: 2 + hornheight: 16 + hornlength: 10 + hornoffset: 8 + motorheight: 19 + motorlength: 23 + motorwidth: 13 + shoulderlength: 5 + s4303r: + horndepth: 2 + hornheight: 14 + hornlength: 38 + hornoffset: 7 + motorheight: 29 + motorlength: 31 + motorwidth: 17 + shoulderlength: 10 + tgy1370a: + horndepth: 2 + hornheight: 10 + hornlength: 7 + hornoffset: 4 + motorheight: 14 + motorlength: 20 + motorwidth: 9 + shoulderlength: 4 shift: defaultValue: 0 spec: @@ -94,23 +130,23 @@ subcomponents: addTabs: parameter: addTabs depth: - function: getDim(x, "motorheight") + function: x.get("motorheight") parameter: servo length: parameter: length length#minValue: - function: getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength") + function: x.get("motorlength") + 2 * x.get("shoulderlength") parameter: servo width: - function: getDim(x, "motorwidth") + function: x.get("motorwidth") parameter: servo mount: classname: Cutout kwargs: {} parameters: dx: - function: getDim(x, "motorwidth") * 0.99 + function: x.get("motorwidth") * 0.99 parameter: servo dy: - function: getDim(x, "motorlength") + function: x.get("motorlength") parameter: servo diff --git a/rocolib/library/Stool.py b/rocolib/library/Stool.py index a7d4165d83199419a49f285b620fb337193dd2a6..92db4e3a7caeb02086847cf747f1a12e2f0f8799 100644 --- a/rocolib/library/Stool.py +++ b/rocolib/library/Stool.py @@ -9,7 +9,7 @@ class Stool(FoldedComponent): self.addParameter("height", 60, paramType="length", minValue=10) self.addParameter("legs", 3, paramType="count", minValue=1) self.addParameter("radius", minValue=10, overrides={ - "legwidth": lambda c: r2l.r2l(c.getParameter("radius"), c.getParameter("legs")*2) + "legwidth": 'c.getParameter("radius") * 2 * np.sin( np.pi() / c.getParameter("legs") / 2)', }) self.addParameter("legwidth", 20, paramType="length", minValue=9) self.addParameter("angle", 80, paramType="angle") diff --git a/rocolib/library/ThruHole.py b/rocolib/library/ThruHole.py new file mode 100644 index 0000000000000000000000000000000000000000..b61671480639d9731fe14a335c8ff7e73eee81e2 --- /dev/null +++ b/rocolib/library/ThruHole.py @@ -0,0 +1,35 @@ +from rocolib.api.components import DecorationComponent +from rocolib.api.composables.graph.Face import Face + + +class ThruHole(DecorationComponent): + + def define(self): + self.addParameter("nrows", 3, paramType="count") + self.addParameter("ncols", 1, paramType="count") + self.addParameter("rowsep", 2.54, paramType="length") + self.addParameter("colsep", 2.54, paramType="length") + self.addParameter("diameter", 1, paramType="length") + + def assemble(self): + diam = self.getParameter("diameter")/2. + nr = self.getParameter("nrows") + nc = self.getParameter("ncols") + + def hole(i, j, d): + dx = (j - (nc-1)/2.)*self.getParameter("colsep") + dy = (i - (nr-1)/2.)*self.getParameter("rowsep") + return Face("r-%d-%d" % (i,j), + ((dx-d, dy-d), (dx+d, dy-d), (dx+d, dy+d), (dx-d, dy+d)), + recenter=False) + + for i in range(nr): + for j in range(nc): + d = diam + if (i == 0 and j == 0) or \ + (i == nr-1 and j == nc-1): + d = diam*3 + self.addFace(hole(i,j,d), prefix="r-%d-%d" % (i,j)) + +if __name__ == "__main__": + ThruHole.test() diff --git a/rocolib/library/UChannel.py b/rocolib/library/UChannel.py index 088b9acbf4c0694e6b1a95d4dbad2af19edf4a41..f2ede902bc4d84bdbc9f4255d580a0f90e033c87 100644 --- a/rocolib/library/UChannel.py +++ b/rocolib/library/UChannel.py @@ -11,10 +11,7 @@ class UChannel(FoldedComponent): # Minimum of 45deg to make sure the geometry stays convex self.addParameter("tangle", 80, paramType="angle", minValue=45) self.addParameter("bangle", 135, paramType="angle", minValue=45) - self.addParameter("angle", paramType="angle", minValue=45, overrides={ - "bangle": lambda c : c.getParameter("angle"), - "tangle": lambda c : c.getParameter("angle"), - }) + self.addParameter("angle", paramType="angle", minValue=45, overrides=("bangle", "tangle")) for i in range(3): self.addEdgeInterface("topedge%d" % i, "r%d.e0" % i, ["depth", "width"][i % 2]) diff --git a/rocolib/library/Wheel.yaml b/rocolib/library/Wheel.yaml index f902aa7f8e451b6254f78e167f1f747a333f9a4c..6de1d93af4b845fe912b2cf84b60e44275325bc3 100644 --- a/rocolib/library/Wheel.yaml +++ b/rocolib/library/Wheel.yaml @@ -144,7 +144,43 @@ parameters: servo: defaultValue: fs90r spec: - valueType: str + values: + ds2g: + horndepth: 1 + hornheight: 9 + hornlength: 11 + hornoffset: 4 + motorheight: 11 + motorlength: 17 + motorwidth: 8.5 + shoulderlength: 3.5 + fs90r: + horndepth: 2 + hornheight: 16 + hornlength: 10 + hornoffset: 8 + motorheight: 19 + motorlength: 23 + motorwidth: 13 + shoulderlength: 5 + s4303r: + horndepth: 2 + hornheight: 14 + hornlength: 38 + hornoffset: 7 + motorheight: 29 + motorlength: 31 + motorwidth: 17 + shoulderlength: 10 + tgy1370a: + horndepth: 2 + hornheight: 10 + hornlength: 7 + hornoffset: 4 + motorheight: 14 + motorlength: 20 + motorwidth: 9 + shoulderlength: 4 shift: defaultValue: 0 spec: diff --git a/rocolib/utils/dimensions.py b/rocolib/utils/dimensions.py deleted file mode 100644 index 4d87f57f6335a69363889b7f6f15bd43d22ed6e9..0000000000000000000000000000000000000000 --- a/rocolib/utils/dimensions.py +++ /dev/null @@ -1,156 +0,0 @@ -from sympy import symbols - -dims = {} - -def isDim(obj): - return obj in dims - -def getDim(obj, param): - return dims[obj][param] - -''' -Brain dimension parameters: - params.setdefault("length") - params.setdefault("width") - params.setdefault("height") - - params.setdefault("nrows") - params.setdefault("ncols") - params.setdefault("rowsep") - params.setdefault("colsep") -''' -dims["proMini"] = { "type" : "brains", - "length" : 39, - "width" : 19, - "height" : 9, - "nrows" : 12, - "ncols" : 2, - "rowsep" : 0.1 * 25.4, - "colsep" : 0.6 * 25.4, -} - -dims["nodeMCU"] = { "type" : "brains", - "length" : 59.5, - "width" : 44, - "height" : 13, - "nrows" : 15, - "ncols" : 2, - "rowsep" : 0.1 * 25.4, - "colsep" : 0.9 * 25.4, -} - -''' -Servo dimension parameters: - - |<-G->| -^ =====v===== { H -E _I_ -v ________| | |_____ - ^ | |<-F->|<> D - | | | - B | <--- A ---> | - | | (X) C | - v |_____________| - -A : motorlength -B : motorheight -C : motorwidth -D : shoulderlength - -E : hornheight -F : hornoffset - -G : hornlength -H : horndepth - - params.setdefault("motorlength") - params.setdefault("motorwidth") - params.setdefault("motorheight") - params.setdefault("shoulderlength", 0) - - params.setdefault("hornheight", 0) - params.setdefault("hornoffset", 0) - - params.setdefault("hornlength", 0) - params.setdefault("horndepth", 0) - -If horn is not symmetric? - - params.setdefault("rhornlength", 0) - params.setdefault("lhornlength", 0) - if name == "hornlength": - self.setParameter("rhornlength", val) - self.setParameter("lhornlength", val) - -Should horn be a different object? - -''' - -dims["ds2g"] = { "type" : "servo", - "motorlength" : 17, - "motorwidth" : 8.5, - "motorheight" : 11, - "shoulderlength": 3.5, - "hornlength" : 11, - "hornheight" : 9, - "hornoffset" : 4, - "horndepth" : 1, -} - -dims["s4303r"] = { "type" : "servo", - "motorlength" : 31, - "motorwidth" : 17, - "motorheight" : 29, - "shoulderlength": 10, - "hornlength" : 38, - "hornheight" : 14, - "hornoffset" : 7, - "horndepth" : 2, -} - -dims["tgy1370a"] = { "type" : "servo", - "motorlength" : 20, - "motorwidth" : 9, - "motorheight" : 14, - "shoulderlength": 4, - "hornlength" : 7, - "hornheight" : 10, - "hornoffset" : 4, - "horndepth" : 2, -} - -dims["fs90r"] = { "type" : "servo", - "motorlength" : 23, - "motorwidth" : 13, - "motorheight" : 19, - "shoulderlength": 5, - "hornlength" : 10, - "hornheight" : 16, - "hornoffset" : 8, - "horndepth" : 2, -} - -l, w, h, r, c, rs, cs = symbols("brainLength brainWidth brainHeight brainNRows brainNCols brainRowSep brainColSep", positive=True) - -dims["brainSymbols"] = { "type" : "brains", - "length" : l, - "width" : w, - "height" : h, - "nrows" : r, - "ncols" : c, - "rowsep" : rs, - "colsep" : cs, -} - -l, w, h, s, hl, hh, ho, hd = symbols("servoLength servoWidth servoHeight servoShoulder servoHornLength servoHornHeight servoHornOffset servoHornDepth", positive=True) - -dims["servoSymbols"] = { "type" : "servo", - "motorlength" : l, - "motorwidth" : w, - "motorheight" : h, - "shoulderlength": s, - "hornlength" : hl, - "hornheight" : hh, - "hornoffset" : ho, - "horndepth" : hd, -}