def detect_color(queue: Queue, filename: str, location: List[int]): queue.put(QueueMessage('Starting', task_name='Detect Color')) radius_offset = 60 img = cv.imread(filename) hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) x, y, z = location mask = np.zeros(img.shape[:2], dtype="uint8") cv.circle(mask, (x, y), z - radius_offset, 255, -1) result = {} plot_color = ['r', 'g', 'b'] hsv_var = ['h', 's', 'v'] for i, col in enumerate(plot_color): hist = cv.calcHist([hsv], [i], mask, [256], [0, 256]) result[hsv_var[i]] = hist plt.plot(hist, color=col) plt.xlim([0, 256]) queue.put(QueueMessage('Saving Files', task_name='Detect Circle')) hist_file = '{}_hist.png'.format(filename[:-3]) plt.savefig(hist_file, bbox_inches='tight') json_file = '{}_hist.json'.format(filename[:-3]) with open(json_file, 'w') as jf: json.dump(result, jf, indent=4) queue.put(QueueMessage('Finished', task_name='Detect Circle')) return (hist_file, json_file, result)
def move_paper(queue: Queue, completed: int, jog: bool = False): """ Moves new paper into position Need to somehow track roll usage """ queue.put(QueueMessage('Starting', task_name='Move Paper')) speed = 2 # rad / second length = 20 # mm total_length = 20 * completed inner_radius = 123 # TODO thickness = 0.05 # used paper thickness.... TODO radius = sqrt(total_length * thickness / 3.14159 + inner_radius * inner_radius) # https://math.stackexchange.com/questions/2145821/calculating-the-length-of-tape-when-it-is-wound-up theta = length / radius run_time = theta / speed if (jog): queue.put(QueueMessage('Jog mode', task_name='Move Paper')) run_time = run_time / 10 queue.put(QueueMessage('Turning Servo by {rad} rad, time required {time} s'.format( rad=theta, time=run_time), task_name='Move Paper')) servo = maestro.Controller() servo.setAccel(0, 4) servo.setSpeed(0, 10) servo.setTarget(0, 6000) # turn continuous servo time.sleep(run_time) servo.setTarget(0, 1500) # stop servo queue.put(QueueMessage('Finished', task_name='Move Paper'))
def movement_feedback(queue: Queue, completed: int, test_time: str): """ Ensures the postition of the paper is correct for the next test """ queue.put(QueueMessage('Starting', task_name='Movement Feedback')) x = 340 i = 0 queue.put( QueueMessage('Initial Paper movement', task_name='Movement Feedback')) move_paper(queue, completed) filename = take_photo(queue, test_time) location = detect_circle(queue, filename) incorrect = abs(location[0] - x) > 20 while (incorrect): i = i + 1 queue.put( QueueMessage('Paper Jog: {}'.format(i), task_name='Movement Feedback')) os.remove(filename) move_paper(queue, completed, True) filename = take_photo(queue, test_time) location = detect_circle(queue, filename) incorrect = abs(location[0] - x) > 20 queue.put(QueueMessage('Finished', task_name='Movement Feedback')) return location
def take_photo(queue: Queue, test_time: str): """ """ queue.put(QueueMessage('Starting', task_name='Camera')) queue.put(QueueMessage('Turning on LEDs', task_name='Camera')) GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(23, GPIO.OUT) GPIO.setup(24, GPIO.OUT) GPIO.setup(25, GPIO.OUT) GPIO.output(23, GPIO.HIGH) GPIO.output(24, GPIO.HIGH) GPIO.output(25, GPIO.HIGH) time.sleep(1) camera = PiCamera() queue.put(QueueMessage('Taking photo', task_name='Camera')) filename = '/home/pi/nutrient_tester_rpi/{}.jpg'.format(test_time) camera.capture(filename) queue.put( QueueMessage('Photo saved as "{}"'.format(filename), task_name='Camera')) camera.close() GPIO.output(23, GPIO.LOW) GPIO.output(24, GPIO.LOW) GPIO.output(25, GPIO.LOW) queue.put(QueueMessage('Finished', task_name='Camera')) return filename
def run_heater(queue: Queue): """ """ queue.put(QueueMessage('Starting', task_name='Heater')) queue.put(QueueMessage('Turning on heater for {time} seconds'.format( time=300), task_name='Heater')) # TODO set pin to high time.sleep(300) # 5 minutes queue.put(QueueMessage('Finished', task_name='Heater'))
def just_add_water(queue: Queue, completed: int): """ put water sample and reactant onto paper """ queue.put(QueueMessage('Starting', task_name='Sampling')) queue.put(QueueMessage('Adding Water', task_name='Sampling')) move_water_valve(1) # push out some water then sucking back in move_water_linear([2000, 0]) # move valve to inlet so no liquid can go on paper queue.put(QueueMessage('Adding Reactant', task_name='Sampling')) move_water_valve(2) move_reactant_linear(completed) queue.put(QueueMessage('Finished', task_name='Sampling'))
def pre_test_clean(queue: Queue): """ Flush the pipe with air before test begins Assume water actuator starts in extended position """ # suck in air queue.put(QueueMessage('Starting', task_name='Pre-Test Cleaning')) queue.put(QueueMessage('Sucking in Air', task_name='Pre-Test Cleaning')) move_water_valve(1) move_water_linear([0]) queue.put(QueueMessage('Pushing out air, then pulling in water', task_name='Pre-Test Cleaning')) move_water_valve(2) # push out air, pull in water move_water_linear([5000, 1000]) queue.put(QueueMessage('Finished', task_name='Pre-Test Cleaning'))
def post_test_clean(queue: Queue): """ Empty tubes so that there is only air """ # make doubly sure queue.put(QueueMessage('Starting', task_name='Post-test Clean')) queue.put(QueueMessage('Push out water', task_name='Post-test Clean')) move_water_valve(2) # push water out move_water_linear([5000]) # take in more air queue.put(QueueMessage('Pulling in air', task_name='Post-test Clean')) move_water_valve(1) move_water_linear(0) queue.put(QueueMessage('Push out air', task_name='Post-test Clean')) move_water_valve(2) move_water_linear([5000]) queue.put(QueueMessage('Finished', task_name='Post-test Clean'))
def test_main(queue: Queue, completed: int, test_time: str): try: queue.put(QueueMessage('Starting', task_name='Test Main')) timer = time.time() pre_test_clean(queue) just_add_water(queue, completed) # tube cleaning can run async at while we are waiting for heater clean = Thread(target=post_test_clean, args=(queue, )) clean.start() run_heater(queue) location = movement_feedback(queue, completed, test_time) result = detect_color(queue, filename, location) # TODO add files to be sent, analysis # it doesnt really matter when cleaning finishes as long as it does by the end clean.join() queue.put(QueueMessage('Finished in: ' + str(time.time() - timer), task_name='Test Main')) except: queue.put(QueueMessage('Unexpected Exception', 4, sys.exc_info()))
def detect_circle(queue: Queue, filename: str): queue.put(QueueMessage('Starting', task_name='Detect Circle')) img = cv.imread(filename) img = cv.medianBlur(img, 5) # 256 shades of gray gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # detect circles circles = cv.HoughCircles(gray_img, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0) circles = np.uint16(np.around(circles)) queue.put( QueueMessage('Circle detected at: {}'.format(str(circles[0][0])), task_name='Detect Circle')) queue.put(QueueMessage('Finished', task_name='Detect Circle')) return circles[0][0] # return first circle detected