I need a theodolite… Too cheap to buy one. Hopefully not too dumb to build one. Whether I finish this small project or not, who knows!?

*updated, now with more out of control code. More cursed theodolite than ever.

```
//Parameters
//Ring scales
InnerRad = 45;
OuterRad = 58;
ScaleRad = 50;
ring_height = 2;
scale_height = 0.6;
number_height = 0.4;
//base dimensions
base_outer = 75;
base_mid = 70;
base_inner = 65;
base_bearing_outer_diam = 10;
base_bearing_inner_diam = 3;
base_bearing_height = 5;
elev_scale_radius = 40;
//gap between printed areas that should move freely
gap = 0.05;
//Graduation lengths
len1 = 3;
len5 = 5;
len10 = 7;
//Text parameters
TextOffset = -4;
TextSize = 3;
//Initial round detail
$fn = 10;
//Functions for returning points around a circle
function fangle2(d,radius) = [sin(d)*(radius),cos(d)*(radius)];
function fangle3(d,radius) = [sin(d)*(radius),cos(d)*(radius),0];
//Assemble top level pieces
translate([0,0,40-40])
azimuth_ring();
translate([0,0,35-40])
level_top();
translate([0,0,5-40])
level_base();
translate([0,0,0])
top_base();
//LH scale
translate([12.5,0,40])
elevation_scale(3.5);
//RH Scale
translate([-17.5,0,40])
elevation_scale(1.5);
module elevation_scale(text_displacement=2.5) {
rotate([40,0,0])
rotate([0,-90,180])
difference(){
//Elevation Scale
//rotate([0,90,0])
color("green")
translate([0,0,2.5])
rotate([0,0,0])
rotate_extrude(angle = 100, $fn=100)
translate([elev_scale_radius + 0.30,0])
square([.5,5],true);
union(){
color("red")
for (i = [-10:5:90])
{
translate([sin(i)*elev_scale_radius,cos(i)*elev_scale_radius,0])
rotate([0,0,i*-1])
cube([.25,.25,5]);
}
color("yellow")
for (i = [-10:5:90])
{
translate([sin(i+0.5)*elev_scale_radius,cos(i+0.5)*elev_scale_radius,text_displacement])
rotate([90,90,i*-1])
linear_extrude(height=1,center=true,$fn=1)
text(text=str(abs(i-40)),font="Arial Rounded MT Bold:style=Regular", size=1.5, halign="center");
}
}
}
}
module top_base() {
$fn=100;
//Inner bearing grip
translate([0,0,-base_bearing_height])
cylinder(h=base_bearing_height,d1=base_bearing_inner_diam,d2=base_bearing_inner_diam);
//Top platter
cylinder(h=2,r1=InnerRad-gap,r2=InnerRad-gap);
//Arrow
translate([0,InnerRad,2+gap])
rotate([0,0,45])
square(5,center=true);
//Laser mount
translate([-10,0,40])
rotate([0,90,0])
linear_extrude(height=5,center=true,$fn=1)
polygon([[-40,-40],[40,40],[40,-40]]);
translate([10,0,40])
rotate([0,90,0])
linear_extrude(height=5,center=true,$fn=1)
polygon([[-40,-40],[40,40],[40,-40]]);
translate([-15,0,40])
rotate([0,90,0])
cylinder(h=30,d1=5,d2=5);
}
//Base stuff
module level_base() {
difference() {
color("orange")
translate([0,0,0])
linear_extrude(height = 5, center = false,$fn=1)
level_base_2D();
translate([0,0,0])
level_top_cutout(7.05);
}
difference() {
color("red")
translate([0,0,-5])
linear_extrude(height = 5, center = false,$fn=1)
level_base_2D();
translate([0,0,0])
level_top_cutout(7.05);
}
}
module level_top() {
difference() {
color("lightgreen")
translate([0,0,0])
linear_extrude(height = 5, center = false,$fn=1)
level_top_2D();
union() {
translate([0,0,0])
level_base_cutout(7.05);
translate([0,0,0])
cylinder(h=base_bearing_height+1, d1=base_bearing_outer_diam, d2=base_bearing_outer_diam,$fn=50);
}
}
difference() {
color("darkgreen")
translate([0,0,-5])
linear_extrude(height = 5, center = false,$fn=1)
level_top_2D();
translate([0,0,0])
level_base_cutout(7.05);
}
}
module level_top_2D() {
$fn=50;
triangle_points =[fangle2(0,base_outer),
fangle2(120,base_outer),
fangle2(240,base_outer),
fangle2(0,base_inner),
fangle2(120,base_inner),
fangle2(240,base_inner),
fangle2(0+180,base_outer*.5),
fangle2(120+180,base_outer*.5),
fangle2(240+180,base_outer*.5),
fangle2(0+180,base_inner*.4),
fangle2(120+180,base_inner*.4),
fangle2(240+180,base_inner*.4)
];
//Outer triangle frame
triangle_paths =[[0,1,2],[3,4,5]];
polygon(triangle_points,triangle_paths,10);
//Inner triangle frame
triangle_paths2 =[[6,7,8],[9,10,11]];
polygon(triangle_points,triangle_paths2,10);
//Inner circle bearing base
circle(base_outer*.2);
translate(fangle3(0,base_mid))
circle(10);
translate(fangle3(120,base_inner))
circle(10);
translate(fangle3(120,base_outer))
circle(10);
translate(fangle3(120,base_mid))
rotate([0,0,-120])
square([(base_outer-base_inner)*2,(base_outer-base_inner)],true);
translate(fangle3(240,base_inner))
circle(10);
translate(fangle3(240,base_mid))
rotate([0,0,-240])
square([(base_outer-base_inner)*2,(base_outer-base_inner)],true);
translate(fangle3(240,base_outer))
circle(10);
}
module level_top_cutout(rad) {
$fn=50;
translate(fangle3(0,base_mid))
sphere(rad);
translate(fangle3(120,base_mid))
sphere(rad);
translate(fangle3(240,base_mid))
sphere(rad);
}
module level_base_2D() {
$fn=50;
triangle_points =[fangle2(0,base_outer),fangle2(120,base_outer),fangle2(240,base_outer),fangle2(0,base_inner),fangle2(120,base_inner),fangle2(240,base_inner)];
triangle_paths =[[0,1,2],[3,4,5]];
polygon(triangle_points,triangle_paths,10);
translate(fangle3(0,base_mid))
circle(10);
translate(fangle3(120,base_mid))
circle(10);
translate(fangle3(240,base_mid))
circle(10);
}
module level_base_cutout(rad) {
$fn=50;
translate(fangle3(0,base_mid))
sphere(rad);
translate(fangle3(120,base_inner))
sphere(rad);
translate(fangle3(120,base_outer))
sphere(rad);
translate(fangle3(120,base_mid))
rotate([90,0,-120])
cylinder(r1=rad,r2=rad,h=(base_outer-base_inner),center=true);
translate(fangle3(240,base_inner))
sphere(rad);
translate(fangle3(240,base_outer))
sphere(rad);
translate(fangle3(240,base_mid))
rotate([90,0,-240])
cylinder(r1=rad,r2=rad,h=(base_outer-base_inner),center=true);
}
//Azimuth Ring
module azimuth_ring() {
union()
{
difference() {
color("yellow")
translate([0,0,0])
linear_extrude(height = ring_height, center = false,$fn=1)
ring(OuterRad,InnerRad);
color("red")
translate([0,0,ring_height - number_height])
linear_extrude(height = number_height + 0.1, center = false,$fn=1)
scale_numbers();
}
color("green")
translate([0,0,ring_height])
linear_extrude(height = scale_height, center = false,$fn=1)
scale();
}
}
module ring(radOuter,radInner) {
$fn=50;
difference() {
circle(radOuter);
circle(radInner);
}
}
module scale_numbers() {
$fn=10;
color("yellow")
for (i = [0:10:350])
{
translate([sin(i)*(ScaleRad+TextOffset),cos(i)*(ScaleRad+TextOffset),0])
rotate([0,0,i*-1])
text(text=str(i/10),font="Arial Rounded MT Bold:style=Regular", size=TextSize, halign="center");
//square([1,10],false);
}
}
module scale() {
$fn=10;
color("green")
for (i = [0:10:360])
{
translate([sin(i)*ScaleRad,cos(i)*ScaleRad,0])
rotate([0,0,i*-1])
translate([0,len10/2,0])
square([1,len10],true);
}
color("red")
for (i = [0:5:360])
{
translate([sin(i)*ScaleRad,cos(i)*ScaleRad,0])
rotate([0,0,i*-1])
translate([0,len5/2,0])
square([1,len5],true);
}
/*
color("blue")
for (i = [0:1:360])
{
translate([sin(i)*ScaleRad,cos(i)*ScaleRad,0])
rotate([0,0,i*-1])
translate([0,len1 / 2,0])
square([0.5,len1],true);
}
*/
}
```

This is probably as far as I will go with this project. Found a spare universal motor driver and motorised az/el mount I can attach a laser pointer too, so just gonna use that instead. I can write a simple program to control the motor driver over serial port, and have it point where I want it to point with high accuracy.

I might however rip out the level base, if leveling the tripod to sliding the legs in and out is too cumbersome.