12. Machine¶
I worked with Aaron Logan, Jack Donnelly, and Jada Greene. The full group work for our machine can be found here. All files can be found there as well.
My contributions to the group included designing the corner connectors and y axis carriage as well as playing a large part in the design of the wood base and the x axis carriage. I also wrote the final code implementing parts that myself and other members of the team tested separately.
Concept¶
Our machine would take data on the location of Elon Musk’s private jet (or any other plane we choose) from a flight api and move a laser pointer to that corresponding location on a map.
Corner Connectors¶
The design for this was fairly simple with just a 3 pronged piece with holes to press fit the steel rods into.
Y axis carriage¶
The hole in the middle mounts the laser on it with the 2 slots for connecting the belt on either side on the top. The 2 holes mount it to the steel rods via linear bearings, and all the edges have a fillet to them. This was made to be as small as possible both to minimize weight the gantry would have to move and to maximize the amount of usable space in the middle.
Base¶
I made the design svg in cuttle while my groupmates used it to make a file for cnc cutting it. It was fairly simple with 4 holes in each of the four corners to have the vertical steel rods go into and a rectangle that would be pocketed out for the map to go into. The pocket cut for the map was made slightly bigger than the map for 2 reasons: to be able to be easily slid in and to account for the round bit not cutting all the way into the corner and causing the map not to fit, but using dogbones would not be aesthetically pleasing, so making the pocket bigger would solve the problem while keeping aesthetic elements.
X axis carriage¶
I worked with Aaron Logan on this. He did the CAD work while I advised him based on how I did the y axis carriage, and I determined measurements for it based on the other parts of the machine.
Code¶
The final code I wrote and put together was split in 3 files
apiData.py¶
This had functions involving getting raw data from the api and converting it from latitude longitude to inches on the map.
import requests
import math
from numpy import log as ln
def get_lat_lon(callsign='N502SX'):
# uses the api to get the latitude and longitude and returns a list of 2 ints
url = 'https://adsbexchange-com1.p.rapidapi.com/v2/callsign/' + callsign + '/'
headers = {
"X-RapidAPI-Host": "adsbexchange-com1.p.rapidapi.com",
"X-RapidAPI-Key": "27d6e0192emsh0b0d9c0364793c1p175136jsn803c2abbbc60"
}
response = requests.get(url, headers=headers)
data = response.text
lat, lon = 0.0, 0.0
flying = False
for i in range(len(data)):
if data[i: i + 6] == '"lat":':
lenNum = 1
while data[i + lenNum] != ',':
lenNum += 1
lat = float(data[i + 6: i + lenNum])
flying = True
elif data[i: i + 6] == '"lon":':
lenNum = 1
while data[i + lenNum] != ',':
lenNum += 1
lon = float(data[i + 6: i + lenNum])
flying = True
return [lon, lat], flying
def lat_lon_to_xy(pos):
# Define the size of map
mapWidth = 584.2
mapHeight = 431.8
# get x value
x = (pos[0] + 180) * (mapWidth / 360)
# convert from degrees to radians
latRad = (pos[1] * math.pi) / 180
# get y value
mercN = ln(math.tan((math.pi / 4) + (latRad / 2)))
y = (mapHeight / 2) - (mapWidth * mercN / (2 * math.pi))
return [x, mapHeight-y] # mapHeight - y makes the origin point from the bottom left corner for the latitude
stepper.py¶
This had a class for the stepper motor that used a combination of code from my outputs week (converted from arduino to python of course) and work from Aaron and Jada.
import RPi.GPIO as GPIO
from time import sleep
class Stepper():
def __init__(self, chan, delayTime):
self.chan = chan
self.delayTime = delayTime
self.phase = 0
def run_step(self):
if self.phase == 0:
GPIO.output(self.chan, (GPIO.HIGH, GPIO.LOW, GPIO.HIGH, GPIO.LOW))
elif self.phase == 1:
GPIO.output(self.chan, (GPIO.LOW, GPIO.HIGH, GPIO.HIGH, GPIO.LOW))
elif self.phase == 2:
GPIO.output(self.chan, (GPIO.LOW, GPIO.HIGH, GPIO.LOW, GPIO.HIGH))
elif self.phase == 3:
GPIO.output(self.chan, (GPIO.HIGH, GPIO.LOW, GPIO.LOW, GPIO.HIGH))
sleep(self.delayTime)
def step_cw(self, num_steps):
for i in range(num_steps):
self.phase = (self.phase + 1) % 4
self.run_step()
def step_ccw(self, num_steps):
for i in range(num_steps):
self.phase = (self.phase - 1) % 4
self.run_step()
def clear(self):
GPIO.output(self.chan, (GPIO.LOW, GPIO.LOW, GPIO.LOW, GPIO.LOW))
main.py¶
This put everything together with keeping track of the gantry while taking data from the api and moving accordingly.
import apiData #hello
from stepper import Stepper
import math
from time import sleep
import RPi.GPIO as GPIO
__name__ = 'main'
if __name__ == 'main':
gear_diameter = 12
gear_cirumference = 12 * math.pi
step_dist = gear_cirumference / 200
GPIO.setmode(GPIO.BOARD)
motorx_chan = (29, 31, 33, 35)
motory_chan = (32, 36, 38, 40)
GPIO.setup(motorx_chan, GPIO.OUT)
GPIO.setup(motory_chan, GPIO.OUT)
stepperx = Stepper(motorx_chan, 0.005) # add pins and stuff later
steppery = Stepper(motory_chan, 0.005) # add pins and stuff later
callsign = input('Enter a callsign of a plane to track: ')
# steps from corner 9.42477796076938mm each direction to get to map 0
#stepperx.step_cw(50)
#steppery.step_cw(50)
pos = [0, 0]
while True:
latLon, flying = apiData.get_lat_lon(callsign)
print(latLon)
if not flying:
stepperx.clear()
steppery.clear()
sleep(60)
else:
new_pos = apiData.lat_lon_to_xy(latLon)
new_pos[1] -= 31.75
new_pos[1] %= 431.8
print(new_pos)
while new_pos[0] > pos[0]:
stepperx.step_cw(1)
pos[0] += step_dist
while new_pos[0] < pos[0]:
stepperx.step_ccw(1)
pos[0] -= step_dist
while new_pos[1] > pos[1]:
steppery.step_ccw(1)
pos[1] += step_dist
while new_pos[1] < pos[1]:
steppery.step_cw(1)
pos[1] -= step_dist
stepperx.clear()
steppery.clear()
sleep(60)