From 2d5b4b462741ffec9efa90958158b8672bd3aa64 Mon Sep 17 00:00:00 2001
From: pjil27 <jillpantigcs@gmail.com>
Date: Sun, 17 Oct 2021 14:49:23 -0700
Subject: [PATCH] Adding new pivot and differential car (redo)

---
 rocolib/builders/BoatBaseBuilder.py    |  15 +
 rocolib/builders/CentipedeBuilder.py   |  98 +++++
 rocolib/builders/HalfCarBuilder.py     |  90 +++++
 rocolib/builders/HingeServoBuilder.py  |  43 +++
 rocolib/builders/NWheeledCarBuilder.py |  38 ++
 rocolib/builders/PivotCarBuilder.py    |  74 ++++
 rocolib/library/Centipede.yaml         | 493 +++++++++++++++++++++++++
 rocolib/library/HalfCar.py             |  12 +
 rocolib/library/HalfCar.yaml           | 420 +++++++++++++++++++++
 rocolib/library/HingeServo.yaml        | 209 +++++++++++
 rocolib/library/NWheeledCar.py         |  13 +
 rocolib/library/NWheeledCar.yaml       | 122 ++++++
 rocolib/library/PivotCar.yaml          | 201 ++++++++++
 rocolib/library/RightTriangle.py       |  28 ++
 rocolib/library/Tire.py                |  70 ++++
 15 files changed, 1926 insertions(+)
 create mode 100644 rocolib/builders/BoatBaseBuilder.py
 create mode 100644 rocolib/builders/CentipedeBuilder.py
 create mode 100644 rocolib/builders/HalfCarBuilder.py
 create mode 100644 rocolib/builders/HingeServoBuilder.py
 create mode 100644 rocolib/builders/NWheeledCarBuilder.py
 create mode 100644 rocolib/builders/PivotCarBuilder.py
 create mode 100644 rocolib/library/Centipede.yaml
 create mode 100644 rocolib/library/HalfCar.py
 create mode 100644 rocolib/library/HalfCar.yaml
 create mode 100644 rocolib/library/HingeServo.yaml
 create mode 100644 rocolib/library/NWheeledCar.py
 create mode 100644 rocolib/library/NWheeledCar.yaml
 create mode 100644 rocolib/library/PivotCar.yaml
 create mode 100644 rocolib/library/RightTriangle.py
 create mode 100644 rocolib/library/Tire.py

diff --git a/rocolib/builders/BoatBaseBuilder.py b/rocolib/builders/BoatBaseBuilder.py
new file mode 100644
index 0000000..6007f07
--- /dev/null
+++ b/rocolib/builders/BoatBaseBuilder.py
@@ -0,0 +1,15 @@
+from rocolib.api.components.Component import Component
+
+c = Component()
+
+c.addSubcomponent("boat","SimpleUChannel", inherit=True)
+c.addSubcomponent("bow","BoatPoint", inherit=True)
+c.addSubcomponent("stern","BoatPoint", inherit=True)
+
+c.join(("boat", "top"), ("bow", "edge"))
+c.join(("boat", "bot"), ("stern", "edge"))
+
+c.inheritInterface("portedge", ("boat", "ledge"))
+c.inheritInterface("staredge", ("boat", "redge"))
+
+c.toLibrary("BoatBase")
diff --git a/rocolib/builders/CentipedeBuilder.py b/rocolib/builders/CentipedeBuilder.py
new file mode 100644
index 0000000..5e275f2
--- /dev/null
+++ b/rocolib/builders/CentipedeBuilder.py
@@ -0,0 +1,98 @@
+from rocolib.api.components.Component import Component
+
+c = Component()
+
+#NEEDS CLEANING
+#Don't change n yet, haven't figured out how to make it n-wheeled
+#8-Wheeled Pivot Car
+n = 3 #(number of wheels - 1)/2
+c.addParameter("length", 76, paramType="length", minValue=76) #tested minValue
+c.addParameter("height", 36, paramType="length", minValue=36) #tested minValue
+c.addParameter("width", 60, paramType="length", minValue=60) #tested minValue
+
+for i in range(n - 1):
+    c.addSubcomponent("front%d" %i, "HalfCar")
+    c.addConstraint(("front%d" %i, "length"), "length")
+    c.addConstraint(("front%d" %i, "height"), "height")
+    c.addConstraint(("front%d" %i, "width"), "width")
+    c.addSubcomponent("middle%d" %i, "HalfCar")
+    c.addConstraint(("middle%d" %i, "length"), "length")
+    c.addConstraint(("middle%d" %i, "height"), "height")
+    c.addConstraint(("middle%d" %i, "width"), "width")
+
+#Main component of steering wheel car which makes them moveable: trapezoid that connects the two half of the car
+for i in range(4 * n):
+    c.addSubcomponent("midsupport%d" %i, "Trapezoid")
+    c.addConstraint(("midsupport%d" %i, "width"), "width", "x-10")
+    c.addConstraint(("midsupport%d" %i, "depth"), "width", "x-37")
+    c.addConstraint(("midsupport%d" %i, "bangle"), "width",
+                    "float(np.atan((x-37)/5)* 180 * 0.318309)")
+
+c.addConnection(("middle1", "rect4.l"), ("midsupport0", "botedge"))
+c.addConnection(("middle1", "rect4.r"), ("midsupport1", "botedge"))
+c.addConnection(("front1", "rect4.l"), ("midsupport2", "botedge"))
+
+c.addConnection(("middle1", "rect3.r"), ("midsupport3", "botedge"))
+c.addConnection(("middle1", "rect3.l"), ("midsupport4", "botedge"))
+c.addConnection(("front1", "rect3.l"), ("midsupport5", "botedge"))
+
+c.addConnection(("middle0", "rect4.l"), ("midsupport6", "botedge"))
+c.addConnection(("middle0", "rect4.r"), ("midsupport7", "botedge"))
+c.addConnection(("front0", "rect4.l"), ("midsupport8", "botedge"))
+
+c.addConnection(("middle0", "rect3.r"), ("midsupport9", "botedge"))
+c.addConnection(("middle0", "rect3.l"), ("midsupport10", "botedge"))
+c.addConnection(("front0", "rect3.l"), ("midsupport11", "botedge"))
+
+c.addConnection(("midsupport4", "topedge"), ("midsupport5", "topedge"))
+c.addConnection(("midsupport10", "topedge"), ("midsupport11", "topedge"))
+c.addConnection(("midsupport9", "topedge"), ("midsupport3", "topedge"))
+
+#Putting the brains in front component of the car
+c.addParameter("brains", "esp32stack", paramType="dimension")
+c.addParameter("driveservo", "fs90r", paramType="dimension")
+
+for i in range(2):
+    c.addSubcomponent("split%d" %i, "SplitEdge")
+    c.addConstraint(("split%d" % i, "toplength"), "length", '(x,)')
+    c.addConstraint(("split%d" % i, "botlength"), ("length", "height"),
+                    '(x[1], x[0]-x[1])')
+    c.addSubcomponent("holder%d" %i, "ESP32Stack")
+    c.addConstraint(("holder%d" %i, "length"), "width")
+    c.addConstraint(("holder%d" %i, "heightChanger"), ("brains", "height"), ("x[1] - getDim(x[0], 'height')"))
+    c.addConstraint(("holder%d" %i, "length"), "width")
+
+c.addConnection(("front0", "rect3.t"), ("split0", "topedge0"))
+c.addConnection(("front1", "rect3.t"), ("split1", "topedge0"))
+
+c.addConnection(("holder0", "rect2.t"), ("front0", "rect2.r"), angle=-90)
+c.addConnection(("holder1", "rect2.t"), ("front1", "rect2.r"), angle=-90)
+
+#Putting servo hinge between cars
+for i in range(3):
+    c.addSubcomponent("hinge%d" %i, "HingeServo")
+    c.addConstraint(("hinge%d" % i, "length"), "length")
+    c.addConstraint(("hinge%d" % i, "width"), "width")
+    c.addSubcomponent("hingeSplit%d" %i, "SplitEdge")
+    c.addConstraint(("hingeSplit%d" %i, "toplength"), "height", '(x,)')
+    c.addConstraint(("hingeSplit%d" %i, "botlength"), ("height", "driveservo"),
+                        '((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"), '
+                        '(x[0]-getDim(x[1], "motorheight"))/2)')
+
+c.addSubcomponent("rectAssist", "Rectangle")
+c.addConstraint(("rectAssist", "l"), "driveservo", 'getDim(x, "motorheight")')
+c.addConstraint(("rectAssist", "w"), "length")
+
+c.addConnection(("front0", "rect1.r"), ("hingeSplit0", "topedge0"))
+c.addConnection(("hingeSplit0", "botedge1"), ("hinge0", "belt2.r"), angle=-90)
+
+c.addConnection(("middle1", "rect1.r"), ("hingeSplit1", "topedge0"))
+c.addConnection(("hingeSplit1", "botedge1"), ("hinge1", "belt2.r"), angle=-90)
+
+c.addConnection(("middle0", "rect2.r"), ("hingeSplit2", "topedge0"))
+c.addConnection(("hingeSplit2", "botedge1"), ("rectAssist", "t"), angle=-180)
+c.addConnection(("rectAssist", "b"), ("hinge2", "belt0.r"), angle=90)
+
+# c.addConnection(("hinge0", "servo.mount"), ("midsupport4", "face0"))
+
+c.toLibrary("Centipede")
diff --git a/rocolib/builders/HalfCarBuilder.py b/rocolib/builders/HalfCarBuilder.py
new file mode 100644
index 0000000..f4538c9
--- /dev/null
+++ b/rocolib/builders/HalfCarBuilder.py
@@ -0,0 +1,90 @@
+from rocolib.api.components.Component import Component
+
+c = Component()
+
+#Parameters for the sheath that would cover the wheels and the ESP32 Stack
+#Parameters that will change the dimension of the car
+c.addParameter("length", 76, paramType="length", minValue=65) #tested minValue
+c.addParameter("height", 36, paramType="length", minValue=36) #tested minValue
+c.addParameter("width", 60, paramType="length", minValue=60) #tested minValue
+
+#This car will use the customized ESP32 stack in dimensions.py and the FS90R servo
+#Change here if you have another board
+c.addParameter("driveservo", "fs90r", paramType="dimension")
+c.addParameter("brains", "esp32stack", paramType="dimension")
+
+#Cover/body of the car (I needed one that folds -90; will try on SimpleRectBeam)
+for i in range(1, 3):
+    c.addSubcomponent("rect%d" %i, "Rectangle")
+    c.addConstraint(("rect%d" %i, "l"), "length")
+    c.addConstraint(("rect%d" %i, "w"), "height")
+
+for i in range(3, 5):
+    c.addSubcomponent("rect%d" %i, "Rectangle")
+    c.addConstraint(("rect%d" %i, "l"), "length")
+    c.addConstraint(("rect%d" %i, "w"), "width")
+
+#TODO: ADD TABS FOR ATTACHMENT
+# c.addConnection(("rect2", "b"), ("rect3", "t"), angle=90)
+c.addConnection(("rect3", "b"), ("rect1", "b"), angle=-90)
+c.addConnection(("rect2", "b"), ("rect4", "b"), angle=-90)
+c.addConnection(("rect4", "t"), ("rect1", "t"), angle=-90)
+
+#Attaching servos to the car
+c.addSubcomponent("rect0", "Rectangle")
+c.addConstraint(("rect0", "l"), ("height", "driveservo"), "x[0]-getDim(x[1], 'motorwidth')")
+c.addConstraint(("rect0", "w"), "driveservo", "getDim(x, 'motorwidth')")
+
+c.addSubcomponent("sheathsplit", "SplitEdge")
+c.addConstraint(("sheathsplit", "toplength"), "length", "(x,)")
+c.addConstraint(("sheathsplit", "botlength"), ("length", "driveservo"), "(x[0] * 0.0691, getDim(x[1], 'motorwidth'), "
+                                                                        "(x[0]-(getDim(x[1], 'motorwidth') + x[0] * 0.0691)))")
+
+c.addConnection(("sheathsplit", "topedge0"), ("rect2", "t"))
+c.addConnection(("sheathsplit", "botedge1"), ("rect0", "r"), angle=180)
+
+for i in range(2):
+    c.addSubcomponent("rTriangle%d" %i, "RightTriangle")
+    c.addConstraint(("rTriangle%d" %i, "base"), "driveservo", "getDim(x, 'motorwidth')")
+    c.addConstraint(("rTriangle%d" %i, "height"), "driveservo", "getDim(x, 'motorwidth')")
+
+c.addConnection(("rect0", "l"), ("rTriangle0", "bedge"))
+c.addConnection(("rTriangle0", "hedge"), ("rTriangle1", "hedge"), angle=180)
+
+#Four wheels using Wheel.yaml
+c.addSubcomponent("fleft", "Wheel", invert=True, inherit="angle")
+c.addSubcomponent("bright", "Wheel", invert=True, inherit="angle")
+
+#Setting the parameters for the Wheels
+for servo in ("bright", "fleft"):
+    c.addConstraint((servo, "servo"), "driveservo")
+    c.addConstraint((servo, "length"), ("length", "brains"), '((x[0] - getDim(x[1], "width")))')
+    c.addConstConstraint((servo, "center"), False)
+    c.addConstraint((servo, "radius"), "brains", '(getDim(x, "height") / 1.35)')
+
+#Support for the middle of the front and back wheels so that they won't collapse or wiggle
+for i in range(1, 3):
+    c.addSubcomponent("between%d" %i, "SimpleRectBeam")
+    c.addConstraint(("between%d" %i, "length"), ("width", "driveservo"), "x[0]- 2 * getDim(x[1], 'motorheight')")
+    c.addConstraint(("between%d" % i, "depth"), "driveservo", "getDim(x, 'motorwidth')")
+    c.addConstraint(("between%d" % i, "width"), "driveservo", "getDim(x, 'motorwidth')")
+
+#Back between support
+c.addConnection(("fleft", "topedge2"), ("between1", "topedge1"), angle=90)
+c.addConnection(("between1", "botedge1"), ("bright", "botedge2"), angle=90)
+c.addConnection(("between2", "topedge1"), ("bright", "topedge2"), angle=90)
+c.addConnection(("between2", "botedge1"), ("fleft", "botedge2"), angle=90, tabWidth=10)
+
+# Flipping right wheels to match the orientation of left wheels
+c.addConstConstraint(("bright", "flip"), True)
+
+c.addConnection(("rTriangle1", "bedge"), ("fleft", "botedge0"))
+
+c.inheritAllInterfaces("fleft")
+c.inheritAllInterfaces("bright")
+c.inheritAllInterfaces("rect1")
+c.inheritAllInterfaces("rect2")
+c.inheritAllInterfaces("rect3")
+c.inheritAllInterfaces("rect4")
+
+c.toLibrary("HalfCar")
\ No newline at end of file
diff --git a/rocolib/builders/HingeServoBuilder.py b/rocolib/builders/HingeServoBuilder.py
new file mode 100644
index 0000000..76b4c2d
--- /dev/null
+++ b/rocolib/builders/HingeServoBuilder.py
@@ -0,0 +1,43 @@
+
+from rocolib.api.components.Component import Component
+
+c = Component()
+
+c.addParameter("length", 76, paramType="length", minValue=65) #tested minValue
+c.addParameter("width", 60, paramType="length", minValue=60) #tested minValue
+
+c.addSubcomponent("servo", "MountedServo")
+c.addParameter("driveservo", "fs90r", paramType="dimension")
+c.addConstraint(("servo", "servo"), "driveservo")
+c.addConstraint(("servo", "length"), "driveservo", 'getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")')
+c.addConstConstraint(("servo", "center"), False)
+
+for i in range(5):
+    c.addSubcomponent("belt%d" %i, "Rectangle")
+    c.addConstraint(("belt%d"%i, "w"), "driveservo", 'getDim(x, "motorheight")')
+
+for i in range(3):
+    c.addConstraint(("belt%d"%i, "l"), ("width", "driveservo"), "(x[0]-getDim(x[1], 'motorwidth'))/2")
+
+for i in range(3, 5):
+    c.addConstraint(("belt%d" % i, "l"), "driveservo", 'getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")')
+
+# for i in range(6, 10):
+#     c.addConstraint(("belt%d"%i, "l"), "length")
+
+c.addConnection(("servo", "botedge3"), ("belt0", "l"), angle=-90)
+c.addConnection(("servo", "botedge1"), ("belt1", "l"), angle=-90)
+c.addConnection(("servo", "topedge1"), ("belt3", "l"), angle=-180)
+c.addConnection(("servo", "topedge3"), ("belt4", "l"), angle=-180)
+c.addConnection(("belt2", "l"), ("belt4", "r"), angle=90)
+
+# c.addConnection(("belt0", "r"), ("belt6", "l"), angle=90)
+# c.addConnection(("belt1", "r"), ("belt7", "l"), angle=90)
+# c.addConnection(("belt2", "r"), ("belt8", "l"), angle=-90)
+# c.addConnection(("belt3", "r"), ("belt9", "l"), angle=-90)
+
+c.inheritAllInterfaces("servo")
+for i in range(3):
+    c.inheritAllInterfaces("belt%d" %i)
+
+c.toLibrary("HingeServo")
\ No newline at end of file
diff --git a/rocolib/builders/NWheeledCarBuilder.py b/rocolib/builders/NWheeledCarBuilder.py
new file mode 100644
index 0000000..020c965
--- /dev/null
+++ b/rocolib/builders/NWheeledCarBuilder.py
@@ -0,0 +1,38 @@
+from rocolib.api.components.Component import Component
+
+c = Component()
+#N-WHEELED CAR (10-wheeed car)
+#Probably need to additional microcontroller in the middle for N > 8
+n = 4 #(number of wheels/2) - 1
+c.addParameter("length", 76, paramType="length", minValue=76) #tested minValue
+c.addParameter("height", 36, paramType="length", minValue=36) #tested minValue
+c.addParameter("width", 60, paramType="length", minValue=60) #tested minValue
+
+c.addSubcomponent("front", "HalfCar") #must always have a front car for the brains
+c.addConstraint(("front", "length"), "length")
+c.addConstraint(("front", "height"), "height")
+c.addConstraint(("front", "width"), "width")
+
+#Connecting Each Car
+for i in range(n):
+    c.addSubcomponent("car%d" %i, "HalfCar")
+    c.addConstraint(("car%d" %i, "length"), "length")
+    c.addConstraint(("car%d" %i, "height"), "height")
+    c.addConstraint(("car%d" %i, "width"), "width")
+
+for i in range(n - 1):
+    c.addConnection(("car%d" %i, "rect4.l"), ("car%d" %(i+1), "rect4.r"))
+
+c.addConnection(("front", "rect4.l"), ("car%d" %(n-1), "rect4.l"))
+
+#Putting the brains in the front of the car
+c.addParameter("brains", "esp32stack", paramType="dimension")
+c.addParameter("driveservo", "fs90r", paramType="dimension")
+c.addSubcomponent("holder", "ESP32Stack")
+
+c.addConstraint(("holder", "heightChanger"), ("brains", "height"), ("x[1] - getDim(x[0], 'height')"))
+c.addConstraint(("holder", "length"), "width")
+
+c.addConnection(("holder", "rect2.t"), ("front", "rect2.l"), angle=-90)
+
+c.toLibrary("NWheeledCar")
diff --git a/rocolib/builders/PivotCarBuilder.py b/rocolib/builders/PivotCarBuilder.py
new file mode 100644
index 0000000..ede468d
--- /dev/null
+++ b/rocolib/builders/PivotCarBuilder.py
@@ -0,0 +1,74 @@
+from rocolib.api.components.Component import Component
+
+c = Component()
+
+#NEEDS CLEANING
+#Don't change n yet, haven't figured out how to make it n-wheeled
+#4-wheeled pivot car
+n = 2
+c.addParameter("length", 76, paramType="length", minValue=76) #tested minValue
+c.addParameter("height", 36, paramType="length", minValue=36) #tested minValue
+c.addParameter("width", 60, paramType="length", minValue=60) #tested minValue
+
+for i in range(n - 1):
+    c.addSubcomponent("front%d" % i, "HalfCar")
+    c.addConstraint(("front%d" % i, "length"), "length")
+    c.addConstraint(("front%d" % i, "height"), "height")
+    c.addConstraint(("front%d" % i, "width"), "width")
+    c.addSubcomponent("middle%d" % i, "HalfCar")
+    c.addConstraint(("middle%d" % i, "length"), "length")
+    c.addConstraint(("middle%d" % i, "height"), "height")
+    c.addConstraint(("middle%d" % i, "width"), "width")
+
+#Main component of steering wheel car which makes them moveable: trapezoid that connects the two half of the car
+for i in range(4):
+    c.addSubcomponent("midsupport%d" %i, "Trapezoid")
+    c.addConstraint(("midsupport%d" %i, "width"), "width", "x-10")
+    c.addConstraint(("midsupport%d" %i, "depth"), "width", "x-37")
+    c.addConstraint(("midsupport%d" %i, "bangle"), "width",
+                    "float(np.atan((x-37)/5)* 180 * 0.318309)")
+
+c.addConnection(("middle0", "rect4.l"), ("midsupport0", "botedge"))
+c.addConnection(("front0", "rect4.l"), ("midsupport1", "botedge"))
+
+c.addConnection(("middle0", "rect3.l"), ("midsupport2", "botedge"))
+c.addConnection(("front0", "rect3.l"), ("midsupport3", "botedge"))
+
+c.addConnection(("midsupport2", "topedge"), ("midsupport3", "topedge"))
+
+#Putting the brains in front component of the car
+c.addParameter("brains", "esp32stack", paramType="dimension")
+c.addParameter("driveservo", "fs90r", paramType="dimension")
+
+for i in range(1):
+    c.addSubcomponent("split%d" % i, "SplitEdge")
+    c.addConstraint(("split%d" % i, "toplength"), "length", '(x,)')
+    c.addConstraint(("split%d" % i, "botlength"), ("length", "height"),
+                    '(x[1], x[0]-x[1])')
+    c.addSubcomponent("holder%d" % i, "ESP32Stack")
+    c.addConstraint(("holder%d" % i, "length"), "width")
+    c.addConstraint(("holder%d" % i, "heightChanger"), ("brains", "height"), ("x[1] - getDim(x[0], 'height')"))
+    c.addConstraint(("holder%d" % i, "length"), "width")
+
+c.addConnection(("front0", "rect3.t"), ("split0", "topedge0"))
+
+c.addConnection(("holder0", "rect2.t"), ("front0", "rect2.r"), angle=-90)
+
+#Putting servo hinge between cars
+for i in range(1):
+    c.addSubcomponent("hinge%d" % i, "HingeServo")
+    c.addConstraint(("hinge%d" % i, "length"), "length")
+    c.addConstraint(("hinge%d" % i, "width"), "width")
+    c.addSubcomponent("hingeSplit%d" % i, "SplitEdge")
+    c.addConstraint(("hingeSplit%d" % i, "toplength"), "height", '(x,)')
+    c.addConstraint(("hingeSplit%d" % i, "botlength"), ("height", "driveservo"),
+                    '((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"), '
+                    '(x[0]-getDim(x[1], "motorheight"))/2)')
+
+c.addConnection(("front0", "rect1.r"), ("hingeSplit0", "topedge0"))
+c.addConnection(("hingeSplit0", "botedge1"), ("hinge0", "belt2.r"), angle=-90)
+
+#Attach hinge on face of Trapezoid to move in Webots
+# c.addConnection(("hinge0", "servo.mount"), ("midsupport4", "face0"))
+
+c.toLibrary("PivotCar")
diff --git a/rocolib/library/Centipede.yaml b/rocolib/library/Centipede.yaml
new file mode 100644
index 0000000..11608fb
--- /dev/null
+++ b/rocolib/library/Centipede.yaml
@@ -0,0 +1,493 @@
+connections:
+  connection0:
+  - - middle1
+    - rect4.l
+  - - midsupport0
+    - botedge
+  - {}
+  connection1:
+  - - middle1
+    - rect4.r
+  - - midsupport1
+    - botedge
+  - {}
+  connection10:
+  - - middle0
+    - rect3.l
+  - - midsupport10
+    - botedge
+  - {}
+  connection11:
+  - - front0
+    - rect3.l
+  - - midsupport11
+    - botedge
+  - {}
+  connection12:
+  - - midsupport4
+    - topedge
+  - - midsupport5
+    - topedge
+  - {}
+  connection13:
+  - - midsupport10
+    - topedge
+  - - midsupport11
+    - topedge
+  - {}
+  connection14:
+  - - midsupport9
+    - topedge
+  - - midsupport3
+    - topedge
+  - {}
+  connection15:
+  - - front0
+    - rect3.t
+  - - split0
+    - topedge0
+  - {}
+  connection16:
+  - - front1
+    - rect3.t
+  - - split1
+    - topedge0
+  - {}
+  connection17:
+  - - holder0
+    - rect2.t
+  - - front0
+    - rect2.r
+  - angle: -90
+  connection18:
+  - - holder1
+    - rect2.t
+  - - front1
+    - rect2.r
+  - angle: -90
+  connection19:
+  - - front0
+    - rect1.r
+  - - hingeSplit0
+    - topedge0
+  - {}
+  connection2:
+  - - front1
+    - rect4.l
+  - - midsupport2
+    - botedge
+  - {}
+  connection20:
+  - - hingeSplit0
+    - botedge1
+  - - hinge0
+    - belt2.r
+  - angle: -90
+  connection21:
+  - - middle1
+    - rect1.r
+  - - hingeSplit1
+    - topedge0
+  - {}
+  connection22:
+  - - hingeSplit1
+    - botedge1
+  - - hinge1
+    - belt2.r
+  - angle: -90
+  connection23:
+  - - middle0
+    - rect2.r
+  - - hingeSplit2
+    - topedge0
+  - {}
+  connection24:
+  - - hingeSplit2
+    - botedge1
+  - - rectAssist
+    - t
+  - angle: -180
+  connection25:
+  - - rectAssist
+    - b
+  - - hinge2
+    - belt0.r
+  - angle: 90
+  connection3:
+  - - middle1
+    - rect3.r
+  - - midsupport3
+    - botedge
+  - {}
+  connection4:
+  - - middle1
+    - rect3.l
+  - - midsupport4
+    - botedge
+  - {}
+  connection5:
+  - - front1
+    - rect3.l
+  - - midsupport5
+    - botedge
+  - {}
+  connection6:
+  - - middle0
+    - rect4.l
+  - - midsupport6
+    - botedge
+  - {}
+  connection7:
+  - - middle0
+    - rect4.r
+  - - midsupport7
+    - botedge
+  - {}
+  connection8:
+  - - front0
+    - rect4.l
+  - - midsupport8
+    - botedge
+  - {}
+  connection9:
+  - - middle0
+    - rect3.r
+  - - midsupport9
+    - botedge
+  - {}
+interfaces: {}
+parameters:
+  brains:
+    defaultValue: esp32stack
+    spec:
+      valueType: str
+  driveservo:
+    defaultValue: fs90r
+    spec:
+      valueType: str
+  height:
+    defaultValue: 36
+    spec:
+      minValue: 36
+      units: mm
+      valueType: (float, int)
+  length:
+    defaultValue: 76
+    spec:
+      minValue: 76
+      units: mm
+      valueType: (float, int)
+  width:
+    defaultValue: 60
+    spec:
+      minValue: 60
+      units: mm
+      valueType: (float, int)
+source: ..\builders\CentipedeBuilder.py
+subcomponents:
+  front0:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  front1:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hinge0:
+    classname: HingeServo
+    kwargs: {}
+    parameters:
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hinge1:
+    classname: HingeServo
+    kwargs: {}
+    parameters:
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hinge2:
+    classname: HingeServo
+    kwargs: {}
+    parameters:
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hingeSplit0:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: ((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"),
+          (x[0]-getDim(x[1], "motorheight"))/2)
+        parameter: &id001
+        - height
+        - driveservo
+      toplength:
+        function: (x,)
+        parameter: height
+  hingeSplit1:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: ((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"),
+          (x[0]-getDim(x[1], "motorheight"))/2)
+        parameter: *id001
+      toplength:
+        function: (x,)
+        parameter: height
+  hingeSplit2:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: ((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"),
+          (x[0]-getDim(x[1], "motorheight"))/2)
+        parameter: *id001
+      toplength:
+        function: (x,)
+        parameter: height
+  holder0:
+    classname: ESP32Stack
+    kwargs: {}
+    parameters:
+      heightChanger:
+        function: x[1] - getDim(x[0], 'height')
+        parameter: &id002
+        - brains
+        - height
+      length:
+        parameter: width
+  holder1:
+    classname: ESP32Stack
+    kwargs: {}
+    parameters:
+      heightChanger:
+        function: x[1] - getDim(x[0], 'height')
+        parameter: *id002
+      length:
+        parameter: width
+  middle0:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  middle1:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  midsupport0:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport1:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport10:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport11:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport2:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport3:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport4:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport5:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport6:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport7:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport8:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport9:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  rectAssist:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+      w:
+        parameter: length
+  split0:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: (x[1], x[0]-x[1])
+        parameter: &id003
+        - length
+        - height
+      toplength:
+        function: (x,)
+        parameter: length
+  split1:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: (x[1], x[0]-x[1])
+        parameter: *id003
+      toplength:
+        function: (x,)
+        parameter: length
diff --git a/rocolib/library/HalfCar.py b/rocolib/library/HalfCar.py
new file mode 100644
index 0000000..3becff5
--- /dev/null
+++ b/rocolib/library/HalfCar.py
@@ -0,0 +1,12 @@
+from rocolib.api.components import Component
+from rocolib.utils.utils import copyDecorations2
+
+class HalfCar(Component):
+    def assemble(self):
+        copyDecorations2(self, ("fleftservoface", ("fleft", "face0", -1)),
+                        ("fleftservosheath", ("rect2", "face", 0)), 90)
+        copyDecorations2(self, ("brightservoface", ("fleft", "face0", 0)),
+                         ("brightservosheath", ("rect1", "face", 1)), 90)
+
+if __name__ == "__main__":
+    HalfCar.test()
diff --git a/rocolib/library/HalfCar.yaml b/rocolib/library/HalfCar.yaml
new file mode 100644
index 0000000..661a005
--- /dev/null
+++ b/rocolib/library/HalfCar.yaml
@@ -0,0 +1,420 @@
+connections:
+  connection0:
+  - - rect3
+    - b
+  - - rect1
+    - b
+  - angle: -90
+  connection1:
+  - - rect2
+    - b
+  - - rect4
+    - b
+  - angle: -90
+  connection10:
+  - - between2
+    - botedge1
+  - - fleft
+    - botedge2
+  - angle: 90
+    tabWidth: 10
+  connection11:
+  - - rTriangle1
+    - bedge
+  - - fleft
+    - botedge0
+  - {}
+  connection2:
+  - - rect4
+    - t
+  - - rect1
+    - t
+  - angle: -90
+  connection3:
+  - - sheathsplit
+    - topedge0
+  - - rect2
+    - t
+  - {}
+  connection4:
+  - - sheathsplit
+    - botedge1
+  - - rect0
+    - r
+  - angle: 180
+  connection5:
+  - - rect0
+    - l
+  - - rTriangle0
+    - bedge
+  - {}
+  connection6:
+  - - rTriangle0
+    - hedge
+  - - rTriangle1
+    - hedge
+  - angle: 180
+  connection7:
+  - - fleft
+    - topedge2
+  - - between1
+    - topedge1
+  - angle: 90
+  connection8:
+  - - between1
+    - botedge1
+  - - bright
+    - botedge2
+  - angle: 90
+  connection9:
+  - - between2
+    - topedge1
+  - - bright
+    - topedge2
+  - angle: 90
+interfaces:
+  bright.botedge0:
+    interface: botedge0
+    subcomponent: bright
+  bright.botedge1:
+    interface: botedge1
+    subcomponent: bright
+  bright.botedge2:
+    interface: botedge2
+    subcomponent: bright
+  bright.botedge3:
+    interface: botedge3
+    subcomponent: bright
+  bright.face0:
+    interface: face0
+    subcomponent: bright
+  bright.face1:
+    interface: face1
+    subcomponent: bright
+  bright.face2:
+    interface: face2
+    subcomponent: bright
+  bright.face3:
+    interface: face3
+    subcomponent: bright
+  bright.horn:
+    interface: horn
+    subcomponent: bright
+  bright.mount:
+    interface: mount
+    subcomponent: bright
+  bright.mount.decoration:
+    interface: mount.decoration
+    subcomponent: bright
+  bright.slotedge:
+    interface: slotedge
+    subcomponent: bright
+  bright.tabedge:
+    interface: tabedge
+    subcomponent: bright
+  bright.topedge0:
+    interface: topedge0
+    subcomponent: bright
+  bright.topedge1:
+    interface: topedge1
+    subcomponent: bright
+  bright.topedge2:
+    interface: topedge2
+    subcomponent: bright
+  bright.topedge3:
+    interface: topedge3
+    subcomponent: bright
+  fleft.botedge0:
+    interface: botedge0
+    subcomponent: fleft
+  fleft.botedge1:
+    interface: botedge1
+    subcomponent: fleft
+  fleft.botedge2:
+    interface: botedge2
+    subcomponent: fleft
+  fleft.botedge3:
+    interface: botedge3
+    subcomponent: fleft
+  fleft.face0:
+    interface: face0
+    subcomponent: fleft
+  fleft.face1:
+    interface: face1
+    subcomponent: fleft
+  fleft.face2:
+    interface: face2
+    subcomponent: fleft
+  fleft.face3:
+    interface: face3
+    subcomponent: fleft
+  fleft.horn:
+    interface: horn
+    subcomponent: fleft
+  fleft.mount:
+    interface: mount
+    subcomponent: fleft
+  fleft.mount.decoration:
+    interface: mount.decoration
+    subcomponent: fleft
+  fleft.slotedge:
+    interface: slotedge
+    subcomponent: fleft
+  fleft.tabedge:
+    interface: tabedge
+    subcomponent: fleft
+  fleft.topedge0:
+    interface: topedge0
+    subcomponent: fleft
+  fleft.topedge1:
+    interface: topedge1
+    subcomponent: fleft
+  fleft.topedge2:
+    interface: topedge2
+    subcomponent: fleft
+  fleft.topedge3:
+    interface: topedge3
+    subcomponent: fleft
+  rect1.b:
+    interface: b
+    subcomponent: rect1
+  rect1.face:
+    interface: face
+    subcomponent: rect1
+  rect1.l:
+    interface: l
+    subcomponent: rect1
+  rect1.r:
+    interface: r
+    subcomponent: rect1
+  rect1.t:
+    interface: t
+    subcomponent: rect1
+  rect2.b:
+    interface: b
+    subcomponent: rect2
+  rect2.face:
+    interface: face
+    subcomponent: rect2
+  rect2.l:
+    interface: l
+    subcomponent: rect2
+  rect2.r:
+    interface: r
+    subcomponent: rect2
+  rect2.t:
+    interface: t
+    subcomponent: rect2
+  rect3.b:
+    interface: b
+    subcomponent: rect3
+  rect3.face:
+    interface: face
+    subcomponent: rect3
+  rect3.l:
+    interface: l
+    subcomponent: rect3
+  rect3.r:
+    interface: r
+    subcomponent: rect3
+  rect3.t:
+    interface: t
+    subcomponent: rect3
+  rect4.b:
+    interface: b
+    subcomponent: rect4
+  rect4.face:
+    interface: face
+    subcomponent: rect4
+  rect4.l:
+    interface: l
+    subcomponent: rect4
+  rect4.r:
+    interface: r
+    subcomponent: rect4
+  rect4.t:
+    interface: t
+    subcomponent: rect4
+parameters:
+  brains:
+    defaultValue: esp32stack
+    spec:
+      valueType: str
+  bright.angle:
+    defaultValue: 0
+    spec:
+      maxValue: null
+      minValue: null
+      units: degrees
+      valueType: (float, int)
+  driveservo:
+    defaultValue: fs90r
+    spec:
+      valueType: str
+  fleft.angle:
+    defaultValue: 0
+    spec:
+      maxValue: null
+      minValue: null
+      units: degrees
+      valueType: (float, int)
+  height:
+    defaultValue: 36
+    spec:
+      minValue: 36
+      units: mm
+      valueType: (float, int)
+  length:
+    defaultValue: 76
+    spec:
+      minValue: 65
+      units: mm
+      valueType: (float, int)
+  width:
+    defaultValue: 60
+    spec:
+      minValue: 60
+      units: mm
+      valueType: (float, int)
+source: ..\builders\HalfCarBuilder.py
+subcomponents:
+  between1:
+    classname: SimpleRectBeam
+    kwargs: {}
+    parameters:
+      depth:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+      length:
+        function: x[0]- 2 * getDim(x[1], 'motorheight')
+        parameter: &id001
+        - width
+        - driveservo
+      width:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+  between2:
+    classname: SimpleRectBeam
+    kwargs: {}
+    parameters:
+      depth:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+      length:
+        function: x[0]- 2 * getDim(x[1], 'motorheight')
+        parameter: *id001
+      width:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+  bright:
+    classname: Wheel
+    kwargs:
+      invert: true
+    parameters:
+      angle:
+        parameter: bright.angle
+      center: false
+      flip: true
+      length:
+        function: ((x[0] - getDim(x[1], "width")))
+        parameter: &id002
+        - length
+        - brains
+      radius:
+        function: (getDim(x, "height") / 1.35)
+        parameter: brains
+      servo:
+        parameter: driveservo
+  fleft:
+    classname: Wheel
+    kwargs:
+      invert: true
+    parameters:
+      angle:
+        parameter: fleft.angle
+      center: false
+      length:
+        function: ((x[0] - getDim(x[1], "width")))
+        parameter: *id002
+      radius:
+        function: (getDim(x, "height") / 1.35)
+        parameter: brains
+      servo:
+        parameter: driveservo
+  rTriangle0:
+    classname: RightTriangle
+    kwargs: {}
+    parameters:
+      base:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+      height:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+  rTriangle1:
+    classname: RightTriangle
+    kwargs: {}
+    parameters:
+      base:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+      height:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+  rect0:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: x[0]-getDim(x[1], 'motorwidth')
+        parameter:
+        - height
+        - driveservo
+      w:
+        function: getDim(x, 'motorwidth')
+        parameter: driveservo
+  rect1:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        parameter: length
+      w:
+        parameter: height
+  rect2:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        parameter: length
+      w:
+        parameter: height
+  rect3:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        parameter: length
+      w:
+        parameter: width
+  rect4:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        parameter: length
+      w:
+        parameter: width
+  sheathsplit:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: (x[0] * 0.0691, getDim(x[1], 'motorwidth'), (x[0]-(getDim(x[1],
+          'motorwidth') + x[0] * 0.0691)))
+        parameter:
+        - length
+        - driveservo
+      toplength:
+        function: (x,)
+        parameter: length
diff --git a/rocolib/library/HingeServo.yaml b/rocolib/library/HingeServo.yaml
new file mode 100644
index 0000000..994d89c
--- /dev/null
+++ b/rocolib/library/HingeServo.yaml
@@ -0,0 +1,209 @@
+connections:
+  connection0:
+  - - servo
+    - botedge3
+  - - belt0
+    - l
+  - angle: -90
+  connection1:
+  - - servo
+    - botedge1
+  - - belt1
+    - l
+  - angle: -90
+  connection2:
+  - - servo
+    - topedge1
+  - - belt3
+    - l
+  - angle: -180
+  connection3:
+  - - servo
+    - topedge3
+  - - belt4
+    - l
+  - angle: -180
+  connection4:
+  - - belt2
+    - l
+  - - belt4
+    - r
+  - angle: 90
+interfaces:
+  belt0.b:
+    interface: b
+    subcomponent: belt0
+  belt0.face:
+    interface: face
+    subcomponent: belt0
+  belt0.l:
+    interface: l
+    subcomponent: belt0
+  belt0.r:
+    interface: r
+    subcomponent: belt0
+  belt0.t:
+    interface: t
+    subcomponent: belt0
+  belt1.b:
+    interface: b
+    subcomponent: belt1
+  belt1.face:
+    interface: face
+    subcomponent: belt1
+  belt1.l:
+    interface: l
+    subcomponent: belt1
+  belt1.r:
+    interface: r
+    subcomponent: belt1
+  belt1.t:
+    interface: t
+    subcomponent: belt1
+  belt2.b:
+    interface: b
+    subcomponent: belt2
+  belt2.face:
+    interface: face
+    subcomponent: belt2
+  belt2.l:
+    interface: l
+    subcomponent: belt2
+  belt2.r:
+    interface: r
+    subcomponent: belt2
+  belt2.t:
+    interface: t
+    subcomponent: belt2
+  servo.botedge0:
+    interface: botedge0
+    subcomponent: servo
+  servo.botedge1:
+    interface: botedge1
+    subcomponent: servo
+  servo.botedge2:
+    interface: botedge2
+    subcomponent: servo
+  servo.botedge3:
+    interface: botedge3
+    subcomponent: servo
+  servo.face0:
+    interface: face0
+    subcomponent: servo
+  servo.face1:
+    interface: face1
+    subcomponent: servo
+  servo.face2:
+    interface: face2
+    subcomponent: servo
+  servo.face3:
+    interface: face3
+    subcomponent: servo
+  servo.horn:
+    interface: horn
+    subcomponent: servo
+  servo.mount:
+    interface: mount
+    subcomponent: servo
+  servo.mount.decoration:
+    interface: mount.decoration
+    subcomponent: servo
+  servo.slotedge:
+    interface: slotedge
+    subcomponent: servo
+  servo.tabedge:
+    interface: tabedge
+    subcomponent: servo
+  servo.topedge0:
+    interface: topedge0
+    subcomponent: servo
+  servo.topedge1:
+    interface: topedge1
+    subcomponent: servo
+  servo.topedge2:
+    interface: topedge2
+    subcomponent: servo
+  servo.topedge3:
+    interface: topedge3
+    subcomponent: servo
+parameters:
+  driveservo:
+    defaultValue: fs90r
+    spec:
+      valueType: str
+  length:
+    defaultValue: 76
+    spec:
+      minValue: 65
+      units: mm
+      valueType: (float, int)
+  width:
+    defaultValue: 60
+    spec:
+      minValue: 60
+      units: mm
+      valueType: (float, int)
+source: HingeServoBuilder.py
+subcomponents:
+  belt0:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: (x[0]-getDim(x[1], 'motorwidth'))/2
+        parameter: &id001
+        - width
+        - driveservo
+      w:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+  belt1:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: (x[0]-getDim(x[1], 'motorwidth'))/2
+        parameter: *id001
+      w:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+  belt2:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: (x[0]-getDim(x[1], 'motorwidth'))/2
+        parameter: *id001
+      w:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+  belt3:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")
+        parameter: driveservo
+      w:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+  belt4:
+    classname: Rectangle
+    kwargs: {}
+    parameters:
+      l:
+        function: getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")
+        parameter: driveservo
+      w:
+        function: getDim(x, "motorheight")
+        parameter: driveservo
+  servo:
+    classname: MountedServo
+    kwargs: {}
+    parameters:
+      center: false
+      length:
+        function: getDim(x, "motorlength") + 2 * getDim(x, "shoulderlength")
+        parameter: driveservo
+      servo:
+        parameter: driveservo
diff --git a/rocolib/library/NWheeledCar.py b/rocolib/library/NWheeledCar.py
new file mode 100644
index 0000000..dc5caa7
--- /dev/null
+++ b/rocolib/library/NWheeledCar.py
@@ -0,0 +1,13 @@
+from rocolib.api.components import Component
+from rocolib.utils.utils import copyDecorations2
+
+class NWheeledCar(Component):
+    def assemble(self):
+        copyDecorations2(self, ("holderface0", ("holder", "rect4.face", 0)),
+                        ("bodyface0", ("front", "rect3.face", 0)), 0)
+        copyDecorations2(self, ("holderface1", ("holder", "rect3.face", 0)),
+                         ("bodyface1", ("front", "rect4.face", 0)), 0)
+
+
+if __name__ == "__main__":
+    NWheeledCar.test()
diff --git a/rocolib/library/NWheeledCar.yaml b/rocolib/library/NWheeledCar.yaml
new file mode 100644
index 0000000..3562647
--- /dev/null
+++ b/rocolib/library/NWheeledCar.yaml
@@ -0,0 +1,122 @@
+connections:
+  connection0:
+  - - car0
+    - rect4.l
+  - - car1
+    - rect4.r
+  - {}
+  connection1:
+  - - car1
+    - rect4.l
+  - - car2
+    - rect4.r
+  - {}
+  connection2:
+  - - car2
+    - rect4.l
+  - - car3
+    - rect4.r
+  - {}
+  connection3:
+  - - front
+    - rect4.l
+  - - car3
+    - rect4.l
+  - {}
+  connection4:
+  - - holder
+    - rect2.t
+  - - front
+    - rect2.l
+  - angle: -90
+interfaces: {}
+parameters:
+  brains:
+    defaultValue: esp32stack
+    spec:
+      valueType: str
+  driveservo:
+    defaultValue: fs90r
+    spec:
+      valueType: str
+  height:
+    defaultValue: 36
+    spec:
+      minValue: 36
+      units: mm
+      valueType: (float, int)
+  length:
+    defaultValue: 76
+    spec:
+      minValue: 76
+      units: mm
+      valueType: (float, int)
+  width:
+    defaultValue: 60
+    spec:
+      minValue: 60
+      units: mm
+      valueType: (float, int)
+source: ..\builders\NWheeledCarBuilder.py
+subcomponents:
+  car0:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  car1:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  car2:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  car3:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  front:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  holder:
+    classname: ESP32Stack
+    kwargs: {}
+    parameters:
+      heightChanger:
+        function: x[1] - getDim(x[0], 'height')
+        parameter:
+        - brains
+        - height
+      length:
+        parameter: width
diff --git a/rocolib/library/PivotCar.yaml b/rocolib/library/PivotCar.yaml
new file mode 100644
index 0000000..be78e52
--- /dev/null
+++ b/rocolib/library/PivotCar.yaml
@@ -0,0 +1,201 @@
+connections:
+  connection0:
+  - - middle0
+    - rect4.l
+  - - midsupport0
+    - botedge
+  - {}
+  connection1:
+  - - front0
+    - rect4.l
+  - - midsupport1
+    - botedge
+  - {}
+  connection2:
+  - - middle0
+    - rect3.l
+  - - midsupport2
+    - botedge
+  - {}
+  connection3:
+  - - front0
+    - rect3.l
+  - - midsupport3
+    - botedge
+  - {}
+  connection4:
+  - - midsupport2
+    - topedge
+  - - midsupport3
+    - topedge
+  - {}
+  connection5:
+  - - front0
+    - rect3.t
+  - - split0
+    - topedge0
+  - {}
+  connection6:
+  - - holder0
+    - rect2.t
+  - - front0
+    - rect2.r
+  - angle: -90
+  connection7:
+  - - front0
+    - rect1.r
+  - - hingeSplit0
+    - topedge0
+  - {}
+  connection8:
+  - - hingeSplit0
+    - botedge1
+  - - hinge0
+    - belt2.r
+  - angle: -90
+interfaces: {}
+parameters:
+  brains:
+    defaultValue: esp32stack
+    spec:
+      valueType: str
+  driveservo:
+    defaultValue: fs90r
+    spec:
+      valueType: str
+  height:
+    defaultValue: 36
+    spec:
+      minValue: 36
+      units: mm
+      valueType: (float, int)
+  length:
+    defaultValue: 76
+    spec:
+      minValue: 76
+      units: mm
+      valueType: (float, int)
+  width:
+    defaultValue: 60
+    spec:
+      minValue: 60
+      units: mm
+      valueType: (float, int)
+source: ..\builders\PivotCarBuilder.py
+subcomponents:
+  front0:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hinge0:
+    classname: HingeServo
+    kwargs: {}
+    parameters:
+      length:
+        parameter: length
+      width:
+        parameter: width
+  hingeSplit0:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: ((x[0]-getDim(x[1], "motorheight"))/2, getDim(x[1], "motorheight"),
+          (x[0]-getDim(x[1], "motorheight"))/2)
+        parameter:
+        - height
+        - driveservo
+      toplength:
+        function: (x,)
+        parameter: height
+  holder0:
+    classname: ESP32Stack
+    kwargs: {}
+    parameters:
+      heightChanger:
+        function: x[1] - getDim(x[0], 'height')
+        parameter:
+        - brains
+        - height
+      length:
+        parameter: width
+  middle0:
+    classname: HalfCar
+    kwargs: {}
+    parameters:
+      height:
+        parameter: height
+      length:
+        parameter: length
+      width:
+        parameter: width
+  midsupport0:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport1:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport2:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  midsupport3:
+    classname: Trapezoid
+    kwargs: {}
+    parameters:
+      bangle:
+        function: float(np.atan((x-37)/5)* 180 * 0.318309)
+        parameter: width
+      depth:
+        function: x-37
+        parameter: width
+      width:
+        function: x-10
+        parameter: width
+  split0:
+    classname: SplitEdge
+    kwargs: {}
+    parameters:
+      botlength:
+        function: (x[1], x[0]-x[1])
+        parameter:
+        - length
+        - height
+      toplength:
+        function: (x,)
+        parameter: length
diff --git a/rocolib/library/RightTriangle.py b/rocolib/library/RightTriangle.py
new file mode 100644
index 0000000..818d150
--- /dev/null
+++ b/rocolib/library/RightTriangle.py
@@ -0,0 +1,28 @@
+from rocolib.api.components import FoldedComponent
+from rocolib.api.composables.graph.Face import Face
+
+class RightTriangle(FoldedComponent):
+
+    def define(self):
+        self.addParameter("height", 3, paramType="length")
+        self.addParameter("base", 4, paramType="length")
+        self.addParameter("hypotenuse", 5, paramType="length")
+        self.addParameter("angle", 45, paramType="angle", minValue=45, maxValue=45)
+
+        self.addEdgeInterface("hedge", "r0.e0", "height")
+        self.addEdgeInterface("bedge", "r0.e1", "base")
+        self.addEdgeInterface("hypoedge", "r0.e2", "hypotenuse")
+
+    def assemble(self):
+        h = self.getParameter("height")
+        b = self.getParameter("base")
+        x = h**2 + b**2
+
+        rs = []
+        rs.append(Face("", ((b, 0), (0,0), (0, -h))))
+        self.attachEdge(None, rs[0], "e0", prefix="r0", angle=90)
+
+
+if __name__ == "__main__":
+    RightTriangle.test()
+
diff --git a/rocolib/library/Tire.py b/rocolib/library/Tire.py
new file mode 100644
index 0000000..29fa812
--- /dev/null
+++ b/rocolib/library/Tire.py
@@ -0,0 +1,70 @@
+from rocolib.api.components import FoldedComponent
+from rocolib.api.composables.graph.Face import RegularNGon2
+from rocolib.api.composables.graph.Face import Rectangle
+import numpy as np
+import warnings
+
+class Tire(FoldedComponent):
+    """Tire Component
+    Auto-select tire design based on thickness specified.
+    If 0 or nothing specified, use a disk (regular ngon, 40)
+    Else Nonagon tire with specified thickness.
+    paramType=tire_thickness: control tire thickness
+    paramType=radius: to set radius"""
+    def define(self):
+        self.addParameter("tire_thickness", 0, paramType="length")
+        self.addParameter("radius", 25, paramType="length")
+        self.addFaceInterface("face", "w1")
+
+    def assemble(self):
+        thickness = self.getParameter("tire_thickness")
+        if thickness == 0:
+            #tickness is 0 or not specified
+            self.regularNgonTireAssembly()
+        else:
+            #if thickness is not zero
+            self.foldedTireAssembly()
+
+    def regularNgonTireAssembly(self):
+        # number of polygon sides
+        n = 40
+        l = self.getParameter("radius")
+
+        self.addFace(RegularNGon2("w1", n, l))
+
+    def foldedTireAssembly(self):
+        # number of polygon sides
+        n = 9
+        r = self.getParameter("radius")
+        tw = self.getParameter("tire_thickness")
+        # length of
+        sl = float(2 * r * np.cos(np.deg2rad(90-180/n)))
+
+        wheel1 = RegularNGon2("", n, r)
+        wheel2 = RegularNGon2("", n, r)
+
+        support = []
+        for i in range(n):
+            support.append(Rectangle("", tw, sl))
+
+        fromEdge = None
+        for i in range(9):
+            self.attachEdge(fromEdge, support[i], "e2", prefix="r%d" % i, angle=-40, root=(i == 1))
+            fromEdge = 'r%d.e0' % i
+
+        self.attachEdge("r0.e1", wheel1, "e0", prefix="w1", angle=-90)
+        self.attachEdge("r4.e3", wheel2, "e0", prefix="w2", angle=-90)
+
+        self.addTab("r8.e1", "w1.e8", angle=-90, width=11)
+        self.addTab("r0.e3", "w2.e4", angle=-90, width=11)
+        self.addTab("r4.e1", "w1.e4", angle=-90, width=11)
+
+        self.addTab("r2.e1", "w1.e2", angle=-90, width=11)
+        self.addTab("r2.e3", "w2.e2", angle=-90, width=11)
+
+        self.addTab("r7.e1", "w1.e7", angle=-90, width=11)
+        self.addTab("r7.e3", "w2.e6", angle=-90, width=11)
+
+
+if __name__ == "__main__":
+    Tire.test()
-- 
GitLab