{"id":19,"date":"2021-11-24T17:30:29","date_gmt":"2021-11-24T22:30:29","guid":{"rendered":"http:\/\/piwars22.donstechstuff.com\/?p=19"},"modified":"2021-11-25T13:31:14","modified_gmt":"2021-11-25T18:31:14","slug":"prototyping-the-hungry-cattle-dispenser","status":"publish","type":"post","link":"https:\/\/piwars22.donstechstuff.com\/?p=19","title":{"rendered":"Prototyping the Hungry Cattle dispenser"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Before we build our real robot we need to prototype (try out) some of the ideas for parts and strategies we will use in the real bot. Fortunately we have an existing robot that has a chassis pretty much perfect for trying out ideas. <\/p>\n\n\n\n<p class=\"highlightblock wp-block-paragraph\"><em>The test robot has a 3d-printed chassis with grid holes on its front and lid that make it easy to attach test parts for various projects.  It has 4 brushed motors driving <a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Mecanum_wheel\" target=\"_blank\">Mecanum<\/a> (omnidirectional) wheels, and is controlled from a ps4 controller (using <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/ApproxEng\/approxeng.input\" target=\"_blank\">Approximate Engineering&#8217;s<\/a> software drivers on a Raspberry Pi Zero).  Though not relevant to this particular test, it has a TFT display and a NeoPixel ring on its back end that provide a lot of operational information on commands and battery \/ system status. <\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because we want to eventually try to make this work autonomously, we also included mounts for some sensors we want to try out. They&#8217;re shown in the video, but we left them out of the OpenSCAD design code we show below, because they are really fodder (pun intended&#8230;) for another story.  And because we haven&#8217;t actually done anything with them yet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, on to the good news.  It works.  Mostly.  A little bit.  Sort of&#8230;  The prototype did its job and pointed out the flaws in our concept.  As a proof-of-concept, it was a success.   We&#8217;ll fix the oops-es and carry on with this as the strategy.  <\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Hopper Drop first test\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/-elkwyCO_j0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">For sure the driver (oops, me&#8230;) had some issues with accuracy and driving skills.   The major design flaws became much more obvious in the physical reality than they were in the imagination.   You probably noticed that we put a camera on the front of the mounting bracket, in anticipation of later using that to help find and accurately position the robot in front of a trough.  You probably also noticed that the trap door totally blinds it when it opens.  Oops !  Might need to rethink that&#8230;   You&#8217;ll also notice that the hopper needs to be mounted a little higher so its opened door wouldn&#8217;t bump into the food trough on the next approach.  But, fundamentally, it does drop food.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On the &#8220;plus side&#8221;, the unanticipated interference between the camera and the trapdoor made the trapdoor turn into a pretty nice ramp that helps to spread out the feed. Even though we plan to relocate the camera (and probably replace it with a Pi Zero with a tiny spycam on OpenCV), we&#8217;ll probably put in a &#8220;stop&#8221; to duplicate that ramp effect.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our plan is to ultimately have 3 of these hoppers arranged horizontally on the mounting bracket, one for each food trough.  And each hopper will be tall enough to hold enough food to fill a single hopper to the required half-way point.  The one shown here is &#8220;shorter&#8221; to reduce printing time since its only a prototype.<\/p>\n\n\n\n<p class=\"has-large-font-size wp-block-paragraph\"><strong>What it looks like \/ How it works<\/strong><\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Hopper Door Closeup\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/TZ9jHx9Nbho?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<p class=\"wp-block-paragraph\">This is how the hopper door operates; the door itself is on a pivot at the back. Normally a small &#8220;catch&#8221; holds it closed. The catch is mounted on an SG-90 micro servo which can be activated to release the door<\/p>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The photos below show details of the catch mechanism.  Note that the catch is printed with a small pocket into which a standard servo horn is bolted with M2 bolts (its too hard to print the tiny teeth that actually mount to the servo itself).   <\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-1024x768.jpg\" alt=\"\" class=\"wp-image-49\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-1024x768.jpg 1024w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-300x225.jpg 300w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-768x576.jpg 768w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-1536x1152.jpg 1536w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch-1568x1176.jpg 1568w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_catch.jpg 1600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"714\" height=\"474\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/catch_cad.png\" alt=\"\" class=\"wp-image-53\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/catch_cad.png 714w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/catch_cad-300x199.png 300w\" sizes=\"auto, (max-width: 714px) 100vw, 714px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The trapdoor has a lip to make a clean seal for the &#8220;feed&#8221;.  It rotates on pivots that are actually M3 bolts screwed into a tubular sleeve on the back edge of the trapdoor.  Note that the centerline of the pivot should be inline (vertically) with the joint line between the hopper and the trapdoor to avoid binding or interference crashes.  <\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-1024x768.jpg\" alt=\"\" class=\"wp-image-111\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-1024x768.jpg 1024w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-300x225.jpg 300w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-768x576.jpg 768w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-1536x1152.jpg 1536w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/hopper_trapdoor2-2048x1536.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"852\" height=\"484\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/trapdoor_cad.png\" alt=\"\" class=\"wp-image-55\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/trapdoor_cad.png 852w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/trapdoor_cad-300x170.png 300w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/trapdoor_cad-768x436.png 768w\" sizes=\"auto, (max-width: 852px) 100vw, 852px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The bottom of the bin has holes for M3 screws that act as pivots; these holes are 4mm dia so that the screws turn freely in them (and the screws are not &#8220;fully tightened&#8221; when installed).  As noted above, these pivot holes are vertically inline with the joint line.   Also note that the &#8220;back&#8221; of the bin has a vertical clearance gap to allow room for the axle sleeve.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The &#8220;front&#8221; of the bin has mounting holes that the servo mount box bolts into, the back of the box has mounting holes that are used to attach the bin to the mounting bracket.   Note that in the pictures below, the bin is shown &#8220;upside down&#8221; because it is oriented in the way that prints best (with no supports).<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"652\" height=\"504\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_bottom.png\" alt=\"\" class=\"wp-image-106\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_bottom.png 652w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_bottom-300x232.png 300w\" sizes=\"auto, (max-width: 652px) 100vw, 652px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"521\" height=\"466\" src=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_back.png\" alt=\"\" class=\"wp-image-107\" srcset=\"https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_back.png 521w, https:\/\/piwars22.donstechstuff.com\/wp-content\/uploads\/2021\/11\/bin_back-300x268.png 300w\" sizes=\"auto, (max-width: 521px) 100vw, 521px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p class=\"has-large-font-size wp-block-paragraph\"><strong>The CAD Design<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The OpenSCAD code that generates the hopper parts is as shown below.  <\/p>\n\n\n\n<pre class=\"wp-block-code codeblockopenscad\"><code>\/\/ note part should be \"bin\" or \"door\", \"servo\", or \"catch\"\ndraw_part(\"catch\");\n\nbin_l = 55;         \/\/ interior length of bin (x)\nbin_w = 40;         \/\/ interior width of bin (y)\nbody_wall_thickness = 2.0;  \ndoor_clearance_gap = 1.0;       \/\/ clearance gap between door lip and inside of bin box\n\naxle_ring_dia = 8;              \/\/ ring that surrounds axle hole in bin\naxle_offset_x = 3;              \/\/ axle distance from back wall\nshaft_vertical_clearance = 4;   \/\/ height of gap in bin back wall to clear axle shaft\nshaft_horizontal_clearance = 9; \/\/ gap in door bottom lip to clear axle shaft\n\ngrid_spacing = 16;              \/\/ for mounting grid (mount trough to robot)\ngrid_height = 20;               \/\/ height of first grid row above bin bottom  \ngrid_mount_tube_dia = 7;        \/\/ to help self-tap screws grab    \ngrid_mount_tube_len = 5;        \/\/ to help self-tap screws grab    \n\noversize_multiplier = 1.25;\nvolume_needed = 100 * 100 * 25 * oversize_multiplier;\n\/\/ bin_h = 52;       \/\/ used only for testing, normally use volume-calculated from below\nbin_h = volume_needed \/ (bin_l * bin_w);\n\nbin_outer_l = bin_l + (2*body_wall_thickness);\nbin_outer_w = bin_w + (2*body_wall_thickness);\n\n\/\/ standard part dimensions\nM3_selftap_dia = 3;       \nM3_throughhole_dia = 4;   \nM2_selftap_dia = 2;         \nM2_throughhole_dia = 2.5;    \nM25_selftap_dia = 2.5;\n\nmodule draw_part(part) {\n    if (part == \"bin\") {\n        draw_bin();\n    }\n    if (part == \"door\") {\n        draw_door();\n    }\n    if (part == \"servo\") {\n        draw_servo_mount();\n    }\n\n    if (part == \"catch\") {\n        draw_door_catch();\n    }\n}\n\n\/\/ note that the bin is generated \"upside down\" to facilitate support-less 3d printing\nmodule draw_bin() {\n    $fn = 24;\n    difference() {\n        union() {\n            difference() {\n                \/\/ make outside of basic box\n                cube(&#91; bin_outer_l, bin_outer_w, bin_h ]);\n                \/\/ remove inside of box\n                translate(&#91; body_wall_thickness, body_wall_thickness, -0.1 ]) \n                    cube(&#91; bin_l, bin_w, bin_h + 0.2 ]);\n            }    \n\n            \/\/ add rings that surround axle bolts\n            translate(&#91; axle_offset_x, 0, bin_h ]) \n                rotate(&#91; -90, 0, 0 ]) \n                cylinder ( d=axle_ring_dia, h=body_wall_thickness);\n            translate(&#91; axle_offset_x, (bin_outer_w - body_wall_thickness), bin_h ]) \n                rotate(&#91; -90, 0, 0 ]) \n                cylinder ( d=axle_ring_dia, h=body_wall_thickness);    \n\n            \/\/ make mounting grid tubes (to thicken wall so self-tap screws grab)\n            translate(&#91; 0, (bin_outer_w\/2) - (grid_spacing\/2), bin_h - grid_height ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n            translate(&#91; 0, (bin_outer_w\/2) + (grid_spacing\/2), bin_h - grid_height ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n            translate(&#91; 0, (bin_outer_w\/2) - (grid_spacing\/2), bin_h - grid_height - grid_spacing ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n            translate(&#91; 0, (bin_outer_w\/2) + (grid_spacing\/2), bin_h - grid_height - grid_spacing ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n\n            \/\/ make mounting tubes for servo mount\n            translate(&#91; (bin_outer_l - grid_mount_tube_len), 12, bin_h - 5 ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n            translate(&#91; (bin_outer_l - grid_mount_tube_len), 12, bin_h - 5 - 42 ])\n                rotate(&#91; 0, 90, 0 ]) \n                cylinder ( d=grid_mount_tube_dia, h=grid_mount_tube_len );\n        }\n\n        \/\/ make vertical room for axle sheath\n        translate(&#91; -0.1, body_wall_thickness, (bin_h - shaft_vertical_clearance) ]) \n            cube(&#91; body_wall_thickness + 0.2, bin_w, shaft_vertical_clearance + 0.1 ]);\n\n        \/\/ make throughholes for axle bolts\n        translate(&#91; axle_offset_x, -1, bin_h ]) \n            rotate(&#91; -90, 0, 0 ]) \n            cylinder ( d=M3_throughhole_dia, h=56);\n\n        \/\/ make mounting grid (holes for selftap)\n        translate(&#91; -0.1, (bin_outer_w\/2) - (grid_spacing\/2), bin_h - grid_height ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n        translate(&#91; -0.1, (bin_outer_w\/2) + (grid_spacing\/2), bin_h - grid_height ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n\n        translate(&#91; -0.1, (bin_outer_w\/2) - (grid_spacing\/2), bin_h - grid_height - grid_spacing ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n        translate(&#91; -0.1, (bin_outer_w\/2) + (grid_spacing\/2), bin_h - grid_height - grid_spacing ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n\n        \/\/ make mounting holes for servo mount\n        translate(&#91; (bin_outer_l - (grid_mount_tube_len + 0.1)), 12, bin_h - 5 ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n        translate(&#91; (bin_outer_l - (grid_mount_tube_len + 0.1)), 12, bin_h - 5 - 42 ])\n            rotate(&#91; 0, 90, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=grid_mount_tube_len + 0.2 );\n    }\n\n    echo(\"hopper height = \", bin_h);\n}\n\nmodule draw_door() {\n    $fn = 24;\n    wall_and_gap = body_wall_thickness + door_clearance_gap;\n\n    difference() {\n        union() {\n            \/\/ thick part of door (box bottom)\n            \/\/ note it is the raised part that should fit \"inside\" the bin box\n            translate(&#91; 0, wall_and_gap, 0 ]) \n                cube(&#91; (bin_outer_l - wall_and_gap), (bin_w - (2*door_clearance_gap)), (body_wall_thickness + 1.5) ]);\n\n            \/\/ outer \"lip\" for door (thin part of door)\n            \/\/ (should match outside dim of bin, less shaft horizontal clearance gap)\n            translate(&#91; shaft_horizontal_clearance, 0, 0 ]) \n                cube(&#91; (bin_outer_l - shaft_horizontal_clearance), bin_outer_w, body_wall_thickness ]);\n\n            translate(&#91; wall_and_gap, wall_and_gap, wall_and_gap ]) \n                rotate(&#91; -90, 0, 0 ]) \n                cylinder ( r=wall_and_gap, h=(bin_w - (2*door_clearance_gap)));\n        }\n        translate(&#91; wall_and_gap, 0, wall_and_gap ]) \n            rotate(&#91; -90, 0, 0 ]) \n            cylinder ( d=M3_selftap_dia, h=bin_outer_w);        \n    }\n}\n\nmodule draw_servo_mount() {\n    $fn = 24;\n    screw_separaton = 28;\n\n    pocket_length = 24;   \n    pocket_width = 13; \n    mountbox_width = 18;\n    mountbox_length = 35;\n    mountbox_depth = 19;\n\n    mountbox_tab_l = 50;\n    mountbox_tab_screw_sep = 42;\n\n    difference() {\n        translate(&#91; -mountbox_length\/2, -mountbox_width\/2, 0]) \n            cube(&#91; mountbox_length, mountbox_width, mountbox_depth ]); \n\n        translate(&#91; -((pocket_length\/2) + 0.1), -pocket_width\/2, -0.1 ]) \n            cube(&#91; pocket_length+0.2, pocket_width, mountbox_depth+0.2 ]);\n\n        translate(&#91; -screw_separaton\/2, 0, -0.1 ])\n            cylinder( d=M2_selftap_dia, h=mountbox_depth+0.2 );\n        translate(&#91; screw_separaton\/2, 0, -0.1 ])\n            cylinder( d=M2_selftap_dia, h=mountbox_depth+0.2 );\n    }\n\n    translate(&#91; 0, -mountbox_width\/2, 0 ]) difference() {\n        translate(&#91; -mountbox_tab_l\/2, 0, 0 ]) \n            cube(&#91; mountbox_tab_l, 2, mountbox_depth ]);\n        translate(&#91; -mountbox_tab_screw_sep\/2, -0.1, mountbox_depth\/2 ]) \n            rotate(&#91; -90, 0, 0 ]) \n            cylinder( d=M3_throughhole_dia, h=2.2);\n        translate(&#91; mountbox_tab_screw_sep\/2, -0.1, mountbox_depth\/2 ]) \n            rotate(&#91; -90, 0, 0 ]) \n            cylinder( d=M3_throughhole_dia, h=2.2);\n    }\n}\n\nmodule draw_door_catch() {\n    $fn = 24;\n    arm_w = 10;\n    arm_thick = 3;\n    servo_axle_x = 5;\n    horn_shaft_dia = 8;\n    pocket_bottom_z = 1.5;\n    pocket_axle_to_end_x = 18;\n    pocket_width = 6;\n    catch_from_axel = 24;\n    catch_width = 4;\n    catch_length = 18;\n    arm_l = servo_axle_x + catch_from_axel + catch_width;\n    hole1_x = 6.5;\n    hole2_x = 13.0;\n\n    difference() {\n        union() {\n            translate(&#91; -servo_axle_x, -arm_w\/2, 0 ])  \n                cube(&#91; arm_l, arm_w, arm_thick ]);\n            translate(&#91; catch_from_axel, -arm_w\/2, 0 ]) \n                cube(&#91; catch_width, catch_length, arm_thick ]);\n        }\n        translate(&#91; 0, 0, -0.1 ]) \n            cylinder( d=M3_throughhole_dia, h=arm_thick + 0.2 );\n        translate(&#91; 0, 0, pocket_bottom_z ]) \n            cylinder( d=horn_shaft_dia, h=arm_thick );\n        translate(&#91; 0, -pocket_width\/2, pocket_bottom_z]) \n            cube(&#91; pocket_axle_to_end_x, pocket_width, arm_thick ]);\n        translate(&#91; hole1_x, 0, -0.1 ]) \n            cylinder( d=M2_throughhole_dia, h=arm_thick + 0.2);\n        translate(&#91; hole2_x, 0, -0.1 ]) \n            cylinder( d=M2_throughhole_dia, h=arm_thick + 0.2);\n    }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the code is heavily parameterized.  The most likely parameters that would be changed to support a new robot are <strong>bin_l<\/strong>, <strong>bin_w<\/strong>, and <strong>oversize_multiplier<\/strong>.  These control the length (front-to-back) and width (side-to-side) of the bin.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The height of the bin is calculated in the code to hold a sufficient volume of &#8220;food&#8221; to fill the 100 x 100 x 50mm bin half-way.  Note that the <strong>oversize-multiplier<\/strong> parameter allows you to allow room for a bit extra to allow for spillage.  In this example the parameter is set to 1.25 which gives 25% extra.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The &#8220;standard part dimensions&#8221; screw diameter parameters and the <strong>door_clearance_gap<\/strong> parameter can be used to tune your design to match the actual extrusion profiles of your 3d printer.  <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To run this code, simply paste it into the OpenSCAD editor.  You can change the parameter in line 2 to select which part will be generated when you render the design.  There are 4 possibilities: &#8220;bin&#8221;, &#8220;door&#8221;, &#8220;catch&#8221;, and &#8220;servo&#8221; (which generates the clamp that mounts the SG90 servo).  <\/p>\n\n\n\n<p class=\"has-large-font-size wp-block-paragraph\"><strong>The Python Code<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The servo is driven by a PWM signal generated on the Raspberry Pi Zero controller.  This code uses the pigpio library to generate PWM signals that are jitter-free.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The setup for the library and hardware is as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code codeblockpython\"><code>import RPi.GPIO as GPIO\nimport pigpio\n# \n# note it is important to \"sudo pigpiod\" at bootup to allow this to work...\n#\n# verified that it works with all 3 servos, even though documentation\n# seems to suggest that there is only one PWM generator in pi.  \n# probably only needs one generator to work even with multiple pins\n# https:\/\/ben.akrin.com\/?p=9158 \n#\n# the pin numbering is per gpio numbers.   \n# tested with GPIO.24, GPIO.25, and GPIO.9 simultaneously\n# \nservo = 24\npwm = pigpio.pi()\npwm.set_mode(servo, pigpio.OUTPUT)\npwm.set_PWM_frequency( servo, 50 )<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The code used to open and close the trapdoor latch is as follows (if you build one, the actual constants (600 and 1500), which represent the pulse width, will probably be different, based on your angular placement of the arm on the servo motor shaft):<\/p>\n\n\n\n<pre class=\"wp-block-code codeblockpython\"><code>if joystick.presses.l1:\n    print(\"pressed L1 servo 600 LATCH TRAPDOOR\")\n    pwm.set_servo_pulsewidth ( servo, 600 )\n\nif joystick.presses.l2:\n    print(\"pressed L2 servo 1500 OPEN TRAPDOOR\")\n    pwm.set_servo_pulsewidth ( servo, 1500 )<\/code><\/pre>\n\n\n\n<p class=\"has-large-font-size wp-block-paragraph\"><strong>Wrap-Up<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So we are encouraged to know that our initial prototype shows that the idea will work.  We will need to make some hardware tweaks to fix the OOPS-es, and we&#8217;ll need to try it out with a full-height bin just to make sure there&#8217;s no surprises there, but we feel like this is indeed the approach we will use for this challenge. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Before we build our real robot we need to prototype (try out) some of the ideas for parts and strategies we will use in the real bot. Fortunately we have an existing robot that has a chassis pretty much perfect for trying out ideas. The test robot has a 3d-printed chassis with grid holes on [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[5,2],"class_list":["post-19","post","type-post","status-publish","format-standard","hentry","category-7","tag-cattle","tag-progress"],"_links":{"self":[{"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/posts\/19","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=19"}],"version-history":[{"count":43,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/posts\/19\/revisions"}],"predecessor-version":[{"id":128,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=\/wp\/v2\/posts\/19\/revisions\/128"}],"wp:attachment":[{"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=19"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=19"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/piwars22.donstechstuff.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=19"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}