diff --git a/.gitignore b/.gitignore index 51fbad32bf30b3c45a40f8900f8619fcf8952b4e..fbb8c0eedf313e85c0e3903dadf3391c09928306 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,5 @@ cython_debug/ # custom weights/ creds.json -src/creds.py +creds.py +.log diff --git a/farmbot_yolo/client.py b/farmbot_yolo/client.py index 4aa4344f18ed1381e7a08e7331f46078db7cd20f..45d5f9b8cdcad40e231044a67c5318ffe1069cc4 100755 --- a/farmbot_yolo/client.py +++ b/farmbot_yolo/client.py @@ -1,3 +1,4 @@ +<<<<<<<< HEAD:farmbot_yolo/client.py ''' Communicate with the server at the manufacturer Not useful for the local drive script @@ -139,3 +140,345 @@ class FarmbotClient(object): logging.debug("> _on_message [%s] [%s]", msg.topic, resp) if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: self.rpc_status = resp['kind'] +|||||||| 90c14bb:src/client.py +''' +Communicate with the server at the manufacturer +Not useful for the local drive script +''' +import paho.mqtt.client as mqtt +import json +import time +from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) +import logging #日志模块 + +# values over max (and under min) will be clipped +MAX_X = 2400 +MAX_Y = 1200 +MAX_Z = 469 # TODO test this one! + +def coord(x, y, z): + return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 + +def move_request(x, y, z): + return {"kind": "rpc_request", # 返回 json对象,对象内含数组 + "args": {"label": ""}, + "body": [{"kind": "move_absolute", + "args": {"location": coord(x, y, z), + "offset": coord(0, 0, 0), + "speed": 100}}]} + +def take_photo_request(): + return {"kind": "rpc_request", + "args": {"label": ""}, #label空着是为了在blocking_request中填上uuid,唯一识别码 + "body": [{"kind": "take_photo", "args": {}}]} + +def clip(v, min_v, max_v): + if v < min_v: return min_v + if v > max_v: return max_v + return v + +class FarmbotClient(object): + + def __init__(self, device_id, token): + + self.device_id = device_id + self.client = mqtt.Client() # 类元素继承了另一个对象 + self.client.username_pw_set(self.device_id, token) #传入 用户名和密码 + self.client.on_connect = self._on_connect #??? + self.client.on_message = self._on_message + + logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", + filename='farmbot_client.log', + filemode='a') + console = logging.StreamHandler() + console.setLevel(logging.INFO) + console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) + logging.getLogger('').addHandler(console) + + self.connected = False + self.client.connect("clever-octopus.rmq.cloudamqp.com", 1883, 60) #前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port + self.client.loop_start() + # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 + + + def shutdown(self): + self.client.disconnect() + self.client.loop_stop() + + def move(self, x, y, z): + x = clip(x, 0, MAX_X) + y = clip(y, 0, MAX_Y) + z = clip(z, 0, MAX_Z) + status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 + logging.info("MOVE (%s,%s,%s) [%s]", x, y, z, status_ok) #存日志,包括执行了什么“move x y z +返回值 ” + + def take_photo(self): + # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? + status_ok = self._blocking_request(take_photo_request()) + logging.info("TAKE_PHOTO [%s]", status_ok) + + def _blocking_request(self, request, retries_remaining=3): + if retries_remaining==0: + logging.error("< blocking request [%s] OUT OF RETRIES", request) #尝试3次,然后在日志中记录错误 + return False + + self._wait_for_connection() #在哪定义的? + + # assign a new uuid for this attempt + self.pending_uuid = str(uuid4()) + request['args']['label'] = self.pending_uuid #接收move_request函数的json对象 + logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) + + # send request off 发送请求 + self.rpc_status = None + self.client.publish("bot/" + self.device_id + "/from_clients", json.dumps(request)) + + # wait for response + timeout_counter = 600 # ~1min 等待1s + while self.rpc_status is None: #这个self.rpc_status 是应答的flag + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + logging.warn("< blocking request TIMEOUT [%s]", request) #时间到了,无应答 + return self._blocking_request(request, retries_remaining-1) + self.pending_uuid = None + + # if it's ok, we're done! + if self.rpc_status == 'rpc_ok': + logging.debug("< blocking request OK [%s]", request) + return True + + # if it's not ok, wait a bit and retry + if self.rpc_status == 'rpc_error': + logging.warn("< blocking request ERROR [%s]", request) + time.sleep(1) + return self._blocking_request(request, retries_remaining-1) + + # unexpected state (???) + msg = "unexpected rpc_status [%s]" % self.rpc_status + logging.error(msg) + raise Exception(msg) + + + def _wait_for_connection(self): + # TODO: better way to do all this async event driven rather than with polling :/ + timeout_counter = 600 # ~1min + while not self.connected: #用一个self.connected判断连上了没有,若没连上,等待 + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + raise Exception("unable to connect") + + def _on_connect(self, client, userdata, flags, rc): + logging.debug("> _on_connect") + self.client.subscribe("bot/" + self.device_id + "/from_device") + self.connected = True + logging.debug("< _on_connect") + + def _on_message(self, client, userdata, msg): + resp = json.loads(msg.payload.decode()) + if resp['args']['label'] != 'ping': + logging.debug("> _on_message [%s] [%s]", msg.topic, resp) + if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: + self.rpc_status = resp['kind'] +======== +''' +Communicate with the server at the manufacturer +Not useful for the local drive script +''' +import paho.mqtt.client as mqtt +import json +import time +from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) +import logging #日志模块 + +# values over max (and under min) will be clipped +MAX_X = 2400 +MAX_Y = 1200 +MAX_Z = 469 # TODO test this one! + + +def coord(x, y, z): + return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 + +def move_request(x, y, z): + return {"kind": "rpc_request", # 返回 json对象,对象内含数组 + "args": {"label": ""}, + "body": [{"kind": "move_absolute", + "args": {"location": coord(x, y, z), + "offset": coord(0, 0, 0), + "speed": 100}}]} + +def read_pin_request(pin_number, pin_mode="digital"): + modes = {"digital": 0, "analog": 1} + + if pin_mode != "digital": + raise NotImplementedError() + + return {"kind": "rpc_request", + "args": {"label": ""}, + "body": [{"kind": "read_pin", + "args": { + "label": "pin" + str(pin_number), + "pin_mode": modes[pin_mode] or (modes["digital"]), + "pin_number": pin_number + }}]} + +def write_pin_request(pin_number, pin_value, pin_mode="digital"): + modes = {"digital": 0, "analog": 1} + + if pin_mode != "digital": + raise NotImplementedError() + + return {"kind": "rpc_request", + "args": {"label": ""}, + "body": [{"kind": "write_pin", + "args": { + "pin_mode": modes[pin_mode] or (modes["digital"]), + "pin_number": pin_number, + "pin_value": pin_value + } + } + ] + } + +def toggle_pin_request(pin_number): + return {"kind": "rpc_request", + "args": {"label": ""}, + "body": [{"kind": "toggle_pin", + "args": { + "pin_number": pin_number, + } + } + ] + } + +def take_photo_request(): + return {"kind": "rpc_request", + "args": {"label": ""}, #label空着是为了在blocking_request中填上uuid,唯一识别码 + "body": [{"kind": "take_photo", "args": {}}]} + +def clip(v, min_v, max_v): + if v < min_v: return min_v + if v > max_v: return max_v + return v + +class FarmbotClient(object): + + def __init__(self, device_id, token): + + self.device_id = device_id + self.client = mqtt.Client() # 类元素继承了另一个对象 + self.client.username_pw_set(self.device_id, token) #传入 用户名和密码 + self.client.on_connect = self._on_connect #??? + self.client.on_message = self._on_message + + logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", + filename='farmbot_client.log', + filemode='a') + console = logging.StreamHandler() + console.setLevel(logging.INFO) + console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) + logging.getLogger('').addHandler(console) + + self.connected = False + self.client.connect("clever-octopus.rmq.cloudamqp.com", 1883, 60) #前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port + self.client.loop_start() + # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 + + + def shutdown(self): + self.client.disconnect() + self.client.loop_stop() + + def move(self, x, y, z): + x = clip(x, 0, MAX_X) + y = clip(y, 0, MAX_Y) + z = clip(z, 0, MAX_Z) + status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 + logging.info("MOVE (%s,%s,%s) [%s]", x, y, z, status_ok) #存日志,包括执行了什么“move x y z +返回值 ” + + def take_photo(self): + # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? + status_ok = self._blocking_request(take_photo_request()) + logging.info("TAKE_PHOTO [%s]", status_ok) + + def read_pin(self, pin_number, pin_mode="digital"): + status_ok = self._blocking_request(read_pin_request(pin_number, pin_mode=pin_mode)) + logging.info(f"READ PIN (pin_number: {pin_number}) [{status_ok}]") + + def write_pin(self, pin_number, pin_value, pin_mode="digital"): + status_ok = self._blocking_request(write_pin_request(pin_number, pin_value, pin_mode=pin_mode)) + logging.info(f"WRITE PIN (pin_number: {pin_number}, pin_value: {pin_value}) [{status_ok}]") + + def toggle_pin(self, pin_number): + status_ok = self._blocking_request(toggle_pin_request(pin_number)) + logging.info(f"TOGGLE PIN (pin_number: {pin_number}) [{status_ok}]") + + def _blocking_request(self, request, retries_remaining=3): + if retries_remaining==0: + logging.error("< blocking request [%s] OUT OF RETRIES", request) #尝试3次,然后在日志中记录错误 + return False + + self._wait_for_connection() #在哪定义的? + + # assign a new uuid for this attempt + self.pending_uuid = str(uuid4()) + request['args']['label'] = self.pending_uuid #接收move_request函数的json对象 + logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) + + # send request off 发送请求 + self.rpc_status = None + self.client.publish("bot/" + self.device_id + "/from_clients", json.dumps(request)) + + # wait for response + timeout_counter = 600 # ~1min 等待1s + while self.rpc_status is None: #这个self.rpc_status 是应答的flag + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + logging.warn("< blocking request TIMEOUT [%s]", request) #时间到了,无应答 + return self._blocking_request(request, retries_remaining-1) + self.pending_uuid = None + + # if it's ok, we're done! + if self.rpc_status == 'rpc_ok': + logging.debug("< blocking request OK [%s]", request) + return True + + # if it's not ok, wait a bit and retry + if self.rpc_status == 'rpc_error': + logging.warn("< blocking request ERROR [%s]", request) + time.sleep(1) + return self._blocking_request(request, retries_remaining-1) + + # unexpected state (???) + msg = "unexpected rpc_status [%s]" % self.rpc_status + logging.error(msg) + raise Exception(msg) + + + def _wait_for_connection(self): + # TODO: better way to do all this async event driven rather than with polling :/ + timeout_counter = 600 # ~1min + while not self.connected: #用一个self.connected判断连上了没有,若没连上,等待 + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + raise Exception("unable to connect") + + def _on_connect(self, client, userdata, flags, rc): + logging.debug("> _on_connect") + self.client.subscribe("bot/" + self.device_id + "/from_device") + self.connected = True + logging.debug("< _on_connect") + + def _on_message(self, client, userdata, msg): + resp = json.loads(msg.payload.decode()) + if resp['args']['label'] != 'ping': + logging.debug("> _on_message [%s] [%s]", msg.topic, resp) + if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: + self.rpc_status = resp['kind'] +>>>>>>>> master:src/utils/client.py diff --git a/farmbot_yolo/download.py b/farmbot_yolo/download.py new file mode 100644 index 0000000000000000000000000000000000000000..67caace59ae348c9a5181e23e9d0faebee39516b --- /dev/null +++ b/farmbot_yolo/download.py @@ -0,0 +1,102 @@ +"""Download images from Farmbot instance.""" +import argparse +import os +from pathlib import Path +from typing import List + +import requests + +import utils.creds as creds + + +# note: download only returns 100 at a time! +# note: we are currently ignoreing placeholders + +DEBUG_SKIP_DELETE_FILES = True + +IMG_FILE_SUFFIX = ".jpg" + +REQUEST_HEADERS = { + "Authorization": "Bearer " + creds.token, + "content-type": "application/json", +} + + +def download_images(directory: os.PathLike, delete_after=False) -> List[str]: + """Download all images on server, optionally deleting after download. + + Parameters + ---------- + directory + directory to store images in + + Raises + ------ + RuntimeError + If the server gives a bad response (not 200). + + Returns + ------- + list of str + List of filepaths with downloaded images + """ + response = requests.get("https://my.farmbot.io/api/images", headers=REQUEST_HEADERS) + json_response = response.json() + + if response.status_code != 200: + raise RuntimeError(f"Got status code {response.status_code}.") + + print(json_response) + print(f"Got a response containing {len(json_response)}") + + if len(json_response) < 1: + return [] + + img_paths = [] + + for img_dict in json_response: + if "placehold.it" in img_dict["attachment_url"]: + print("IGNORE! placeholder", img_dict["id"]) + continue + + server_path: str = img_dict["meta"]["name"] + + if not server_path.startswith("/tmp/images"): + print("meta name does not start with /tmp/images") + continue + + filename = Path(server_path).stem + IMG_FILE_SUFFIX + filepath = Path(directory) / filename + + print(">", filepath) + + # download image from google storage and save locally + if filepath.exists(): + print("File exists, skipping") + continue + + img_req = requests.get(img_dict["attachment_url"], allow_redirects=True) + + with filepath.open(mode="wb") as fp: + fp.write(img_req.content) + + img_paths.append(filepath) + + # post delete from cloud storage + if delete_after: + requests.delete( + f"https://my.farmbot.io/api/images/{img_dict['id']}", + headers=REQUEST_HEADERS, + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Farmbot YOLO image downloader") + parser.add_argument( + "download_dir", type=Path, help="Directory to download images too." + ) + parser.add_argument("-d", "--delete", action="store_true") + + args = parser.parse_args() + + download_images(args.download_dir, delete_after=args.delete) diff --git a/farmbot_yolo/gripper.py b/farmbot_yolo/gripper.py index d53b714fc353c24ca9f0435d3f0dc8262a09aa92..27b72215533b7f2414874aca6fb8068055dd86e7 100755 --- a/farmbot_yolo/gripper.py +++ b/farmbot_yolo/gripper.py @@ -1,11 +1,24 @@ -#!/usr/bin/env python3 -import serial +"""Functions to manipulate gripper. + +TODO: Integrate with FarmbotClient or FarmbotYoloClient +""" +from utils.client import FarmbotClient +from utils.creds import device_id +from utils.creds import token + +GRIPPER_PIN = 12 +GRIPPER_OPEN_STATE = 0 +GRIPPER_CLOSED_STATE = 1 + def gripper_open(): - ser = serial.Serial('/dev/ttyUSB0') - ser.write(str.encode("o")) - ser.close + """Manipulate gripper by setting pin to 1.""" + client = FarmbotClient(device_id, token) + client.write_pin(GRIPPER_PIN, GRIPPER_OPEN_STATE, pin_mode="digital") + client.shutdown() + def gripper_close(): - ser = serial.Serial('/dev/ttyUSB0') - ser.write(str.encode("c")) - ser.close \ No newline at end of file + """Manipulate gripper by setting pin to 0.""" + client = FarmbotClient(device_id, token) + client.write_pin(GRIPPER_PIN, GRIPPER_CLOSED_STATE, pin_mode="digital") + client.shutdown() diff --git a/farmbot_yolo/main.py b/farmbot_yolo/main.py index 3ae2d0fb5f624a9d5d75b607ea641982f252c25a..5295b4e6bd94d337197f2f567cd3d2e31ed4a3dd 100644 --- a/farmbot_yolo/main.py +++ b/farmbot_yolo/main.py @@ -48,7 +48,6 @@ def remove_overlap(table_coordinate:DataFrame, tolerance=50.00)->DataFrame: return table_coordinate - def remove_temp(path: Path)-> None: ''' Clean temporary files, i.e., photos, location.txt, annotations diff --git a/farmbot_yolo/move.py b/farmbot_yolo/move.py index 85eeba094f630110b2bee97ae25dcb72061daa83..064cf5518240f03df8a79a0d1239cab629c89afb 100644 --- a/farmbot_yolo/move.py +++ b/farmbot_yolo/move.py @@ -1,15 +1,17 @@ -''' +""" Author: Ziliang Xiong This script is for all the functions that drive Farmbot to Move, including: 1. Taking Photos 2. Move to an assigned point (x, y, z) 3. Sweep the planting bed 4. Grip a target Note: it is for remote server, can ben replaced by a local script -''' +""" from argparse import ArgumentParser from logging import getLogger from os import path, makedirs, system -from time import sleep, strftime, time -#from serial import Serial, PARITY_NONE, STOPBITS_ONE, EIGHTBITS +import sys +from time import sleep, strftime, time + +# from serial import Serial, PARITY_NONE, STOPBITS_ONE, EIGHTBITS from requests.api import delete from typing import List from pathlib import Path @@ -20,14 +22,14 @@ from datetime import timezone, datetime from dateutil.parser import parse from requests import get, delete -from creds import read_credentials +import creds from client import FarmbotClient - _SWEEEP_HEIGHT = 0 Logger = getLogger(__name__) + class Opts: def __init__(self, min_x, max_x, min_y, max_y, delta, offset, flag): self.min_x = min_x @@ -37,11 +39,20 @@ class Opts: self.delta = delta self.offset = offset self.flag = flag - -def scan(img_path: Path, location_path: Path, # smaller delta - min_x=0, max_x=1300, min_y=0, max_y=1000, delta=1000, offset=0, flag=True) -> List: #里面的数字需要重新测量 - ''' + +def scan( + img_path: Path, + location_path: Path, # smaller delta + min_x=0, + max_x=1175, + min_y=0, + max_y=974, + delta=300, + offset=0, + flag=True, +) -> List: # 里面的数字需要重新测量 + """ scan the bed at a certain height, first move along x axis, then y, like a zig zag; Taking pictures and record the location of the camera that corresponds to the picture The default value of x, y should be from the measurement of Farmbot @@ -53,7 +64,7 @@ def scan(img_path: Path, location_path: Path, # smaller delta offset: flag: for degging, if true, don't actually drive FarmBot Output: none - ''' + """ opts = Opts(min_x, max_x, min_y, max_y, delta, offset, flag) creds = read_credentials() @@ -65,95 +76,98 @@ def scan(img_path: Path, location_path: Path, # smaller delta y_range = reversed(y_range) sweep_y_negative = not sweep_y_negative for y in y_range: - pts.append((x+opts.offset, y+opts.offset)) + pts.append((x + opts.offset, y + opts.offset)) - Logger.info('Moving pattern generated') + Logger.info("Moving pattern generated") if opts.flag: - Logger.info('Run without sweep') + Logger.info("Run without sweep") exit() client = FarmbotClient(creds["device_id"], creds["token"]) - client.move(0, 0, _SWEEEP_HEIGHT) # ensure moving from original + client.move(0, 0, _SWEEEP_HEIGHT) # ensure moving from original for x, y in pts: - client.move(x, y, _SWEEEP_HEIGHT) # move camera - take_photo(img_path) + client.move(x, y, _SWEEEP_HEIGHT) # move camera + # take_photo(img_path) + client.take_photo() client.shutdown() # write to img/location - with open(path.join(location_path, "location.txt"), 'w') as f: + with open(path.join(location_path, "location.txt"), "w") as f: for postion in pts: - f.write('{} {} {}\n'.format(postion[0], postion[1], _SWEEEP_HEIGHT)) - return None + f.write("{} {} {}\n".format(postion[0], postion[1], _SWEEEP_HEIGHT)) + return None -def take_photo(img_path: Path): - HERE = path.dirname(__file__) - IMG_DIR = path.join(HERE, img_path) +def take_photo(): + client = FarmbotClient(creds.device_id, creds.token) + client.take_photo() + # download image + system("python ./utils/download.py") - with request.urlopen('http://localhost:8080/?action=snapshot') as photo: - filename = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + ".jpg" - with open(path.join(IMG_DIR, filename), mode="wb") as save_file: - save_file.write(photo.read()) +# def take_photo(img_path: Path): +# HERE = path.dirname(__file__) +# IMG_DIR = path.join(HERE, img_path) -def simple_move(x: int, y: int, z: int) -> None: - ''' +# with request.urlopen('http://localhost:8080/?action=snapshot') as photo: +# filename = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + ".jpg" +# with open(path.join(IMG_DIR, filename), mode="wb") as save_file: +# save_file.write(photo.read()) + + +def simple_move(x: int, y: int, z: int) -> None: + """ Move to a place, if flag is true, take a picture Input: x, y,z: destination point photo: take a pic or not - ''' + """ creds = read_credentials() client = FarmbotClient(creds["device_id"], creds["token"]) - client.move(x, y, z) + client.move(x, y, z) client.shutdown() return None -if __name__ == '__main__': +if __name__ == "__main__": parser = ArgumentParser() parser.add_argument( - '-m', - '--mode', + "-m", + "--mode", type=int, - help='Mode for FarmBot, 1 for simple move with an assigned detination, 2 for scaning' + help="Mode for FarmBot, 1 for simple move with an assigned detination, 2 for scaning", ) parser.add_argument( - '-l', - '--log', - type=Path, - default='../log/move.log', - help='Path to the log file' + "-l", "--log", type=Path, default="../log/move.log", help="Path to the log file" ) parser.add_argument( - '-p', - '--photo', + "-p", + "--photo", type=Path, default="../img", - help='Mode for FarmBot, 1 for simple move with an assigned detination, 2 for scaning' + help="Mode for FarmBot, 1 for simple move with an assigned detination, 2 for scaning", ) parser.add_argument( - '-loc', - '--locations', + "-loc", + "--locations", type=Path, - default='../img/locations/', - help='the path to txt files contains locations from encoders corresponds to each photo' + default="../img/locations/", + help="the path to txt files contains locations from encoders corresponds to each photo", ) - parser.add_argument('-v', '--verbose', action='store_true', help='Verbose mode') + parser.add_argument("-v", "--verbose", action="store_true", help="Verbose mode") arguments = parser.parse_args() - if arguments.mode == 1: - Logger.info('Input the destination:') - destination_x = int(input('X:')) - destination_y = int(input('Y:')) - destination_z = int(input('Z:')) - photo = True if input('Take a photo or not?[Y/N]:') == 'Y' else False + Logger.info("Input the destination:") + destination_x = int(input("X:")) + destination_y = int(input("Y:")) + destination_z = int(input("Z:")) simple_move_start = time() - simple_move(destination_x, destination_y, destination_z, photo) - Logger.info(f'time cost {time()-simple_move_start}') + simple_move(destination_x, destination_y, destination_z) + Logger.info(f"time cost {time()-simple_move_start}") elif arguments.mode == 2: scan(arguments.photo, arguments.locations, flag=False) + # take_photo(arguments.photo) + elif arguments.mode == 3: + take_photo() else: - Logger.error('Wrong mode number {arguments.mode}') - - + Logger.error("Wrong mode number {arguments.mode}") diff --git a/img/WIN_20211103_21_16_18_Pro.jpg b/img/WIN_20211103_21_16_18_Pro.jpg deleted file mode 100644 index 27b585013a55f2853a29424ccfeb124cc719edb1..0000000000000000000000000000000000000000 Binary files a/img/WIN_20211103_21_16_18_Pro.jpg and /dev/null differ diff --git a/img/annotations/WIN_20211103_21_16_18_Pro.txt b/img/annotations/WIN_20211103_21_16_18_Pro.txt deleted file mode 100644 index 7fd6b5a6fdeeb230cbf138bde46f802ea1928095..0000000000000000000000000000000000000000 --- a/img/annotations/WIN_20211103_21_16_18_Pro.txt +++ /dev/null @@ -1,3 +0,0 @@ -3 1055.2865 148.5889 443.2753 73.4710 99.5100 -1 188.5453 22.3466 85.2053 49.0357 99.9200 -3 1048.2261 134.2752 271.3041 76.3464 99.9600 diff --git a/img/locations/WIN_20211101_17_19_37_Pro.txt b/img/locations/WIN_20211101_17_19_37_Pro.txt deleted file mode 100644 index fdd0b107edc822f4b6d0a84b83d0b5d910757b21..0000000000000000000000000000000000000000 --- a/img/locations/WIN_20211101_17_19_37_Pro.txt +++ /dev/null @@ -1 +0,0 @@ -350 700 -100 \ No newline at end of file diff --git a/img/readme.md b/img/readme.md deleted file mode 100644 index d6af6012b91c95a8c1a29b38ffad1f453ca7a0e9..0000000000000000000000000000000000000000 --- a/img/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -This folder is to store all the photos of the planting bed, -and is supposed to be cleaned each time after detection. \ No newline at end of file