From 9f8f7b60d4bdca62c6451b0b4d478e7cca3f569e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Tue, 12 Nov 2024 13:39:56 +0100 Subject: [PATCH 1/8] Return an optional dict from every 'init()' function --- CHANGELOG.md | 3 +++ ng_trajectory/criterions/curvature/main.py | 8 ++++++- ng_trajectory/criterions/jazar_model/main.py | 8 ++++++- ng_trajectory/criterions/length/main.py | 8 ++++++- ng_trajectory/criterions/manual/main.py | 8 ++++++- ng_trajectory/criterions/profile/main.py | 8 ++++++- ng_trajectory/criterions/profile2/main.py | 9 +++++-- .../interpolators/cubic_spline/main.py | 8 ++++++- ng_trajectory/interpolators/none/main.py | 8 ++++++- ng_trajectory/main.py | 24 +++++++++++++++---- ng_trajectory/optimizers/braghin/main.py | 12 ++++++++-- ng_trajectory/optimizers/matryoshka/main.py | 12 ++++++++-- ng_trajectory/penalizers/borderlines/main.py | 9 +++++-- ng_trajectory/penalizers/centerline/main.py | 9 +++++-- ng_trajectory/penalizers/count/main.py | 8 ++++++- ng_trajectory/penalizers/curvature/main.py | 8 ++++++- ng_trajectory/penalizers/none/main.py | 8 ++++++- ng_trajectory/penalizers/segment/main.py | 9 +++++-- ng_trajectory/segmentators/euclidean/main.py | 9 +++++-- ng_trajectory/segmentators/flood_fill/main.py | 9 +++++-- ng_trajectory/selectors/curvature/main.py | 8 +++++-- ng_trajectory/selectors/curvature2/main.py | 9 +++++-- .../selectors/curvature_sample/main.py | 8 ++++++- ng_trajectory/selectors/fixed/main.py | 9 +++++-- ng_trajectory/selectors/uniform/main.py | 8 ++++++- .../selectors/uniform_distance/main.py | 8 ++++++- ng_trajectory/selectors/uniform_time/main.py | 9 +++++-- 27 files changed, 202 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c9f3e..5e3540a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Unreleased +### Changed + - Initialization (`init()`) of all algorithms may now return an optional dictionary. When returned, it is fused together with the configuration of the current cascade step (except penalizers as they are handled by the optimizers). + ## 1.15.2 - 2024-11-12 ### Added - 'ng_generate_data' diff --git a/ng_trajectory/criterions/curvature/main.py b/ng_trajectory/criterions/curvature/main.py index 1e4d932..ded74eb 100644 --- a/ng_trajectory/criterions/curvature/main.py +++ b/ng_trajectory/criterions/curvature/main.py @@ -10,12 +10,18 @@ import numpy +from typing import ( + Any, + Dict, + Optional, +) + ###################### # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" pass diff --git a/ng_trajectory/criterions/jazar_model/main.py b/ng_trajectory/criterions/jazar_model/main.py index d3e450d..577fa48 100644 --- a/ng_trajectory/criterions/jazar_model/main.py +++ b/ng_trajectory/criterions/jazar_model/main.py @@ -12,6 +12,12 @@ import numpy import math +from typing import ( + Any, + Dict, + Optional, +) + # Parameters from ng_trajectory.parameter import ParameterList @@ -383,7 +389,7 @@ def computeProfile(points): # General functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" P.updateAll(kwargs, reset = False) diff --git a/ng_trajectory/criterions/length/main.py b/ng_trajectory/criterions/length/main.py index b43b7fe..fe997a7 100644 --- a/ng_trajectory/criterions/length/main.py +++ b/ng_trajectory/criterions/length/main.py @@ -11,12 +11,18 @@ import numpy +from typing import ( + Any, + Dict, + Optional, +) + ###################### # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" pass diff --git a/ng_trajectory/criterions/manual/main.py b/ng_trajectory/criterions/manual/main.py index c955d12..c17a8f4 100644 --- a/ng_trajectory/criterions/manual/main.py +++ b/ng_trajectory/criterions/manual/main.py @@ -11,6 +11,12 @@ from threading import Lock +from typing import ( + Any, + Dict, + Optional, +) + # Global variables INPUT_LOCK = Lock() @@ -20,7 +26,7 @@ # Functions ###################### -def init(**kwargs): +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" return None diff --git a/ng_trajectory/criterions/profile/main.py b/ng_trajectory/criterions/profile/main.py index b29381e..c09498b 100644 --- a/ng_trajectory/criterions/profile/main.py +++ b/ng_trajectory/criterions/profile/main.py @@ -43,6 +43,12 @@ from itertools import chain # Join generators +from typing import ( + Any, + Dict, + Optional, +) + # Global variables CENTERLINE = None @@ -329,7 +335,7 @@ def perr(*args, **kwargs): # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" global REFERENCE, CENTERLINE, OVERTAKING_POINTS diff --git a/ng_trajectory/criterions/profile2/main.py b/ng_trajectory/criterions/profile2/main.py index 7ec50b3..3a5d694 100644 --- a/ng_trajectory/criterions/profile2/main.py +++ b/ng_trajectory/criterions/profile2/main.py @@ -53,7 +53,12 @@ from skimage.segmentation import flood_fill import copy -from typing import Tuple +from typing import ( + Any, + Dict, + Tuple, + Optional, +) # Global variables @@ -465,7 +470,7 @@ def get_rect_points( return corners.T # n x 2 -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" global REFERENCE, CENTERLINE, OVERTAKING_POINTS, MAP_OUTSIDE, MAP_INSIDE diff --git a/ng_trajectory/interpolators/cubic_spline/main.py b/ng_trajectory/interpolators/cubic_spline/main.py index 808380c..d8bba63 100644 --- a/ng_trajectory/interpolators/cubic_spline/main.py +++ b/ng_trajectory/interpolators/cubic_spline/main.py @@ -15,6 +15,12 @@ from ng_trajectory.parameter import ParameterList +from typing import ( + Any, + Dict, + Optional, +) + # Parameters P = ParameterList() @@ -26,7 +32,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize interpolator.""" P.updateAll(kwargs) diff --git a/ng_trajectory/interpolators/none/main.py b/ng_trajectory/interpolators/none/main.py index 2fef495..9347f95 100644 --- a/ng_trajectory/interpolators/none/main.py +++ b/ng_trajectory/interpolators/none/main.py @@ -12,6 +12,12 @@ from ng_trajectory.parameter import ParameterList +from typing import ( + Any, + Dict, + Optional, +) + # Parameters P = ParameterList() @@ -25,7 +31,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize interpolator.""" P.updateAll(kwargs) diff --git a/ng_trajectory/main.py b/ng_trajectory/main.py index 61ad4a7..7f6a712 100644 --- a/ng_trajectory/main.py +++ b/ng_trajectory/main.py @@ -450,38 +450,49 @@ def cascadeRun( ) # Initialize parts - sel.init( + _sel_dict = sel.init( **{ **_alg, **_alg.get("selector_init", {}) } ) - itp.init( + if _sel_dict is not None: + _alg = {**_alg, **_sel_dict} + + _itp_dict = itp.init( **{ **_alg, **_alg.get("interpolator_init", {}) } ) - seg.init( + if _itp_dict is not None: + _alg = {**_alg, **_itp_dict} + + _seg_dict = seg.init( track, **{ **_alg, **_alg.get("segmentator_init", {}) } ) - cri.init( + if _seg_dict is not None: + _alg = {**_alg, **_seg_dict} + + _cri_dict = cri.init( **{ **_alg, **_alg.get("criterion_init", {}) } ) + if _cri_dict is not None: + _alg = {**_alg, **_cri_dict} # Note: This passes the initial line (which is usually centerline). # TODO: Actually pass centerline. if not hasattr(cri.main, "CENTERLINE") or cri.main.CENTERLINE is None: cri.main.CENTERLINE = result.copy() - opt.init( + _opt_dict = opt.init( track, rcandidate, result, @@ -494,6 +505,9 @@ def cascadeRun( **{"penalizer": pen} } ) + if _opt_dict is not None: + _alg = {**_alg, **_opt_dict} + logfileFlush() # # Optimization # # diff --git a/ng_trajectory/optimizers/braghin/main.py b/ng_trajectory/optimizers/braghin/main.py index becd9af..431b81f 100644 --- a/ng_trajectory/optimizers/braghin/main.py +++ b/ng_trajectory/optimizers/braghin/main.py @@ -33,7 +33,15 @@ from threading import Lock # Typing -from typing import Tuple, Dict, TextIO, List, types +from typing import ( + Any, + Dict, + List, + Optional, + TextIO, + Tuple, + types, +) # Global variables @@ -122,7 +130,7 @@ def init( line_reduction: float = 3, grid: List[float] = [], figure: ngplot.matplotlib.figure.Figure = None, - **kwargs): + **kwargs) -> Optional[Dict[str, Any]]: """Initialize variables for Braghin's transformation. Arguments: diff --git a/ng_trajectory/optimizers/matryoshka/main.py b/ng_trajectory/optimizers/matryoshka/main.py index c8b18e0..c4eb371 100644 --- a/ng_trajectory/optimizers/matryoshka/main.py +++ b/ng_trajectory/optimizers/matryoshka/main.py @@ -37,7 +37,15 @@ from threading import Lock # Typing -from typing import Tuple, Dict, TextIO, List, types +from typing import ( + Any, + Dict, + List, + Optional, + TextIO, + Tuple, + types, +) # Global variables @@ -173,7 +181,7 @@ def init( plot: bool = False, grid: List[float] = [], figure: ngplot.matplotlib.figure.Figure = None, - **kwargs): + **kwargs) -> Optional[Dict[str, Any]]: """Initialize variables for Matryoshka transformation. Arguments: diff --git a/ng_trajectory/penalizers/borderlines/main.py b/ng_trajectory/penalizers/borderlines/main.py index 2e5ae8c..5af6c6b 100644 --- a/ng_trajectory/penalizers/borderlines/main.py +++ b/ng_trajectory/penalizers/borderlines/main.py @@ -17,7 +17,12 @@ pointToMap ) -from typing import List, Dict +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -118,7 +123,7 @@ def init( map_grid: float, map_last: numpy.ndarray, group_centers: numpy.ndarray, - **kwargs) -> None: + **kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer. Arguments: diff --git a/ng_trajectory/penalizers/centerline/main.py b/ng_trajectory/penalizers/centerline/main.py index f2c7087..9810c69 100644 --- a/ng_trajectory/penalizers/centerline/main.py +++ b/ng_trajectory/penalizers/centerline/main.py @@ -14,7 +14,12 @@ from ng_trajectory.parameter import ParameterList from ng_trajectory.penalizers.utils import eInvalidPoints -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -76,7 +81,7 @@ # Functions ###################### -def init(start_points: numpy.ndarray, **kwargs) -> None: +def init(start_points: numpy.ndarray, **kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer. Arguments: diff --git a/ng_trajectory/penalizers/count/main.py b/ng_trajectory/penalizers/count/main.py index 410f167..5609620 100644 --- a/ng_trajectory/penalizers/count/main.py +++ b/ng_trajectory/penalizers/count/main.py @@ -12,6 +12,12 @@ from ng_trajectory.penalizers.utils import eInvalidPoints +from typing import ( + Any, + Dict, + Optional, +) + # Global variables INVALID_POINTS = [] @@ -21,7 +27,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer.""" pass diff --git a/ng_trajectory/penalizers/curvature/main.py b/ng_trajectory/penalizers/curvature/main.py index 36cd460..ab47fe7 100644 --- a/ng_trajectory/penalizers/curvature/main.py +++ b/ng_trajectory/penalizers/curvature/main.py @@ -14,6 +14,12 @@ from ng_trajectory.parameter import ParameterList from ng_trajectory.penalizers.utils import eInvalidPoints +from typing import ( + Any, + Dict, + Optional, +) + # Global variables INVALID_POINTS = [] @@ -28,7 +34,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer.""" # Update parameters P.updateAll(kwargs) diff --git a/ng_trajectory/penalizers/none/main.py b/ng_trajectory/penalizers/none/main.py index 7154908..c141faf 100644 --- a/ng_trajectory/penalizers/none/main.py +++ b/ng_trajectory/penalizers/none/main.py @@ -10,6 +10,12 @@ import numpy +from typing import ( + Any, + Dict, + Optional, +) + # Global variables INVALID_POINTS = [] @@ -19,7 +25,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer.""" pass diff --git a/ng_trajectory/penalizers/segment/main.py b/ng_trajectory/penalizers/segment/main.py index b2db892..3b25546 100644 --- a/ng_trajectory/penalizers/segment/main.py +++ b/ng_trajectory/penalizers/segment/main.py @@ -34,7 +34,12 @@ # Optimization methods from ng_trajectory.penalizers import utils -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -92,7 +97,7 @@ def init( map_origin: numpy.ndarray, map_grid: float, map_last: numpy.ndarray, - **kwargs) -> None: + **kwargs) -> Optional[Dict[str, Any]]: """Initialize penalizer. Arguments: diff --git a/ng_trajectory/segmentators/euclidean/main.py b/ng_trajectory/segmentators/euclidean/main.py index 1409a71..a4b16bd 100644 --- a/ng_trajectory/segmentators/euclidean/main.py +++ b/ng_trajectory/segmentators/euclidean/main.py @@ -17,7 +17,12 @@ from ng_trajectory.interpolators.utils import pointDistance from ng_trajectory.parameter import ParameterList -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Parameters @@ -29,7 +34,7 @@ # Functions ###################### -def init(track: numpy.ndarray, **kwargs) -> None: +def init(track: numpy.ndarray, **kwargs) -> Optional[Dict[str, Any]]: """Initialize segmentator.""" pass diff --git a/ng_trajectory/segmentators/flood_fill/main.py b/ng_trajectory/segmentators/flood_fill/main.py index 609ca09..5d116eb 100644 --- a/ng_trajectory/segmentators/flood_fill/main.py +++ b/ng_trajectory/segmentators/flood_fill/main.py @@ -25,7 +25,12 @@ # Parallel execution of flood fill from concurrent import futures -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -135,7 +140,7 @@ def segmentDistance(p: List[float], a: List[float], b: List[float]) -> float: # Functions ###################### -def init(track: numpy.ndarray, **kwargs) -> None: +def init(track: numpy.ndarray, **kwargs) -> Optional[Dict[str, Any]]: """Initialize segmentator by creating map.""" global MAP, MAP_ORIGIN, MAP_GRID diff --git a/ng_trajectory/selectors/curvature/main.py b/ng_trajectory/selectors/curvature/main.py index 11c4053..d99307f 100644 --- a/ng_trajectory/selectors/curvature/main.py +++ b/ng_trajectory/selectors/curvature/main.py @@ -19,7 +19,11 @@ from scipy.signal import find_peaks from . import curve_fitting as cf -from typing import Dict +from typing import ( + Any, + Dict, + Optional, +) # Parameters @@ -98,7 +102,7 @@ def mergePeaks( # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize selector. Arguments: diff --git a/ng_trajectory/selectors/curvature2/main.py b/ng_trajectory/selectors/curvature2/main.py index a66e918..33b7f92 100644 --- a/ng_trajectory/selectors/curvature2/main.py +++ b/ng_trajectory/selectors/curvature2/main.py @@ -28,7 +28,12 @@ from ng_trajectory.plot import PLOT_AVAILABLE # Typing -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Parameters @@ -285,7 +290,7 @@ def peaksMerge( # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize selector. Arguments: diff --git a/ng_trajectory/selectors/curvature_sample/main.py b/ng_trajectory/selectors/curvature_sample/main.py index a6be342..ef2a85d 100644 --- a/ng_trajectory/selectors/curvature_sample/main.py +++ b/ng_trajectory/selectors/curvature_sample/main.py @@ -15,6 +15,12 @@ from ng_trajectory.parameter import ParameterList from ng_trajectory.selectors.curvature import curve_fitting as cf +from typing import ( + Any, + Dict, + Optional, +) + # Parameters P = ParameterList() @@ -25,7 +31,7 @@ # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize selector. Arguments: diff --git a/ng_trajectory/selectors/fixed/main.py b/ng_trajectory/selectors/fixed/main.py index 7f42c48..b9da6ac 100644 --- a/ng_trajectory/selectors/fixed/main.py +++ b/ng_trajectory/selectors/fixed/main.py @@ -12,7 +12,12 @@ from ng_trajectory.parameter import ParameterList -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -30,7 +35,7 @@ def init( points: List[List[float]] = "", - **kwargs) -> None: + **kwargs) -> Optional[Dict[str, Any]]: """Initialize selector. Arguments: diff --git a/ng_trajectory/selectors/uniform/main.py b/ng_trajectory/selectors/uniform/main.py index 996fb6b..41261f4 100644 --- a/ng_trajectory/selectors/uniform/main.py +++ b/ng_trajectory/selectors/uniform/main.py @@ -18,6 +18,12 @@ from ng_trajectory.parameter import ParameterList +from typing import ( + Any, + Dict, + Optional, +) + # Global variables ROTATE = 0 @@ -33,7 +39,7 @@ def init( rotate: float = 0, - **kwargs) -> None: + **kwargs) -> Optional[Dict[str, Any]]: """Initialize selector. Arguments: diff --git a/ng_trajectory/selectors/uniform_distance/main.py b/ng_trajectory/selectors/uniform_distance/main.py index 877f4fb..c26e94d 100644 --- a/ng_trajectory/selectors/uniform_distance/main.py +++ b/ng_trajectory/selectors/uniform_distance/main.py @@ -32,6 +32,12 @@ # Resampling for rotation required GCD import fractions +from typing import ( + Any, + Dict, + Optional, +) + # Global variables INTERPOLATOR = cubic_spline @@ -261,7 +267,7 @@ def trajectoryResample(points, remain): # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize selector.""" # Check value for rotate if "rotate" in kwargs: diff --git a/ng_trajectory/selectors/uniform_time/main.py b/ng_trajectory/selectors/uniform_time/main.py index ce8acef..20d4159 100644 --- a/ng_trajectory/selectors/uniform_time/main.py +++ b/ng_trajectory/selectors/uniform_time/main.py @@ -33,7 +33,12 @@ from ng_trajectory.log import print0 # Typing -from typing import List +from typing import ( + Any, + Dict, + List, + Optional, +) # Global variables @@ -101,7 +106,7 @@ def timeSample( # Functions ###################### -def init(**kwargs) -> None: +def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize selector.""" P.updateAll(kwargs) From 91045c5214b978f8429ff871c82ee12a0e9f2eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Thu, 14 Nov 2024 15:01:25 +0100 Subject: [PATCH 2/8] Add 'reference_obtain_start' functionality to profile2 criterion --- CHANGELOG.md | 5 ++ ng_trajectory/criterions/profile2/main.py | 62 ++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e3540a..7eacadc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Unreleased +### Added +- Criterions + - _Profile2_ + - Parameters `reference_obtain_start` and `reference_obtain_start_td` to prepare the criterion and whole pipeline to generate overtaking maneuvers. Using this generates following parameters that overwrite values in the configuration: `v_0`, `fixed_points` and `fixed_segments`. + ### Changed - Initialization (`init()`) of all algorithms may now return an optional dictionary. When returned, it is fused together with the configuration of the current cascade step (except penalizers as they are handled by the optimizers). diff --git a/ng_trajectory/criterions/profile2/main.py b/ng_trajectory/criterions/profile2/main.py index 3a5d694..e10ab17 100644 --- a/ng_trajectory/criterions/profile2/main.py +++ b/ng_trajectory/criterions/profile2/main.py @@ -33,7 +33,7 @@ from ng_trajectory.log import ( logfileName, - log, logvv, + log, logv, logvv, print0 ) @@ -88,6 +88,8 @@ P.createAdd("reference_dist", 1.0, float, "Minimum allowed distance from the reference at given time [m].", "init") P.createAdd("reference_rotate", 0, int, "Number of points to rotate the reference trajectory.", "init") P.createAdd("reference_laptime", 0, float, "Lap time of the given reference. 0 = estimated from data", "init") +P.createAdd("reference_obtain_start", False, bool, "When given, initial speed and initial position of the vehicle is computed.", "init") +P.createAdd("reference_obtain_start_td", 0.0, float, "Time distance behind the reference [s].", "init") P.createAdd("save_solution_csv", "$", str, "When non-empty, save final trajectory to this file as CSV. Use '$' to use log name instead.", "init") P.createAdd("plot", False, bool, "Whether a graphical representation should be created.", "init (viz.)") P.createAdd("plot_reference", False, bool, "Whether the reference trajectory should be plotted.", "init (viz.)") @@ -474,6 +476,8 @@ def init(**kwargs) -> Optional[Dict[str, Any]]: """Initialize criterion.""" global REFERENCE, CENTERLINE, OVERTAKING_POINTS, MAP_OUTSIDE, MAP_INSIDE + cri_dict = {} + profiler.parametersSet(**kwargs) P.updateAll(kwargs) @@ -490,6 +494,8 @@ def init(**kwargs) -> Optional[Dict[str, Any]]: logfileName() + ".csv" ) + lap_time = 0.0 + if P.getValue("reference") is not None: REFERENCE = numpy.load(P.getValue("reference"))[:, :4] @@ -565,6 +571,58 @@ def init(**kwargs) -> Optional[Dict[str, Any]]: else: REFERENCE = None + if P.getValue("reference_obtain_start") and REFERENCE is not None: + """ + This section is used to compute starting location of the ego car, + to properly set-up the environment for overtaking maneuvers. + """ + # 1. Obtain the starting position. + _start_time = lap_time - P.getValue("reference_obtain_start_td") + _start_time %= lap_time + + _start_id = numpy.argmin( + numpy.sqrt( + numpy.power(REFERENCE[:, 2] - _start_time, 2) + ) + ) + + # 2. Obtain the initial speed. + profiler.parametersSet(v_0 = REFERENCE[_start_id, 3]) + cri_dict["v_0"] = REFERENCE[_start_id, 3] + + # 3. Obtain the positions of fixed points / segments. + # This will enforce starting position of the ego car, as well as + # its initial heading. + # Note: In the original work, the distance between the two points + # was actually 1 -- X -- 2 from the reference. So we use that. + # Side note: There is a limit how close the points can be. If they + # are too close, then the selector/segmentator/optimizer + # will fuse them together/associate with the same segment. + # And that is something we don't want. + _second_id = (_start_id + 2) % len(REFERENCE) + + # Note: As a workaround, we have to push this into 'selector_args'. + # Currently, optimizers do not pass the whole configuration, but only + # selected parts. + cri_dict["selector_args"] = { + "fixed_points": [ + [REFERENCE[_start_id, 0], REFERENCE[_start_id, 1]], + [REFERENCE[_second_id, 0], REFERENCE[_second_id, 1]] + ] + } + cri_dict["fixed_segments"] = [ + [REFERENCE[_start_id, 0], REFERENCE[_start_id, 1]], + [REFERENCE[_second_id, 0], REFERENCE[_second_id, 1]] + ] + + log ( + "Computed ego start location, td = %fs (requested %fs)" + % ( + lap_time - REFERENCE[_start_id, 2], + P.getValue("reference_obtain_start_td") + ) + ) + if P.getValue("friction_map") is not None: fmap = numpy.load(P.getValue("friction_map")) @@ -658,6 +716,8 @@ def init(**kwargs) -> Optional[Dict[str, Any]]: ]) ) + return cri_dict if len(cri_dict) > 0 else None + def compute( points: numpy.ndarray, From 188cc9c3619d8c5fb3c8a32e99f89674a4482204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Thu, 14 Nov 2024 15:09:46 +0100 Subject: [PATCH 3/8] (F) Truly merge dicts from init functions to avoid losing parameters --- ng_trajectory/main.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/ng_trajectory/main.py b/ng_trajectory/main.py index 7f6a712..09c5d89 100644 --- a/ng_trajectory/main.py +++ b/ng_trajectory/main.py @@ -246,14 +246,14 @@ def configurationAppend(conf: Dict[str, any]) -> bool: return True -def configurationMerge(conf: Dict[str, any]) -> bool: - """Merge configuration with the global settings. +def dictMerge(dict1: Dict[str, any], dict2: Dict[str, any]) -> Dict[str, any]: + """Merge two dictionaries in a 'true merge'. Arguments: - conf -- configuration to merge, dict + dict1, dict2 -- dictionaries to merge, dict[str, any] Returns: - success -- True when loaded, otherwise False + merged dictionary, dict[str, any] Note: This crawls through the dicts and performs a 'true merge'; merging values in the subdicts. @@ -261,8 +261,6 @@ def configurationMerge(conf: Dict[str, any]) -> bool: Sources: https://stackoverflow.com/a/7205672 """ - global CONFIGURATION - def mergedicts(dict1, dict2): for k in set(dict1.keys()).union(dict2.keys()): if k in dict1 and k in dict2: @@ -280,7 +278,21 @@ def mergedicts(dict1, dict2): else: yield (k, dict2[k]) - CONFIGURATION = dict(mergedicts(CONFIGURATION, conf)) + return dict(mergedicts(dict1, dict2)) + + +def configurationMerge(conf: Dict[str, any]) -> bool: + """Merge configuration with the global settings. + + Arguments: + conf -- configuration to merge, dict + + Returns: + success -- True when loaded, otherwise False + """ + global CONFIGURATION + + CONFIGURATION = dictMerge(CONFIGURATION, conf) verbositySet(CONFIGURATION.get("logging_verbosity", 1)) @@ -457,7 +469,7 @@ def cascadeRun( } ) if _sel_dict is not None: - _alg = {**_alg, **_sel_dict} + _alg = dictMerge(_alg, _sel_dict) _itp_dict = itp.init( **{ @@ -466,7 +478,7 @@ def cascadeRun( } ) if _itp_dict is not None: - _alg = {**_alg, **_itp_dict} + _alg = dictMerge(_alg, _itp_dict) _seg_dict = seg.init( track, @@ -476,7 +488,7 @@ def cascadeRun( } ) if _seg_dict is not None: - _alg = {**_alg, **_seg_dict} + _alg = dictMerge(_alg, _seg_dict) _cri_dict = cri.init( **{ @@ -485,7 +497,7 @@ def cascadeRun( } ) if _cri_dict is not None: - _alg = {**_alg, **_cri_dict} + _alg = dictMerge(_alg, _cri_dict) # Note: This passes the initial line (which is usually centerline). # TODO: Actually pass centerline. @@ -506,7 +518,7 @@ def cascadeRun( } ) if _opt_dict is not None: - _alg = {**_alg, **_opt_dict} + _alg = dictMerge(_alg, _opt_dict) logfileFlush() From 40208451dd894c0a4ef857c6f4e111b6219573e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Thu, 14 Nov 2024 16:13:04 +0100 Subject: [PATCH 4/8] Allow setting 'fixed_points' from 'selector_args' as well --- CHANGELOG.md | 7 ++++++- ng_trajectory/selectors/uniform_distance/main.py | 5 ++++- ng_trajectory/selectors/uniform_time/main.py | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eacadc..81514e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - Parameters `reference_obtain_start` and `reference_obtain_start_td` to prepare the criterion and whole pipeline to generate overtaking maneuvers. Using this generates following parameters that overwrite values in the configuration: `v_0`, `fixed_points` and `fixed_segments`. ### Changed - - Initialization (`init()`) of all algorithms may now return an optional dictionary. When returned, it is fused together with the configuration of the current cascade step (except penalizers as they are handled by the optimizers). +- Selectors + - _Uniform_distance_ + - Parameter `fixed_points` can be now set from `selector_args` as well. + - _Uniform_time_ + - Parameter `fixed_points` can be now set from `selector_args` as well. +- Initialization (`init()`) of all algorithms may now return an optional dictionary. When returned, it is fused together with the configuration of the current cascade step (except penalizers as they are handled by the optimizers). ## 1.15.2 - 2024-11-12 ### Added diff --git a/ng_trajectory/selectors/uniform_distance/main.py b/ng_trajectory/selectors/uniform_distance/main.py index c26e94d..b0c6e4f 100644 --- a/ng_trajectory/selectors/uniform_distance/main.py +++ b/ng_trajectory/selectors/uniform_distance/main.py @@ -48,7 +48,7 @@ P.createAdd("sampling_distance", 1.0, float, "[m] Distance of super-sampling before the interpolation, skipped when 0.", "init") P.createAdd("distance", 0, float, "[m] Distance between the individual points, ignored when 0, used when requesting negative number of points.", "init") P.createAdd("rotate", 0, float, "Parameter for rotating the input path. 0 is not rotated. <0, 1)", "init") -P.createAdd("fixed_points", [], list, "Points to be used in the selection upon calling 'select'.", "init") +P.createAdd("fixed_points", [], list, "Points to be used in the selection upon calling 'select'.", "") ###################### @@ -328,6 +328,9 @@ def select(points: numpy.ndarray, remain: int, **overflown) -> numpy.ndarray: "for 'uniform_distance' selector." ) + if "fixed_points" in overflown: + P.update("fixed_points", overflown["fixed_points"]) + rpoints = trajectoryResample(points, remain) # !Force number of points diff --git a/ng_trajectory/selectors/uniform_time/main.py b/ng_trajectory/selectors/uniform_time/main.py index 20d4159..4a281d7 100644 --- a/ng_trajectory/selectors/uniform_time/main.py +++ b/ng_trajectory/selectors/uniform_time/main.py @@ -149,6 +149,9 @@ def select(points: numpy.ndarray, remain: int, **overflown) -> numpy.ndarray: file = sys.stderr ) + if "fixed_points" in overflown: + P.update("fixed_points", overflown["fixed_points"]) + # Resample the trajectory (even with the super sampling!) resampled_trajectory = trajectoryResample(points, -1) From 2548ace6bb26e9b5653f34501448b870ac5c5e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Mon, 18 Nov 2024 06:47:41 +0100 Subject: [PATCH 5/8] Print out a message when setting undeclared global variable in profile* criterions --- CHANGELOG.md | 3 +++ ng_trajectory/criterions/profile/profiler.py | 10 ++++++++++ ng_trajectory/criterions/profile2/profiler.py | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81514e9..a84f584 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Unreleased ### Added - Criterions + - _Profile_ + - Print out a message when setting global variable that does not exist in `profiler.parametersSet`. - _Profile2_ - Parameters `reference_obtain_start` and `reference_obtain_start_td` to prepare the criterion and whole pipeline to generate overtaking maneuvers. Using this generates following parameters that overwrite values in the configuration: `v_0`, `fixed_points` and `fixed_segments`. + - Print out a message when setting global variable that does not exist in `profiler.parametersSet`. ### Changed - Selectors diff --git a/ng_trajectory/criterions/profile/profiler.py b/ng_trajectory/criterions/profile/profiler.py index 32b7cc9..c6f9a89 100644 --- a/ng_trajectory/criterions/profile/profiler.py +++ b/ng_trajectory/criterions/profile/profiler.py @@ -16,6 +16,8 @@ from ng_trajectory.segmentators.utils import pointToMap +from ng_trajectory.log import print0 + from typing import List, Tuple, TextIO, Optional @@ -41,7 +43,15 @@ def parametersSet(**kwargs) -> None: """Set parameters of the profiler.""" + _gls = globals() + for _parameter, _value in kwargs.items(): + if _parameter not in _gls: + print0( + "profiler2: Setting global variable '%s' that does not exist." + % _parameter + ) + globals()[_parameter] = _value diff --git a/ng_trajectory/criterions/profile2/profiler.py b/ng_trajectory/criterions/profile2/profiler.py index 4faaf84..28ef069 100644 --- a/ng_trajectory/criterions/profile2/profiler.py +++ b/ng_trajectory/criterions/profile2/profiler.py @@ -16,6 +16,8 @@ from ng_trajectory.segmentators.utils import pointToMap +from ng_trajectory.log import print0 + from typing import List, Tuple, TextIO @@ -41,7 +43,15 @@ def parametersSet(**kwargs) -> None: """Set parameters of the profiler.""" + _gls = globals() + for _parameter, _value in kwargs.items(): + if _parameter not in _gls: + print0( + "profiler2: Setting global variable '%s' that does not exist." + % _parameter + ) + globals()[_parameter] = _value From 04cb411bdf21b3fb595a26bc1c7507f3a1195d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Mon, 18 Nov 2024 07:10:12 +0100 Subject: [PATCH 6/8] (F) Resolve numpy VisibleDeprecationWarning in profile2 criterion --- CHANGELOG.md | 5 +++++ ng_trajectory/criterions/profile2/main.py | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84f584..570fccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - Parameter `fixed_points` can be now set from `selector_args` as well. - Initialization (`init()`) of all algorithms may now return an optional dictionary. When returned, it is fused together with the configuration of the current cascade step (except penalizers as they are handled by the optimizers). +### Fixed +- Criterions + - _Profile2_ + - Properly save npy data without raising ragged array 'VisibleDeprecationWarning'. + ## 1.15.2 - 2024-11-12 ### Added - 'ng_generate_data' diff --git a/ng_trajectory/criterions/profile2/main.py b/ng_trajectory/criterions/profile2/main.py index e10ab17..d57a5a0 100644 --- a/ng_trajectory/criterions/profile2/main.py +++ b/ng_trajectory/criterions/profile2/main.py @@ -1350,6 +1350,9 @@ def compute( if not overflown.get("optimization", True): # FIXME: This probably fails at some occasions. file_name = logfileName().replace("matryoshka.log", "save.npy") - numpy.save(file_name, data_to_save) + numpy.save( + file_name, + numpy.asarray(data_to_save, dtype = object) + ) return float(criterion) From c8be740c650c748dafb3a43a823b292f4473cfbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Mon, 18 Nov 2024 07:26:47 +0100 Subject: [PATCH 7/8] Revert "Print out a message when setting undeclared global variable in profile* criterions" This reverts commit 2548ace6bb26e9b5653f34501448b870ac5c5e84. Unfortunately, in the current state this function sets a LOT of variables that are not required to be there. This needs to be solved at first. --- CHANGELOG.md | 3 --- ng_trajectory/criterions/profile/profiler.py | 10 ---------- ng_trajectory/criterions/profile2/profiler.py | 10 ---------- 3 files changed, 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 570fccf..a17c9b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Unreleased ### Added - Criterions - - _Profile_ - - Print out a message when setting global variable that does not exist in `profiler.parametersSet`. - _Profile2_ - Parameters `reference_obtain_start` and `reference_obtain_start_td` to prepare the criterion and whole pipeline to generate overtaking maneuvers. Using this generates following parameters that overwrite values in the configuration: `v_0`, `fixed_points` and `fixed_segments`. - - Print out a message when setting global variable that does not exist in `profiler.parametersSet`. ### Changed - Selectors diff --git a/ng_trajectory/criterions/profile/profiler.py b/ng_trajectory/criterions/profile/profiler.py index c6f9a89..32b7cc9 100644 --- a/ng_trajectory/criterions/profile/profiler.py +++ b/ng_trajectory/criterions/profile/profiler.py @@ -16,8 +16,6 @@ from ng_trajectory.segmentators.utils import pointToMap -from ng_trajectory.log import print0 - from typing import List, Tuple, TextIO, Optional @@ -43,15 +41,7 @@ def parametersSet(**kwargs) -> None: """Set parameters of the profiler.""" - _gls = globals() - for _parameter, _value in kwargs.items(): - if _parameter not in _gls: - print0( - "profiler2: Setting global variable '%s' that does not exist." - % _parameter - ) - globals()[_parameter] = _value diff --git a/ng_trajectory/criterions/profile2/profiler.py b/ng_trajectory/criterions/profile2/profiler.py index 28ef069..4faaf84 100644 --- a/ng_trajectory/criterions/profile2/profiler.py +++ b/ng_trajectory/criterions/profile2/profiler.py @@ -16,8 +16,6 @@ from ng_trajectory.segmentators.utils import pointToMap -from ng_trajectory.log import print0 - from typing import List, Tuple, TextIO @@ -43,15 +41,7 @@ def parametersSet(**kwargs) -> None: """Set parameters of the profiler.""" - _gls = globals() - for _parameter, _value in kwargs.items(): - if _parameter not in _gls: - print0( - "profiler2: Setting global variable '%s' that does not exist." - % _parameter - ) - globals()[_parameter] = _value From 73a766144e6a24fa9f9a7bcd999e774378077404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Klap=C3=A1lek?= Date: Mon, 18 Nov 2024 07:45:01 +0100 Subject: [PATCH 8/8] Release version 1.15.3 --- CHANGELOG.md | 1 + CITATION.cff | 4 ++-- doc/README.md | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a17c9b3..741fa2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## Unreleased +## 1.15.3 - 2024-11-18 ### Added - Criterions - _Profile2_ diff --git a/CITATION.cff b/CITATION.cff index dfc4eca..42af8a6 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -5,8 +5,8 @@ authors: given-names: "Jaroslav" orcid: "https://orcid.org/0000-0001-8816-2773" title: "ng_trajectory" -version: 1.15.2 -date-released: 2024-11-12 +version: 1.15.3 +date-released: 2024-11-18 url: "https://github.com/jara001/ng_trajectory" license: GPL-3.0 preferred-citation: diff --git a/doc/README.md b/doc/README.md index aebb025..c03552d 100644 --- a/doc/README.md +++ b/doc/README.md @@ -334,6 +334,8 @@ reference (str) = None [Name of the file to load (x, y, t, v) reference path tha reference_dist (float) = 1.0 [Minimum allowed distance from the reference at given time [m].] reference_rotate (int) = 0 [Number of points to rotate the reference trajectory.] reference_laptime (float) = 0 [Lap time of the given reference. 0 = estimated from data] +reference_obtain_start (bool) = False [When given, initial speed and initial position of the vehicle is computed.] +reference_obtain_start_td (float) = 0.0 [Time distance behind the reference [s].] save_solution_csv (str) = $ [When non-empty, save final trajectory to this file as CSV. Use '$' to use log name instead.] favor_overtaking (float) = 0 [Penalty value to add to the lap time when overtaking does not occur.] friction_map (str) = None [Name of the file to load (x, y, mu*100) with friction map.] @@ -553,11 +555,13 @@ This selector uniformly samples the input path so that the selected points are e ```html +Parameters: +fixed_points (list) = [] [Points to be used in the selection upon calling 'select'.] + Init parameters: sampling_distance (float) = 1.0 [[m] Distance of super-sampling before the interpolation, skipped when 0.] distance (float) = 0 [[m] Distance between the individual points, ignored when 0, used when requesting negative number of points.] rotate (float) = 0 [Parameter for rotating the input path. 0 is not rotated. <0, 1)] -fixed_points (list) = [] [Points to be used in the selection upon calling 'select'.] ``` @@ -592,6 +596,7 @@ Following algorithms are used: Parameters: overlap (int) = 0 [Size of the trajectory overlap. 0 disables this.] friction_map_yaml (str) = None [(Requires pyyaml) Name of the yaml configuration of the original map that was used to create '.npy' files. Map file specified in the configuration has to exist.] +fixed_points (list) = [] [Points to be used in the selection upon calling 'select'.] Init parameters: rotate (float) = 0 [Parameter for rotating the input path. 0 is not rotated. <0, 1)] @@ -620,7 +625,6 @@ friction_map_plot (bool) = False [When True, friction map is plotted.] friction_map_save (bool) = False [When True, friction map is saved alongside the log files.] sampling_distance (float) = 1.0 [[m] Distance of super-sampling before the interpolation, skipped when 0.] distance (float) = 0 [[m] Distance between the individual points, ignored when 0, used when requesting negative number of points.] -fixed_points (list) = [] [Points to be used in the selection upon calling 'select'.] Init (viz.) parameters: plot (bool) = False [Whether a graphical representation should be created.]