diff --git a/src/waypoint_navigation/README.md b/src/waypoint_navigation/README.md
index 693cfbc..551bba0 100644
--- a/src/waypoint_navigation/README.md
+++ b/src/waypoint_navigation/README.md
@@ -2,7 +2,3 @@
- Tkinter 8.6
- Pillow 9.2.0
- ruamel.yaml 0.17.21
-
-waypoint_manager 参考
-- https://imagingsolution.net/category/program/python/tkinter/
-- https://daeudaeu.com/tkinter-mousewheel/
diff --git a/src/waypoint_navigation/waypoint_manager/CMakeLists.txt b/src/waypoint_navigation/waypoint_manager/CMakeLists.txt
deleted file mode 100644
index 2941813..0000000
--- a/src/waypoint_navigation/waypoint_manager/CMakeLists.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-cmake_minimum_required(VERSION 3.0.2)
-project(waypoint_manager)
-
-## Compile as C++11, supported in ROS Kinetic and newer
-# add_compile_options(-std=c++11)
-
-## Find catkin macros and libraries
-## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
-## is used, also find other catkin packages
-find_package(catkin REQUIRED)
-
-## System dependencies are found with CMake's conventions
-# find_package(Boost REQUIRED COMPONENTS system)
-
-
-## Uncomment this if the package has a setup.py. This macro ensures
-## modules and global scripts declared therein get installed
-## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
-# catkin_python_setup()
-
-################################################
-## Declare ROS messages, services and actions ##
-################################################
-
-## To declare and build messages, services or actions from within this
-## package, follow these steps:
-## * Let MSG_DEP_SET be the set of packages whose message types you use in
-## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
-## * In the file package.xml:
-## * add a build_depend tag for "message_generation"
-## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
-## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
-## but can be declared for certainty nonetheless:
-## * add a exec_depend tag for "message_runtime"
-## * In this file (CMakeLists.txt):
-## * add "message_generation" and every package in MSG_DEP_SET to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * add "message_runtime" and every package in MSG_DEP_SET to
-## catkin_package(CATKIN_DEPENDS ...)
-## * uncomment the add_*_files sections below as needed
-## and list every .msg/.srv/.action file to be processed
-## * uncomment the generate_messages entry below
-## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
-
-## Generate messages in the 'msg' folder
-# add_message_files(
-# FILES
-# Message1.msg
-# Message2.msg
-# )
-
-## Generate services in the 'srv' folder
-# add_service_files(
-# FILES
-# Service1.srv
-# Service2.srv
-# )
-
-## Generate actions in the 'action' folder
-# add_action_files(
-# FILES
-# Action1.action
-# Action2.action
-# )
-
-## Generate added messages and services with any dependencies listed here
-# generate_messages(
-# DEPENDENCIES
-# std_msgs # Or other packages containing msgs
-# )
-
-################################################
-## Declare ROS dynamic reconfigure parameters ##
-################################################
-
-## To declare and build dynamic reconfigure parameters within this
-## package, follow these steps:
-## * In the file package.xml:
-## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
-## * In this file (CMakeLists.txt):
-## * add "dynamic_reconfigure" to
-## find_package(catkin REQUIRED COMPONENTS ...)
-## * uncomment the "generate_dynamic_reconfigure_options" section below
-## and list every .cfg file to be processed
-
-## Generate dynamic reconfigure parameters in the 'cfg' folder
-# generate_dynamic_reconfigure_options(
-# cfg/DynReconf1.cfg
-# cfg/DynReconf2.cfg
-# )
-
-###################################
-## catkin specific configuration ##
-###################################
-## The catkin_package macro generates cmake config files for your package
-## Declare things to be passed to dependent projects
-## INCLUDE_DIRS: uncomment this if your package contains header files
-## LIBRARIES: libraries you create in this project that dependent projects also need
-## CATKIN_DEPENDS: catkin_packages dependent projects also need
-## DEPENDS: system dependencies of this project that dependent projects also need
-catkin_package(
-# INCLUDE_DIRS include
-# LIBRARIES waypoint_manager
-# CATKIN_DEPENDS other_catkin_pkg
-# DEPENDS system_lib
-)
-
-###########
-## Build ##
-###########
-
-## Specify additional locations of header files
-## Your package locations should be listed before other locations
-include_directories(
-# include
-# ${catkin_INCLUDE_DIRS}
-)
-
-## Declare a C++ library
-# add_library(${PROJECT_NAME}
-# src/${PROJECT_NAME}/waypoint_manager.cpp
-# )
-
-## Add cmake target dependencies of the library
-## as an example, code may need to be generated before libraries
-## either from message generation or dynamic reconfigure
-# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
-
-## Declare a C++ executable
-## With catkin_make all packages are built within a single CMake context
-## The recommended prefix ensures that target names across packages don't collide
-# add_executable(${PROJECT_NAME}_node src/waypoint_manager_node.cpp)
-
-## Rename C++ executable without prefix
-## The above recommended prefix causes long target names, the following renames the
-## target back to the shorter version for ease of user use
-## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
-# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
-
-## Add cmake target dependencies of the executable
-## same as for the library above
-# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
-
-## Specify libraries to link a library or executable target against
-# target_link_libraries(${PROJECT_NAME}_node
-# ${catkin_LIBRARIES}
-# )
-
-#############
-## Install ##
-#############
-
-# all install targets should use catkin DESTINATION variables
-# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
-
-## Mark executable scripts (Python etc.) for installation
-## in contrast to setup.py, you can choose the destination
-# catkin_install_python(PROGRAMS
-# scripts/my_python_script
-# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
-# )
-
-## Mark executables for installation
-## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
-# install(TARGETS ${PROJECT_NAME}_node
-# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
-# )
-
-## Mark libraries for installation
-## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
-# install(TARGETS ${PROJECT_NAME}
-# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
-# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
-# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
-# )
-
-## Mark cpp header files for installation
-# install(DIRECTORY include/${PROJECT_NAME}/
-# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
-# FILES_MATCHING PATTERN "*.h"
-# PATTERN ".svn" EXCLUDE
-# )
-
-## Mark other files for installation (e.g. launch and bag files, etc.)
-# install(FILES
-# # myfile1
-# # myfile2
-# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
-# )
-
-#############
-## Testing ##
-#############
-
-## Add gtest based cpp test target and link libraries
-# catkin_add_gtest(${PROJECT_NAME}-test test/test_waypoint_manager.cpp)
-# if(TARGET ${PROJECT_NAME}-test)
-# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
-# endif()
-
-## Add folders to be run by python nosetests
-# catkin_add_nosetests(test)
diff --git a/src/waypoint_navigation/waypoint_manager/launch/start_manager.launch b/src/waypoint_navigation/waypoint_manager/launch/start_manager.launch
deleted file mode 100644
index e69de29..0000000
--- a/src/waypoint_navigation/waypoint_manager/launch/start_manager.launch
+++ /dev/null
diff --git a/src/waypoint_navigation/waypoint_manager/package.xml b/src/waypoint_navigation/waypoint_manager/package.xml
deleted file mode 100644
index e77ca19..0000000
--- a/src/waypoint_navigation/waypoint_manager/package.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
- waypoint_manager
- 0.0.0
- The waypoint_manager package
-
-
-
-
- ubuntu
-
-
-
-
-
- TODO
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- catkin
-
-
-
-
-
-
-
-
diff --git a/src/waypoint_navigation/waypoint_manager/scripts/icons/delete_param_btn.png b/src/waypoint_navigation/waypoint_manager/scripts/icons/delete_param_btn.png
new file mode 100644
index 0000000..86f4660
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/scripts/icons/delete_param_btn.png
Binary files differ
diff --git a/src/waypoint_navigation/waypoint_manager/scripts/icons/new_param_btn.png b/src/waypoint_navigation/waypoint_manager/scripts/icons/new_param_btn.png
new file mode 100644
index 0000000..fdf4e36
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/scripts/icons/new_param_btn.png
Binary files differ
diff --git a/src/waypoint_navigation/waypoint_manager/scripts/manager_GUI.py b/src/waypoint_navigation/waypoint_manager/scripts/manager_GUI.py
index cd38a8a..24696f8 100755
--- a/src/waypoint_navigation/waypoint_manager/scripts/manager_GUI.py
+++ b/src/waypoint_navigation/waypoint_manager/scripts/manager_GUI.py
@@ -3,8 +3,10 @@
import math
import ruamel.yaml
import gc
+import itertools
from pathlib import Path
from tkinter import messagebox
+from PIL import Image, ImageTk
from lib.mymaplib import MyMap
from lib.waypointlib import WaypointList, FinishPose, get_waypoint_yaml
@@ -94,19 +96,27 @@
self.master.bind("", self.ctrl_right_click)
self.master.bind("", self.window_resize_callback)
- #### その他必要になる変数 ####
- self.mymap = None
- self.waypoints = None
- self.finish_pose = None
- self.waypoints_filepath = None
+ #### アイコン ####
+ icon = Image.open(Path(__file__).parent / Path("icons","new_param_btn.png"))
+ icon = icon.resize((30, 30))
+ self.new_param_icon = ImageTk.PhotoImage(image=icon)
+ icon = Image.open(Path(__file__).parent / Path("icons","delete_param_btn.png"))
+ icon = icon.resize((30, 30))
+ self.del_param_icon = ImageTk.PhotoImage(image=icon)
+
+ #### その他必要になる変数,オブジェクト ####
+ self.mymap: MyMap = None
+ self.waypoints: WaypointList = None
+ self.finish_pose: FinishPose = None
+ self.waypoints_filepath: Path = None
self.editing_waypoint_id = None # 編集中のウェイポイントを示す図形のオブジェクトID
- self.moving_waypoint = False # ウェイポイントをDnDで動かしている最中かどうか
+ self.moving_waypoint = False # ウェイポイントをmoveで動かしている最中かどうか
self.setting_finish_pose = 0 # finish pose のセット中かどうか
self.old_click_point = None # 最後にカーソルのあった座標を保持
self.wp_info_win: tk.Toplevel = None # ウェイポイント情報を表示するウィンドウ
self.point_rad = 10 # 画像上に示すポイントの半径ピクセル
self.footprint = [[0.25, 0.4], [0.25, -0.4], [-0.65, -0.4], [-0.65, 0.4]]
- self.footprint_id = []
+ self.trajectory = []
return
@@ -142,6 +152,7 @@
return
self.message("Read map file " + map_path)
self.canvas.delete("all")
+ self.trajectory = []
if self.waypoints is not None: self.waypoints.number_dict = {}
## キャンバスサイズに合わせて画像を表示
scale = 1
@@ -170,6 +181,7 @@
self.menu_open_waypoints()
else:
self.plot_waypoints()
+ self.draw_trajectory()
gc.collect()
return
@@ -185,12 +197,6 @@
elif (self.waypoints is not None):
self.master.title(str(self.master.title()).replace(self.waypoints_filepath.name + " - ", ""))
- self.canvas.delete("all")
- self.draw_image()
- self.plot_origin()
- if (self.wp_info_win is not None) and (self.wp_info_win.winfo_exists()):
- self.wp_info_win.destroy()
-
filepath = tkinter.filedialog.askopenfilename(
parent=self.master,
title="Select waypoints yaml file",
@@ -203,11 +209,20 @@
if (not "waypoints" in wp_yaml.keys()) or (not "finish_pose" in wp_yaml.keys()):
messagebox.showerror(title="Format error", message="Selected waypoints file is unexpected format.")
return
+
+ self.canvas.delete("all")
+ self.trajectory = []
+ self.draw_image()
+ self.plot_origin()
+ if (self.wp_info_win is not None) and (self.wp_info_win.winfo_exists()):
+ self.wp_info_win.destroy()
+
del self.waypoints
self.waypoints = WaypointList(wp_yaml)
self.finish_pose = FinishPose(wp_yaml)
self.waypoints_filepath = Path(filepath)
self.plot_waypoints()
+ self.draw_trajectory()
self.master.title(self.waypoints_filepath.name + " - " + self.master.title())
self.message("Read waypoints file " + filepath)
self.file_menu.entryconfigure("Save", state=tk.NORMAL)
@@ -339,6 +354,7 @@
sub_win.destroy()
self.update_title()
self.plot_waypoints()
+ self.draw_trajectory()
return
frame3 = tk.Frame(sub_win)
set_btn = tk.Button(frame3, text="Set", width=5, command=set_btn_callback)
@@ -403,10 +419,8 @@
Y = xy[0]*math.sin(th) + xy[1]*math.cos(th) + y
cx, cy = self.real2canvas(float(X), float(Y))
polygon.append([cx, cy])
- id = self.canvas.create_polygon(polygon, fill="", outline="green")
- self.canvas.lower(id)
- self.canvas.lift(id, "map_image")
- self.footprint_id.append(id)
+ id = self.canvas.create_polygon(polygon, fill="", outline="green", tags="footprint")
+ self.canvas.lift("footprint", "map_image")
return
##
if (self.show_fp.get()):
@@ -417,9 +431,7 @@
# last waypoint
create_footprint(float(next_wp["x"]), float(next_wp["y"]), self.finish_pose.x, self.finish_pose.y)
else:
- for id in self.footprint_id:
- self.canvas.delete(id)
- self.footprint_id = []
+ self.canvas.delete("footprint")
return
@@ -433,16 +445,18 @@
+++++ 地図上の原点に円を描画 +++++
"""
def plot_origin(self):
- x, y = self.mymap.transform(self.mymap.img_origin[0], self.mymap.img_origin[1])
+ cx, cy = self.mymap.transform(self.mymap.img_origin[0], self.mymap.img_origin[1])
r = self.point_rad # 円の半径(ピクセル)
- x0 = x - r
- y0 = y - r
- x1 = x + r + 1
- y1 = y + r + 1
+ x0 = cx - r
+ y0 = cy - r
+ x1 = cx + r + 1
+ y1 = cy + r + 1
if self.canvas.find_withtag("origin"):
self.canvas.moveto("origin", x0, y0)
+ self.trajectory[0] = [cx, cy]
else:
self.canvas.create_oval(x0, y0, x1, y1, tags="origin", fill='cyan', outline='blue')
+ self.trajectory.append([cx, cy])
return
@@ -457,7 +471,8 @@
cx, cy = self.real2canvas(float(wp["x"]), float(wp["y"]))
x0 = cx - self.point_rad
y0 = cy - self.point_rad
- self.canvas.moveto(id, round(x0), round(y0))
+ self.canvas.moveto(id, x0, y0)
+ self.trajectory[self.waypoints.get_num(id)] = [cx, cy]
return
if len(self.waypoints.get_id_list()) == 0:
@@ -472,7 +487,8 @@
cx, cy = self.real2canvas(float(wp["x"]), float(wp["y"]))
x0 = cx - self.point_rad
y0 = cy - self.point_rad
- self.canvas.moveto(id, round(x0), round(y0))
+ self.canvas.moveto(id, x0, y0)
+ self.trajectory[self.waypoints.get_num(id)] = [cx, cy] # trajectory
# Finish poseを描画
cx, cy = self.real2canvas(self.finish_pose.x, self.finish_pose.y)
x0 = cx
@@ -483,31 +499,50 @@
# movetoだと上手くいかないので、毎回削除、再描画
self.canvas.delete(self.finish_pose.id)
self.finish_pose.id = self.canvas.create_line(x0, y0, x1, y1, tags="finish_pose",
- width=10, arrow=tk.LAST, arrowshape=(12,15,9), fill="#AAF"
+ width=10, arrow=tk.LAST, arrowshape=(12,15,9), fill="#AAF"
)
+ # trajectory
+ if self.canvas.find_withtag("trajectory"):
+ self.trajectory[-1] = [cx, cy]
+ else:
+ self.trajectory.append([cx, cy])
return
"""
+ +++++ ウェイポイントをつないだ軌道を描画する +++++
+ """
+ def draw_trajectory(self):
+ if self.canvas.find_withtag("trajectory"):
+ self.canvas.coords("trajectory", list(itertools.chain.from_iterable(self.trajectory)))
+ else:
+ self.canvas.create_line(list(itertools.chain.from_iterable(self.trajectory)),
+ fill="#DF2", width=2, tags="trajectory")
+ self.canvas.lift("trajectory", "map_image")
+ return
+
+
+ """
+++++ キャンバスに新たなウェイポイントを描画する +++++
"""
def create_waypoint(self, waypoint: dict):
img_x, img_y = self.mymap.real2image(float(waypoint["x"]), float(waypoint["y"]))
- cx, cy = self.mymap.transform(img_x, img_y)
- x0 = round(cx - self.point_rad)
- y0 = round(cy - self.point_rad)
- x1 = round(cx + self.point_rad + 1)
- y1 = round(cy + self.point_rad + 1)
+ cx, cy = self.real2canvas(float(waypoint["x"]), float(waypoint["y"]))
+ x0 = (cx - self.point_rad)
+ y0 = (cy - self.point_rad)
+ x1 = (cx + self.point_rad + 1)
+ y1 = (cy + self.point_rad + 1)
if (img_x < 0) or (img_y < 0) or (img_x > self.mymap.width()) or (img_y > self.mymap.height()):
- id = self.canvas.create_oval(x0, y0, x1, y1, fill='#FEE', outline='#FAA', activefill='#F88')
+ id = self.canvas.create_oval(x0, y0, x1, y1, fill='#FEE', outline='#FAA', activefill='#F88', tags="waypoints")
self.canvas.tag_bind(id, "", lambda event, wp_id=id: self.waypoint_enter(event, wp_id))
self.canvas.tag_bind(id, "", self.waypoint_leave)
else:
- id = self.canvas.create_oval(x0, y0, x1, y1, fill='#FDD', outline='red', activefill='red')
+ id = self.canvas.create_oval(x0, y0, x1, y1, fill='#FDD', outline='red', activefill='red', tags="waypoints")
self.canvas.tag_bind(id, "", lambda event, wp_id=id: self.waypoint_clicked(event, wp_id))
self.canvas.tag_bind(id, "", lambda event, wp_id=id: self.waypoint_enter(event, wp_id))
self.canvas.tag_bind(id, "", self.waypoint_leave)
self.canvas.tag_bind(id, "", self.waypoint_click_move)
+ self.trajectory.append([cx, cy]) #trajectory
return id
@@ -537,9 +572,9 @@
delta_y = event.y-self.old_click_point[1]
self.canvas.move(self.editing_waypoint_id, delta_x, delta_y)
box = self.canvas.bbox(self.editing_waypoint_id)
- px = (box[2] + box[0]) / 2 # ウィンドウ上の座標
- py = (box[3] + box[1]) / 2
- img_x, img_y = self.mymap.inv_transform(px, py)
+ cx = (box[2] + box[0]) / 2 # ウィンドウ上の座標
+ cy = (box[3] + box[1]) / 2
+ img_x, img_y = self.mymap.inv_transform(cx, cy)
# マップ画像上の座標を、実際の座標に変換
x, y = self.mymap.image2real(img_x, img_y)
# 編集中のウェイポイント情報を更新
@@ -554,6 +589,9 @@
txt_box.insert(tk.END, y)
self.old_click_point = [event.x, event.y]
self.update_title()
+ # trajectory
+ self.trajectory[self.waypoints.get_num(self.editing_waypoint_id)] = [cx, cy]
+ self.draw_trajectory()
return
@@ -594,22 +632,24 @@
txt_box = tk.Entry(self.wp_info_win, width=20, font=("Consolas", 15))
txt_box.insert(tk.END, str(point[key]).lower())
txt_box.grid(column=1, row=i, padx=2, pady=2, ipady=3, sticky=tk.EW)
- del_btn = tk.Button(self.wp_info_win, text="-", width=2, bg="red", fg="white", font=("",13,"bold"))
+ del_btn = tk.Button(self.wp_info_win, image=self.del_param_icon, relief=tk.FLAT)
del_btn["command"] = lambda name=key, val=str(point[key]).lower(): self.del_param_btn_callback(name, val)
del_btn.grid(column=2, row=i, padx=5, pady=5)
+ self.wp_info_win.grid_columnconfigure(1, weight=1)
# New parameter
- new_param_btn = tk.Button(self.wp_info_win, text="New Parameter", bg="#AFA")
+ new_param_btn = tk.Button(self.wp_info_win, image=self.new_param_icon, relief=tk.FLAT)
new_param_btn["command"] = self.new_param_btn_callback
- new_param_btn.grid(column=0, columnspan=2, row=self.wp_info_win.grid_size()[1], pady=10)
- # Apply, DnD(Drag & Drop), remove ボタン
+ new_param_btn.grid(column=0, columnspan=3, row=self.wp_info_win.grid_size()[1], pady=10)
+ # Apply, Move(Drag & Drop), remove ボタン
canv = tk.Canvas(self.wp_info_win)
canv.grid(column=0, columnspan=3, row=self.wp_info_win.grid_size()[1], sticky=tk.EW, pady=5)
apply_btn = tk.Button(canv, text="Apply", width=5, height=1, bg="#FDD",
command=self.apply_btn_callback)
apply_btn.pack(side=tk.RIGHT, anchor=tk.SE, padx=5, pady=5)
- dnd_btn = tk.Button(canv, text="DnD", width=5, height=1, bg="#EEE")
- dnd_btn["command"] = lambda obj=dnd_btn: self.dnd_btn_callback(dnd_btn)
- dnd_btn.pack(side=tk.RIGHT, anchor=tk.SE, padx=5, pady=5)
+ self.wp_info_win.bind('', self.apply_btn_callback)
+ move_btn = tk.Button(canv, text="Move", width=5, height=1, bg="#EEE")
+ move_btn["command"] = lambda obj=move_btn: self.move_btn_callback(move_btn)
+ move_btn.pack(side=tk.RIGHT, anchor=tk.SE, padx=5, pady=5)
remove_btn = tk.Button(canv, text="Remove", width=7, height=1, bg="#F00",
command=self.remove_btn_callback)
remove_btn.pack(side=tk.LEFT, anchor=tk.SE, padx=5, pady=5)
@@ -617,8 +657,8 @@
self.wp_info_win.update()
w = self.wp_info_win.winfo_width()
h = self.wp_info_win.winfo_height()
- x = self.canvas.winfo_x() + self.canv_w - w
- y = self.canvas.winfo_y() + self.canv_h - h
+ x = self.canvas.winfo_x() + self.canv_w - w -10
+ y = self.canvas.winfo_y() + self.canv_h - h -10
self.wp_info_win.lift()
self.wp_info_win.attributes('-topmost', True) # サブウィンドウを最前面で固定
self.wp_info_win.geometry("+{}+{}".format(x, y))
@@ -629,21 +669,26 @@
"""
+++++ Applyボタンを押したときのコールバック +++++
"""
- def apply_btn_callback(self):
+ def apply_btn_callback(self, event=None):
+ if (event is not None) and (event.keysym != "Return"): return
point = self.waypoints.get_waypoint(id=self.editing_waypoint_id)
for i, key in enumerate(point.keys()):
txt_box = self.wp_info_win.grid_slaves(column=1, row=i)[0]
- self.waypoints.set_waypoint_val(self.editing_waypoint_id, key, txt_box.get())
- self.plot_waypoints(id=self.editing_waypoint_id)
- self.message("Apply changes of waypoint parameters")
- self.update_title()
+ val = txt_box.get()
+ if (str(point[key]) == val): continue
+ self.update_title()
+ self.message("Apply changes of waypoint parameters")
+ self.waypoints.set_waypoint_val(self.editing_waypoint_id, key, val)
+ if ((key == "x") or (key == "y")):
+ self.plot_waypoints(self.editing_waypoint_id)
+ self.draw_trajectory()
return
"""
- +++++ ドラッグ&ドロップボタン(DnD)を押したときのコールバック +++++
+ +++++ ドラッグ&ドロップボタン(Moveボタン)を押したときのコールバック +++++
"""
- def dnd_btn_callback(self, obj=None):
+ def move_btn_callback(self, obj=None):
if obj is None: return
btn = obj
# 押された状態とそうでない状態を切り替える
@@ -664,11 +709,15 @@
+++++ removeボタンを押したときのコールバック +++++
"""
def remove_btn_callback(self):
- self.waypoints.remove(self.editing_waypoint_id)
- self.canvas.delete(self.editing_waypoint_id) # ウェイポイントを示す円を削除
- self.close_wp_info()
- self.message("Removed waypoint")
- self.update_title()
+ yn = messagebox.askyesno("Delete parameter", message="Are you sure you want to remove this waypoint?")
+ if (yn == True):
+ self.trajectory.pop(self.waypoints.get_num(self.editing_waypoint_id))
+ self.waypoints.remove(self.editing_waypoint_id)
+ self.canvas.delete(self.editing_waypoint_id) # ウェイポイントを示す円を削除
+ self.close_wp_info()
+ self.message("Removed waypoint")
+ self.update_title()
+ self.draw_trajectory()
return
@@ -794,7 +843,7 @@
win.attributes('-topmost', True)
return
num = int(num)
- if (num < 0) or (num > len(self.waypoints.waypoints)+1):
+ if (num < 1) or (num > len(self.waypoints.waypoints)+1):
win.attributes('-topmost', False)
messagebox.showwarning(title="Warning", message="The number is out of range.")
win.attributes('-topmost', True)
@@ -811,8 +860,11 @@
elif (key=="z"): point[key] = 0.0
else: point[key] = ""
id = self.create_waypoint(point)
+ cx,cy = self.trajectory.pop(-1)
+ self.trajectory[num:num] = [[cx, cy]]
self.waypoints.insert(num, point, id=id)
self.plot_waypoints(id=id)
+ self.draw_trajectory()
self.editing_waypoint_id = id
self.canvas.itemconfig(id, fill='red')
self.disp_waypoint_info(id)
@@ -853,24 +905,6 @@
"""
- +++++ マウスホイールを回転したとき(タッチパッドをドラッグしたとき) +++++
- """
- def mouse_wheel(self, event):
- if not self.mymap: return
- if event.delta > 0:
- scale = 1.1 # 上に回転(タッチパッドなら下にドラッグ)=> 拡大
- else:
- scale = 0.9 # 下に回転(タッチパッドなら上にドラッグ)=> 縮小
- self.mymap.scale_at(event.x, event.y, scale)
- self.draw_image()
- self.plot_origin()
- self.plot_waypoints()
- for id in self.footprint_id:
- self.canvas.scale(id, event.x, event.y, scale, scale)
- return
-
-
- """
+++++ 左クリックされたとき +++++
"""
def left_click(self, event):
@@ -902,6 +936,8 @@
self.finish_pose.id = self.canvas.create_line(x0, y0, x1, y1, tags="finish_pose",
width=10, arrow=tk.LAST, arrowshape=(12,15,9), fill="#AAF"
)
+ self.trajectory[-1] = [x0, y0]
+ self.draw_trajectory()
img_x, img_y = self.mymap.inv_transform(x0, y0)
real_x, real_y = self.mymap.image2real(img_x, img_y)
self.finish_pose.x = real_x
@@ -932,9 +968,14 @@
# origin, waypoints finish_pose を平行移動
self.canvas.move("origin", delta_x, delta_y)
if self.waypoints:
- for id in list(self.waypoints.get_id_list()) + self.footprint_id:
- self.canvas.move(id, delta_x, delta_y)
+ self.canvas.move("waypoints", delta_x, delta_y)
self.canvas.move("finish_pose", delta_x, delta_y)
+ self.canvas.move("trajectory", delta_x, delta_y)
+ self.canvas.lift("trajectory", "map_image")
+ self.canvas.move("footprint", delta_x, delta_y)
+ for i in range(0, len(self.trajectory)):
+ self.trajectory[i][0] = self.trajectory[i][0] + delta_x
+ self.trajectory[i][1] = self.trajectory[i][1] + delta_y
self.old_click_point = [event.x, event.y]
return
@@ -986,8 +1027,8 @@
self.draw_image()
self.plot_origin()
self.plot_waypoints()
- for id in self.footprint_id:
- self.canvas.scale(id, event.x, event.y, scale, scale)
+ self.canvas.scale("footprint", event.x, event.y, scale, scale)
+ self.canvas.scale("trajectory", event.x, event.y, scale, scale)
self.message("Zoom In")
return
@@ -1003,13 +1044,31 @@
self.draw_image()
self.plot_origin()
self.plot_waypoints()
- for id in self.footprint_id:
- self.canvas.scale(id, event.x, event.y, scale, scale)
+ self.canvas.scale("footprint", event.x, event.y, scale, scale)
+ self.canvas.scale("trajectory", event.x, event.y, scale, scale)
self.message("Zoom Out")
return
"""
+ +++++ マウスホイールを回転したとき(タッチパッドをドラッグしたとき) +++++
+ """
+ def mouse_wheel(self, event):
+ if not self.mymap: return
+ if event.delta > 0:
+ scale = 1.1 # 上に回転(タッチパッドなら下にドラッグ)=> 拡大
+ else:
+ scale = 0.9 # 下に回転(タッチパッドなら上にドラッグ)=> 縮小
+ self.mymap.scale_at(event.x, event.y, scale)
+ self.draw_image()
+ self.plot_origin()
+ self.plot_waypoints()
+ self.canvas.scale("footprint", event.x, event.y, scale, scale)
+ self.canvas.scale("trajectory", event.x, event.y, scale, scale)
+ return
+
+
+ """
+++++ ウィンドウサイズが変更されたとき、情報を更新する +++++
"""
def window_resize_callback(self, event):
@@ -1060,14 +1119,14 @@
def real2canvas(self, x, y):
img_x, img_y = self.mymap.real2image(x,y)
cx, cy = self.mymap.transform(img_x, img_y)
- return cx, cy
+ return round(cx), round(cy)
def update_title(self):
title = self.master.title()
if title[0] != "*":
self.master.title("* "+title)
-
+
diff --git a/src/waypoint_navigation/waypoint_manager/scripts/to_exe.bat b/src/waypoint_navigation/waypoint_manager/scripts/to_exe.bat
new file mode 100644
index 0000000..30a7c4c
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/scripts/to_exe.bat
@@ -0,0 +1,14 @@
+pyinstaller.exe manager_GUI.py --noconsole --noconfirm
+
+if exist .\waypoint_manager PowerShell -command " rm -r .\waypoint_manager "
+PowerShell -command " mv .\dist\manager_GUI .\waypoint_manager "
+PowerShell -command " rm -r .\build "
+PowerShell -command " rm -r .\dist "
+PowerShell -command " rm .\manager_GUI.spec "
+PowerShell -command " cp -r .\icons .\waypoint_manager\ "
+
+
+
+
+
+
diff --git a/src/waypoint_navigation/waypoint_manager/scripts/to_exe.sh b/src/waypoint_navigation/waypoint_manager/scripts/to_exe.sh
new file mode 100755
index 0000000..00dddf8
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/scripts/to_exe.sh
@@ -0,0 +1,13 @@
+python -m PyInstaller manager_GUI.py --noconsole --noconfirm
+
+if [ -d ./waypoint_manager ]; then
+ rm -r ./waypoint_manager
+fi
+
+mv ./dist/manager_GUI ./waypoint_manager
+rm -r ./build
+rm -r ./dist
+rm ./manager_GUI.spec
+cp -r ./icons ./waypoint_manager/
+
+# If the ModuleNotFoundError occur, copy the module from your environment
diff --git a/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-ubuntu.tar b/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-ubuntu.tar
new file mode 100644
index 0000000..d247cb0
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-ubuntu.tar
Binary files differ
diff --git a/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-windows10.zip b/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-windows10.zip
new file mode 100644
index 0000000..48cd956
--- /dev/null
+++ b/src/waypoint_navigation/waypoint_manager/waypoint-manager-for-windows10.zip
Binary files differ