16 from datetime
import datetime
19 from pathlib
import Path
23 from lattice_generator
import LatticeGenerator
25 import matplotlib.pyplot
as plt
29 logging.basicConfig(level=logging.INFO)
30 logger = logging.getLogger(__name__)
33 def handle_arg_parsing():
35 Handle the parsing of arguments.
40 An object containing all parsed arguments
43 parser = argparse.ArgumentParser(description=
'Generate motionprimitives '
46 parser.add_argument(
'--config',
48 default=
'./config.json',
49 help=
'The config file containing the '
50 'parameters to be used')
51 parser.add_argument(
'--output',
53 default=
'./output.json',
54 help=
'The output file containing the '
56 parser.add_argument(
'--visualizations',
58 default=
'./visualizations',
59 help=
'The output folder where the '
60 'visualizations of the trajectories will be saved')
62 return parser.parse_args()
65 def create_heading_angle_list(minimal_set_trajectories: dict) -> list:
67 Create a sorted list of heading angles from the minimal trajectory set.
71 minimal_set_trajectories: dict
72 The minimal spanning set
77 A sorted list of heading angles
80 heading_angles = set(minimal_set_trajectories.keys())
81 return sorted(heading_angles, key=
lambda x: (x < 0, x))
84 def read_config(config_path) -> dict:
86 Read in the user defined parameters via JSON.
91 Path to the config file
96 Dictionary containing the user defined parameters
99 with open(config_path)
as config_file:
100 config = json.load(config_file)
105 def create_header(config: dict, minimal_set_trajectories: dict) -> dict:
107 Create a dict containing all the fields to populate the header with.
112 The dict containing user specified parameters
113 minimal_set_trajectories: dict
114 The minimal spanning set
119 A dictionary containing the fields to populate the header with
123 'version': constants.VERSION,
124 'date_generated': datetime.today().strftime(
'%Y-%m-%d'),
125 'lattice_metadata': {},
129 for key, value
in config.items():
130 header_dict[
'lattice_metadata'][key] = value
132 heading_angles = create_heading_angle_list(minimal_set_trajectories)
133 adjusted_heading_angles = [angle + 2*np.pi
if angle < 0
else angle
for angle
in heading_angles]
135 header_dict[
'lattice_metadata'][
'heading_angles'] = adjusted_heading_angles
140 def write_to_json(output_path: Path, minimal_set_trajectories: dict, config: dict) ->
None:
142 Write the minimal spanning set to an output file.
147 The output file for the json data
148 minimal_set_trajectories: dict
149 The minimal spanning set
151 The dict containing user specified parameters
154 output_dict = create_header(config, minimal_set_trajectories)
156 trajectory_start_angles = list(minimal_set_trajectories.keys())
158 heading_angle_list = create_heading_angle_list(minimal_set_trajectories)
159 heading_lookup = {angle: idx
for idx, angle
in
160 enumerate(heading_angle_list)}
163 for start_angle
in sorted(trajectory_start_angles,
164 key=
lambda x: (x < 0, x)):
166 for trajectory
in sorted(
167 minimal_set_trajectories[start_angle],
168 key=
lambda x: x.parameters.end_angle
172 traj_info[
'trajectory_id'] = idx
173 traj_info[
'start_angle_index'] = heading_lookup[trajectory.parameters.start_angle]
174 traj_info[
'end_angle_index'] = heading_lookup[trajectory.parameters.end_angle]
175 traj_info[
'left_turn'] = bool(trajectory.parameters.left_turn)
176 traj_info[
'trajectory_radius'] = \
177 trajectory.parameters.turning_radius
178 traj_info[
'trajectory_length'] = round(
179 trajectory.parameters.total_length, 5
181 traj_info[
'arc_length'] = round(
182 trajectory.parameters.arc_length,
185 traj_info[
'straight_length'] = round(
186 trajectory.parameters.start_straight_length
187 + trajectory.parameters.end_straight_length,
190 traj_info[
'poses'] = trajectory.path.to_output_format()
192 output_dict[
'primitives'].append(traj_info)
195 output_dict[
'lattice_metadata'][
'number_of_trajectories'] = idx
197 with open(output_path,
'w')
as output_file:
198 json.dump(output_dict, output_file, indent=
'\t')
201 def save_visualizations(visualizations_folder: Path, minimal_set_trajectories: dict) ->
None:
203 Draw the visualizations for every trajectory and save it as an image.
207 visualizations_folder: Path
208 The path to the folder for where to save the images
209 minimal_set_trajectories: dict
210 The minimal spanning set
214 visualizations_folder.mkdir(exist_ok=
True)
216 for start_angle
in minimal_set_trajectories.keys():
218 for trajectory
in minimal_set_trajectories[start_angle]:
219 plt.plot(trajectory.path.xs, trajectory.path.ys,
'b')
223 left_x, right_x = plt.xlim()
224 left_y, right_y = plt.ylim()
226 output_path = visualizations_folder /
'all_trajectories.png'
227 plt.savefig(output_path)
230 for start_angle
in minimal_set_trajectories.keys():
232 angle_in_deg = np.rad2deg(start_angle)
234 if start_angle < 0
or start_angle > np.pi / 2:
237 for trajectory
in minimal_set_trajectories[start_angle]:
238 plt.plot(trajectory.path.xs, trajectory.path.ys,
'b')
239 plt.xlim(left_x, right_x)
240 plt.ylim(left_y, right_y)
244 output_path = visualizations_folder / f
'{angle_in_deg}.png'
245 plt.savefig(output_path)
249 if __name__ ==
'__main__':
251 args = handle_arg_parsing()
252 config = read_config(args.config)
255 lattice_gen = LatticeGenerator(config)
256 minimal_set_trajectories = lattice_gen.run()
257 print(f
'Finished Generating. Took {time.time() - start} seconds')
259 write_to_json(args.output, minimal_set_trajectories, config)
260 save_visualizations(args.visualizations, minimal_set_trajectories)