diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..8b4cf0b --- /dev/null +++ b/404.html @@ -0,0 +1,2393 @@ + + + + + + + + + + + + + + + + + + + + + + + Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/css/extensions/tabbed.css b/assets/css/extensions/tabbed.css new file mode 100644 index 0000000..7fc9ae2 --- /dev/null +++ b/assets/css/extensions/tabbed.css @@ -0,0 +1,41 @@ +.tabbed-set { + display: flex; + position: relative; + flex-wrap: wrap; +} + +.tabbed-set .highlight { + background: #ddd; +} + +.tabbed-set .tabbed-content { + display: none; + order: 99; + width: 100%; +} + +.tabbed-set label { + width: auto; + margin: 0 0.5em; + padding: 0.25em; + font-size: 120%; + cursor: pointer; + color: #ffffff !important; +} + +.tabbed-set input { + position: absolute; + opacity: 0; +} + +.tabbed-set input:nth-child(n+1) { + color: #333333; +} + +.tabbed-set input:nth-child(n+1):checked + label { + color: cyan !important; +} + +.tabbed-set input:nth-child(n+1):checked + label + .tabbed-content { + display: block; +} \ No newline at end of file diff --git a/assets/css/extra.css b/assets/css/extra.css new file mode 100644 index 0000000..7d08509 --- /dev/null +++ b/assets/css/extra.css @@ -0,0 +1 @@ +@import "extensions/tabbed.css"; diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000..1cf13b9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/images/favicon.svg b/assets/images/favicon.svg new file mode 100644 index 0000000..23e4cf7 --- /dev/null +++ b/assets/images/favicon.svg @@ -0,0 +1,17 @@ + + + + + + + diff --git a/assets/images/social/bevezetes/README.png b/assets/images/social/bevezetes/README.png new file mode 100644 index 0000000..9b290ee Binary files /dev/null and b/assets/images/social/bevezetes/README.png differ diff --git a/assets/images/social/bevezetes/copilot.png b/assets/images/social/bevezetes/copilot.png new file mode 100644 index 0000000..6102ddf Binary files /dev/null and b/assets/images/social/bevezetes/copilot.png differ diff --git a/assets/images/social/bevezetes/gepterem.png b/assets/images/social/bevezetes/gepterem.png new file mode 100644 index 0000000..faa6876 Binary files /dev/null and b/assets/images/social/bevezetes/gepterem.png differ diff --git a/assets/images/social/bevezetes/linux.png b/assets/images/social/bevezetes/linux.png new file mode 100644 index 0000000..c9f8013 Binary files /dev/null and b/assets/images/social/bevezetes/linux.png differ diff --git a/assets/images/social/bevezetes/practice.png b/assets/images/social/bevezetes/practice.png new file mode 100644 index 0000000..1507517 Binary files /dev/null and b/assets/images/social/bevezetes/practice.png differ diff --git a/assets/images/social/bevezetes/ros2.png b/assets/images/social/bevezetes/ros2.png new file mode 100644 index 0000000..3e4baa1 Binary files /dev/null and b/assets/images/social/bevezetes/ros2.png differ diff --git a/assets/images/social/bevezetes/ros2gyak.png b/assets/images/social/bevezetes/ros2gyak.png new file mode 100644 index 0000000..c8ccfc4 Binary files /dev/null and b/assets/images/social/bevezetes/ros2gyak.png differ diff --git a/assets/images/social/bevezetes/vscodegit.png b/assets/images/social/bevezetes/vscodegit.png new file mode 100644 index 0000000..f2247f8 Binary files /dev/null and b/assets/images/social/bevezetes/vscodegit.png differ diff --git a/assets/images/social/erzekeles/README.png b/assets/images/social/erzekeles/README.png new file mode 100644 index 0000000..0573afb Binary files /dev/null and b/assets/images/social/erzekeles/README.png differ diff --git a/assets/images/social/erzekeles/practice.png b/assets/images/social/erzekeles/practice.png new file mode 100644 index 0000000..925a6a2 Binary files /dev/null and b/assets/images/social/erzekeles/practice.png differ diff --git a/assets/images/social/eszleles/README.png b/assets/images/social/eszleles/README.png new file mode 100644 index 0000000..7f86b11 Binary files /dev/null and b/assets/images/social/eszleles/README.png differ diff --git a/assets/images/social/eszleles/ground_filter.png b/assets/images/social/eszleles/ground_filter.png new file mode 100644 index 0000000..7d05cde Binary files /dev/null and b/assets/images/social/eszleles/ground_filter.png differ diff --git a/assets/images/social/eszleles/practice.png b/assets/images/social/eszleles/practice.png new file mode 100644 index 0000000..0b682c8 Binary files /dev/null and b/assets/images/social/eszleles/practice.png differ diff --git a/assets/images/social/eszleles/practice_cluster.png b/assets/images/social/eszleles/practice_cluster.png new file mode 100644 index 0000000..32cff96 Binary files /dev/null and b/assets/images/social/eszleles/practice_cluster.png differ diff --git a/assets/images/social/eszleles/road_filter.png b/assets/images/social/eszleles/road_filter.png new file mode 100644 index 0000000..5b3fde8 Binary files /dev/null and b/assets/images/social/eszleles/road_filter.png differ diff --git a/assets/images/social/eszleles/slam.png b/assets/images/social/eszleles/slam.png new file mode 100644 index 0000000..a71809b Binary files /dev/null and b/assets/images/social/eszleles/slam.png differ diff --git a/assets/images/social/feleves_beadando/README.png b/assets/images/social/feleves_beadando/README.png new file mode 100644 index 0000000..696750e Binary files /dev/null and b/assets/images/social/feleves_beadando/README.png differ diff --git a/assets/images/social/feleves_beadando/kisbeadando.png b/assets/images/social/feleves_beadando/kisbeadando.png new file mode 100644 index 0000000..c07acdf Binary files /dev/null and b/assets/images/social/feleves_beadando/kisbeadando.png differ diff --git a/assets/images/social/feleves_beadando/nagyfeleves.png b/assets/images/social/feleves_beadando/nagyfeleves.png new file mode 100644 index 0000000..f135591 Binary files /dev/null and b/assets/images/social/feleves_beadando/nagyfeleves.png differ diff --git a/assets/images/social/index.png b/assets/images/social/index.png new file mode 100644 index 0000000..ca7be75 Binary files /dev/null and b/assets/images/social/index.png differ diff --git a/assets/images/social/kalman_filter/README.png b/assets/images/social/kalman_filter/README.png new file mode 100644 index 0000000..500e482 Binary files /dev/null and b/assets/images/social/kalman_filter/README.png differ diff --git a/assets/images/social/kalman_filter/practice.png b/assets/images/social/kalman_filter/practice.png new file mode 100644 index 0000000..65e7785 Binary files /dev/null and b/assets/images/social/kalman_filter/practice.png differ diff --git a/assets/images/social/linkek/README.png b/assets/images/social/linkek/README.png new file mode 100644 index 0000000..15b4d3a Binary files /dev/null and b/assets/images/social/linkek/README.png differ diff --git a/assets/images/social/mesterseges_intelligencia/README.png b/assets/images/social/mesterseges_intelligencia/README.png new file mode 100644 index 0000000..2a8df31 Binary files /dev/null and b/assets/images/social/mesterseges_intelligencia/README.png differ diff --git a/assets/images/social/mesterseges_intelligencia/practice.png b/assets/images/social/mesterseges_intelligencia/practice.png new file mode 100644 index 0000000..cae9381 Binary files /dev/null and b/assets/images/social/mesterseges_intelligencia/practice.png differ diff --git a/assets/images/social/onallo/README.png b/assets/images/social/onallo/README.png new file mode 100644 index 0000000..be842e7 Binary files /dev/null and b/assets/images/social/onallo/README.png differ diff --git a/assets/images/social/onallo/bashalias.png b/assets/images/social/onallo/bashalias.png new file mode 100644 index 0000000..c56c5a5 Binary files /dev/null and b/assets/images/social/onallo/bashalias.png differ diff --git a/assets/images/social/onallo/joystick.png b/assets/images/social/onallo/joystick.png new file mode 100644 index 0000000..3269628 Binary files /dev/null and b/assets/images/social/onallo/joystick.png differ diff --git a/assets/images/social/onallo/linux.png b/assets/images/social/onallo/linux.png new file mode 100644 index 0000000..8f9fb22 Binary files /dev/null and b/assets/images/social/onallo/linux.png differ diff --git a/assets/images/social/onallo/mermaid.png b/assets/images/social/onallo/mermaid.png new file mode 100644 index 0000000..c54eca2 Binary files /dev/null and b/assets/images/social/onallo/mermaid.png differ diff --git a/assets/images/social/onallo/ros2git.png b/assets/images/social/onallo/ros2git.png new file mode 100644 index 0000000..5ad6e90 Binary files /dev/null and b/assets/images/social/onallo/ros2git.png differ diff --git a/assets/images/social/onallo/ros2launchmarker.png b/assets/images/social/onallo/ros2launchmarker.png new file mode 100644 index 0000000..d1affe5 Binary files /dev/null and b/assets/images/social/onallo/ros2launchmarker.png differ diff --git a/assets/images/social/ros2halado/README.png b/assets/images/social/ros2halado/README.png new file mode 100644 index 0000000..841ae05 Binary files /dev/null and b/assets/images/social/ros2halado/README.png differ diff --git a/assets/images/social/ros2halado/docker.png b/assets/images/social/ros2halado/docker.png new file mode 100644 index 0000000..903e5d6 Binary files /dev/null and b/assets/images/social/ros2halado/docker.png differ diff --git a/assets/images/social/ros2halado/mcap.png b/assets/images/social/ros2halado/mcap.png new file mode 100644 index 0000000..a6c984c Binary files /dev/null and b/assets/images/social/ros2halado/mcap.png differ diff --git a/assets/images/social/ros2halado/pointcloud_to_grid.png b/assets/images/social/ros2halado/pointcloud_to_grid.png new file mode 100644 index 0000000..b38bfd2 Binary files /dev/null and b/assets/images/social/ros2halado/pointcloud_to_grid.png differ diff --git a/assets/images/social/ros2halado/py_cpp.png b/assets/images/social/ros2halado/py_cpp.png new file mode 100644 index 0000000..c557c5b Binary files /dev/null and b/assets/images/social/ros2halado/py_cpp.png differ diff --git a/assets/images/social/ros2halado/qos.png b/assets/images/social/ros2halado/qos.png new file mode 100644 index 0000000..333f00f Binary files /dev/null and b/assets/images/social/ros2halado/qos.png differ diff --git a/assets/images/social/ros2halado/ros2launch.png b/assets/images/social/ros2halado/ros2launch.png new file mode 100644 index 0000000..2f8351b Binary files /dev/null and b/assets/images/social/ros2halado/ros2launch.png differ diff --git a/assets/images/social/ros2halado/rqt.png b/assets/images/social/ros2halado/rqt.png new file mode 100644 index 0000000..8569d04 Binary files /dev/null and b/assets/images/social/ros2halado/rqt.png differ diff --git a/assets/images/social/ros2halado/state.png b/assets/images/social/ros2halado/state.png new file mode 100644 index 0000000..8fcae00 Binary files /dev/null and b/assets/images/social/ros2halado/state.png differ diff --git a/assets/images/social/ros2halado/vizualizacio.png b/assets/images/social/ros2halado/vizualizacio.png new file mode 100644 index 0000000..7ee3710 Binary files /dev/null and b/assets/images/social/ros2halado/vizualizacio.png differ diff --git a/assets/images/social/szabalyozas/README.png b/assets/images/social/szabalyozas/README.png new file mode 100644 index 0000000..afa8392 Binary files /dev/null and b/assets/images/social/szabalyozas/README.png differ diff --git a/assets/images/social/szabalyozas/ros1practice.png b/assets/images/social/szabalyozas/ros1practice.png new file mode 100644 index 0000000..3fb5971 Binary files /dev/null and b/assets/images/social/szabalyozas/ros1practice.png differ diff --git a/assets/images/social/szabalyozas/ros2practice.png b/assets/images/social/szabalyozas/ros2practice.png new file mode 100644 index 0000000..7fbcd94 Binary files /dev/null and b/assets/images/social/szabalyozas/ros2practice.png differ diff --git a/assets/images/social/szimulacio/README.png b/assets/images/social/szimulacio/README.png new file mode 100644 index 0000000..78c2a1c Binary files /dev/null and b/assets/images/social/szimulacio/README.png differ diff --git a/assets/images/social/szimulacio/f1tenth_sim_a.png b/assets/images/social/szimulacio/f1tenth_sim_a.png new file mode 100644 index 0000000..f1e9b11 Binary files /dev/null and b/assets/images/social/szimulacio/f1tenth_sim_a.png differ diff --git a/assets/images/social/szimulacio/gazebo_fortress.png b/assets/images/social/szimulacio/gazebo_fortress.png new file mode 100644 index 0000000..3eca612 Binary files /dev/null and b/assets/images/social/szimulacio/gazebo_fortress.png differ diff --git a/assets/images/social/szimulacio/gyakorlat.png b/assets/images/social/szimulacio/gyakorlat.png new file mode 100644 index 0000000..994202b Binary files /dev/null and b/assets/images/social/szimulacio/gyakorlat.png differ diff --git a/assets/images/social/szimulacio/lgsvl_nissan.png b/assets/images/social/szimulacio/lgsvl_nissan.png new file mode 100644 index 0000000..9f2d582 Binary files /dev/null and b/assets/images/social/szimulacio/lgsvl_nissan.png differ diff --git a/assets/images/social/telepites/README.png b/assets/images/social/telepites/README.png new file mode 100644 index 0000000..82ff1ce Binary files /dev/null and b/assets/images/social/telepites/README.png differ diff --git a/assets/images/social/telepites/ros_humble.png b/assets/images/social/telepites/ros_humble.png new file mode 100644 index 0000000..bfcd754 Binary files /dev/null and b/assets/images/social/telepites/ros_humble.png differ diff --git a/assets/images/social/telepites/ubuntu.png b/assets/images/social/telepites/ubuntu.png new file mode 100644 index 0000000..9554165 Binary files /dev/null and b/assets/images/social/telepites/ubuntu.png differ diff --git a/assets/images/social/telepites/win10.png b/assets/images/social/telepites/win10.png new file mode 100644 index 0000000..146982c Binary files /dev/null and b/assets/images/social/telepites/win10.png differ diff --git a/assets/images/social/tervezes/README.png b/assets/images/social/tervezes/README.png new file mode 100644 index 0000000..749beca Binary files /dev/null and b/assets/images/social/tervezes/README.png differ diff --git a/assets/images/social/tervezes/planning_control_diagram.png b/assets/images/social/tervezes/planning_control_diagram.png new file mode 100644 index 0000000..96acd6d Binary files /dev/null and b/assets/images/social/tervezes/planning_control_diagram.png differ diff --git a/assets/images/social/tervezes/practice.png b/assets/images/social/tervezes/practice.png new file mode 100644 index 0000000..d117e92 Binary files /dev/null and b/assets/images/social/tervezes/practice.png differ diff --git a/assets/images/social/transzformaciok/README.png b/assets/images/social/transzformaciok/README.png new file mode 100644 index 0000000..5938a3d Binary files /dev/null and b/assets/images/social/transzformaciok/README.png differ diff --git a/assets/images/social/transzformaciok/practice.png b/assets/images/social/transzformaciok/practice.png new file mode 100644 index 0000000..1a6ed2a Binary files /dev/null and b/assets/images/social/transzformaciok/practice.png differ diff --git a/assets/images/social1.png b/assets/images/social1.png new file mode 100644 index 0000000..6d3f512 Binary files /dev/null and b/assets/images/social1.png differ diff --git a/assets/javascripts/bundle.83f73b43.min.js b/assets/javascripts/bundle.83f73b43.min.js new file mode 100644 index 0000000..43d8b70 --- /dev/null +++ b/assets/javascripts/bundle.83f73b43.min.js @@ -0,0 +1,16 @@ +"use strict";(()=>{var Wi=Object.create;var gr=Object.defineProperty;var Di=Object.getOwnPropertyDescriptor;var Vi=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,Ni=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,ao=Object.prototype.propertyIsEnumerable;var io=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&io(e,r,t[r]);if(Vt)for(var r of Vt(t))ao.call(t,r)&&io(e,r,t[r]);return e};var so=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&ao.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var zi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Vi(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Di(t,n))||o.enumerable});return e};var Mt=(e,t,r)=>(r=e!=null?Wi(Ni(e)):{},zi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var co=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var lo=xr((Er,po)=>{(function(e,t){typeof Er=="object"&&typeof po!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function L(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function te(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,te())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",L,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var qr=xr((hy,On)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var $a=/["'&<>]/;On.exports=Pa;function Pa(e){var t=""+e,r=$a.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof It=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof It=="object"?It.ClipboardJS=r():t.ClipboardJS=r()})(It,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Ui}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(A){return!1}}var d=function(A){var M=f()(A);return u("cut"),M},y=d;function L(V){var A=document.documentElement.getAttribute("dir")==="rtl",M=document.createElement("textarea");M.style.fontSize="12pt",M.style.border="0",M.style.padding="0",M.style.margin="0",M.style.position="absolute",M.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return M.style.top="".concat(F,"px"),M.setAttribute("readonly",""),M.value=V,M}var X=function(A,M){var F=L(A);M.container.appendChild(F);var D=f()(F);return u("copy"),F.remove(),D},te=function(A){var M=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,M):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,M):(F=f()(A),u("copy")),F},J=te;function k(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(M){return typeof M}:k=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},k(V)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},M=A.action,F=M===void 0?"copy":M,D=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:D});if(Y)return F==="cut"?y(Y):J(Y,{container:D})},qe=ft;function Fe(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(M){return typeof M}:Fe=function(M){return M&&typeof Symbol=="function"&&M.constructor===Symbol&&M!==Symbol.prototype?"symbol":typeof M},Fe(V)}function ki(V,A){if(!(V instanceof A))throw new TypeError("Cannot call a class as a function")}function no(V,A){for(var M=0;M0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof D.action=="function"?D.action:this.defaultAction,this.target=typeof D.target=="function"?D.target:this.defaultTarget,this.text=typeof D.text=="function"?D.text:this.defaultText,this.container=Fe(D.container)==="object"?D.container:document.body}},{key:"listenClick",value:function(D){var Y=this;this.listener=c()(D,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(D){var Y=D.delegateTarget||D.currentTarget,$e=this.action(Y)||"copy",Dt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Dt?"success":"error",{action:$e,text:Dt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(D){return vr("action",D)}},{key:"defaultTarget",value:function(D){var Y=vr("target",D);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(D){return vr("text",D)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(D){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(D,Y)}},{key:"cut",value:function(D){return y(D)}},{key:"isSupported",value:function(){var D=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof D=="string"?[D]:D,$e=!!document.queryCommandSupported;return Y.forEach(function(Dt){$e=$e&&!!document.queryCommandSupported(Dt)}),$e}}]),M}(s()),Ui=Fi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,d,y){var L=c.apply(this,arguments);return l.addEventListener(u,L,y),{destroy:function(){l.removeEventListener(u,L,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(L){return s(L,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(L){L.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(L){L.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function N(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,L)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(L){u(i[0][3],L)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function uo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var zt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ue=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(L){t={error:L}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(L){i=L instanceof zt?L.errors:[L]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{ho(y)}catch(L){i=i!=null?i:[],L instanceof zt?i=q(q([],N(i)),N(L.errors)):i.push(L)}}}catch(L){o={error:L}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new zt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ho(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Ue.EMPTY;function qt(e){return e instanceof Ue||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function ho(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ue(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new To(r,o)},t}(j);var To=function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var At={now:function(){return(At.delegate||Date).now()},delegate:void 0};var Ct=function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=At);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(gt);var Lo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(yt);var kr=new Lo(Oo);var Mo=function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(gt);var _o=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(yt);var me=new _o(Mo);var S=new j(function(e){return e.complete()});function Yt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Yt(Hr(e))?e.pop():void 0}function Bt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Gt(e){return H(e==null?void 0:e.then)}function Jt(e){return H(e[bt])}function Xt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Zt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var er=Zi();function tr(e){return H(e==null?void 0:e[er])}function rr(e){return fo(this,arguments,function(){var r,o,n,i;return Nt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function or(e){return H(e==null?void 0:e.getReader)}function U(e){if(e instanceof j)return e;if(e!=null){if(Jt(e))return ea(e);if(xt(e))return ta(e);if(Gt(e))return ra(e);if(Xt(e))return Ao(e);if(tr(e))return oa(e);if(or(e))return na(e)}throw Zt(e)}function ea(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ta(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?De(t):Qo(function(){return new ir}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,L=!1,X=function(){f==null||f.unsubscribe(),f=void 0},te=function(){X(),l=u=void 0,y=L=!1},J=function(){var k=l;te(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!L&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!L&&!y&&(f=Ur(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){L=!0,X(),f=Ur(te,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Ur(te,a),qe.complete()}}),U(k).subscribe(l))})(c)}}function Ur(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var wa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return wa.pipe(m(t=>e.contains(t)),K())}function $t(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?Ht(r=>Le(+!r*t)):le,Q(e.matches(":hover"))))}function Jo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Jo(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Jo(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Tt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Xo=new g,Ta=C(()=>typeof ResizeObserver=="undefined"?Tt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Xo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ta.pipe(w(r=>r.observe(t)),v(r=>Xo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function St(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Zo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Ve(e){return{x:e.offsetLeft,y:e.offsetTop}}function en(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function tn(e){return O(h(window,"load"),h(window,"resize")).pipe(Me(0,me),m(()=>Ve(e)),Q(Ve(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ne(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Me(0,me),m(()=>pr(e)),Q(pr(e)))}var rn=new g,Sa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)rn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return Sa.pipe(w(t=>t.observe(e)),v(t=>rn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function on(e,t=16){return Ne(e).pipe(m(({y:r})=>{let o=ce(e),n=St(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function nn(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function ze(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Oa(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function La(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function an(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:nn("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Oa(o,r)}return!0}),pe());return La().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function sn(){return new g}function cn(){return location.hash.slice(1)}function pn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ma(e){return O(h(window,"hashchange"),e).pipe(m(cn),Q(cn()),b(t=>t.length>0),G(1))}function ln(e){return Ma(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function Pt(e){let t=matchMedia(e);return ar(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function mn(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function Nr(e,t){return e.pipe(v(r=>r?t():S))}function zr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return zr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function fn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function un(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function dn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function hn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(dn),Q(dn()))}function bn(){return{width:innerWidth,height:innerHeight}}function vn(){return h(window,"resize",{passive:!0}).pipe(m(bn),Q(bn()))}function gn(){return z([hn(),vn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(ee("size")),n=z([o,r]).pipe(m(()=>Ve(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function _a(e){return h(e,"message",t=>t.data)}function Aa(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function yn(e,t=new Worker(e)){let r=_a(t),o=Aa(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(W(i))),pe())}var Ca=R("#__config"),Ot=JSON.parse(Ca.textContent);Ot.base=`${new URL(Ot.base,ye())}`;function xe(){return Ot}function B(e){return Ot.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?Ot.translations[e].replace("#",t.toString()):Ot.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function ka(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function xn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ka(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ha(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function En(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ha(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Rt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function wn(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function Tn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Rt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Rt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Sn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var Ln=Mt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,Ln.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&x("nav",{class:"md-tags"},e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)})),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function _n(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function An(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function Ra(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function Cn(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map(Ra)))}var Ia=0;function ja(e){let t=z([et(e),$t(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Zo(e)).pipe(ne(Ne),pt(1),He(t),m(()=>en(e)));return t.pipe(Ae(o=>o),v(()=>z([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Fa(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Ia++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(Ht(c=>Le(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());z([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>$t(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return z([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),z([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ja(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Fa(e,{content$:new j(o=>{let n=e.title,i=wn(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function Ua(e,t){let r=C(()=>z([tn(e),Ne(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function kn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(W(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Me(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(W(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(W(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(W(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),Ua(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Wa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Da(e){let t=[];for(let r of Wa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function Hn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Da(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,Tn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(W(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?Hn(f,u):Hn(u,f)}),O(...[...a].map(([,l])=>kn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function $n(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return $n(t)}}function Pn(e,t){return C(()=>{let r=$n(e);return typeof r!="undefined"?fr(r,e,t):S})}var Rn=Mt(Br());var Va=0;function In(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return In(t)}}function Na(e){return ge(e).pipe(m(({width:t})=>({scrollable:St(e).width>t})),ee("scrollable"))}function jn(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Rn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Va++}`;let l=Sn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=In(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(W(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),Na(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function za(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Fn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),za(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Un=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,Qa=0;function Ka(){return typeof mermaid=="undefined"||mermaid instanceof Element?Tt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=Ka().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Un,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>co(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Qa++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Dn=x("table");function Vn(e){return e.replaceWith(Dn),Dn.replaceWith(An(e)),I({ref:e})}function Ya(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Nn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));z([s,ge(e),tt(e)]).pipe(W(p),Me(1,me)).subscribe({next([{active:c},l]){let f=Ve(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ne(o),ge(o)]).pipe(W(p)).subscribe(([c,l])=>{let f=St(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(W(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(W(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(W(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let L of P(":scope > input",y)){let X=R(`label[for="${L.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),L.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(W(p)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Ya(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function zn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>Pn(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>jn(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Vn(n)),...P("details",e).map(n=>Fn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>Nn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ba(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function qn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ba(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ga=0;function Ja(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?Ne(o):I({x:0,y:0}),i=O(et(t),$t(t)).pipe(K());return z([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=Ve(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function Qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ga++}`,o=Rt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Me(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ja(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Xa({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=ze("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Kn(e,t){return C(()=>z([ge(e),Xa(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Yn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(ee("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>Qn(a)));return r.subscribe(o),t.pipe(W(n),m(a=>$({ref:e},a)),Re(i.pipe(W(n))))})}function Za(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),ee("active"))}function Bn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Za(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Gn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),ee("bottom"))));return z([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function es(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Jn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Pt("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),es(t).pipe(W(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Xn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Mt(Br());function ts(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Zn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||ts(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function ei(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function rs(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[ei(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(ei(new URL(s),t))}}return r}function ur(e){return un(new URL("sitemap.xml",e)).pipe(m(t=>rs(t,new URL(e))),de(()=>I(new Map)))}function os(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ti(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ri(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function ns(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ti(document);for(let[o,n]of ti(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return We(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function oi({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ri);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>os(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(ee("pathname"),v(p=>fn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ri),v(ns),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),ee("pathname"),v(()=>e),ee("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",pn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(ee("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var ni=Mt(qr());function ii(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,ni.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function jt(e){return e.type===1}function dr(e){return e.type===3}function ai(e,t){let r=yn(e);return O(I(location.protocol!=="file:"),ze("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function si(e){var l;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:o,currentBaseURL:n}=e,i=(l=Xr(n))==null?void 0:l.pathname;if(i===void 0)return;let a=ss(o.pathname,i);if(a===void 0)return;let s=ps(t.keys());if(!t.has(s))return;let p=Xr(a,s);if(!p||!t.has(p.href))return;let c=Xr(a,r);if(c)return c.hash=o.hash,c.search=o.search,c}function Xr(e,t){try{return new URL(e,t)}catch(r){return}}function ss(e,t){if(e.startsWith(t))return e.slice(t.length)}function cs(e,t){let r=Math.min(e.length,t.length),o;for(o=0;oS)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(new URL(p)))}}return S}),v(i=>ur(i).pipe(m(a=>{var s;return(s=si({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(n=>lt(n,!0)),z([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(Cn(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var a;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let s=((a=t.version)==null?void 0:a.default)||"latest";Array.isArray(s)||(s=[s]);e:for(let p of s)for(let c of n.aliases.concat(n.version))if(new RegExp(p,"i").test(c)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let s of ae("outdated"))s.hidden=!1})}function ls(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),ze("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(jt)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return z([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function pi(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));z([t.pipe(Ae(jt)),r],(i,a)=>a).pipe(ee("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(ee("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(W(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),ls(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function li(e,{worker$:t,query$:r}){let o=new g,n=on(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);ze("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(re(r),Wr(t.pipe(Ae(jt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Vr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(W(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function ms(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function mi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(W(o)).subscribe(n=>n.preventDefault()),ms(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function fi(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function ui(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ai(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=pi(i,{worker$:n});return O(s,li(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>mi(p,{query$:s})),...ae("search-suggest",e).map(p=>fi(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function di(e,{index$:t,location$:r}){return z([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ii(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function fs(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Zr(e,o){var n=o,{header$:t}=n,r=so(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=Ve(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Me(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),W(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),fs(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),De({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),De({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),De({}))}}function bi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),De({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),De({}))).pipe(m(([o,n])=>$($({},o),n)))}function vi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return hi(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return bi(r,o)}return S}var us;function ds(e){return us||(us=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return vi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function gi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(_n(o)),t.classList.add("md-source__repository--active")}),ds(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function hs(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),ee("hidden"))}function yi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):hs(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function bs(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(ee("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(ee("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,L]=f[0];if(L-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(W(a),ee("offset"),_e(250),Ce(1),W(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),bs(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function vs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return z([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),W(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function Ei(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(W(a),ee("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),vs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function wi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(W(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(W(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ti({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Dr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function gs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Si({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(gs),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Oi({viewport$:e,tablet$:t}){z([ze("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ys(){return location.protocol==="file:"?Tt(`${new URL("search/search_index.js",eo.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",eo.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Go(),Ut=sn(),Lt=ln(Ut),to=an(),Oe=gn(),hr=Pt("(min-width: 960px)"),Mi=Pt("(min-width: 1220px)"),_i=mn(),eo=xe(),Ai=document.forms.namedItem("search")?ys():Ye,ro=new g;Zn({alert$:ro});var oo=new g;B("navigation.instant")&&oi({location$:Ut,viewport$:Oe,progress$:oo}).subscribe(ot);var Li;((Li=eo.version)==null?void 0:Li.provider)==="mike"&&ci({document$:ot});O(Ut,Lt).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});to.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});wi({viewport$:Oe,document$:ot});Ti({document$:ot,tablet$:hr});Si({document$:ot});Oi({viewport$:Oe,tablet$:hr});var rt=Kn(Se("header"),{viewport$:Oe}),Ft=ot.pipe(m(()=>Se("main")),v(e=>Gn(e,{viewport$:Oe,header$:rt})),G(1)),xs=O(...ae("consent").map(e=>En(e,{target$:Lt})),...ae("dialog").map(e=>qn(e,{alert$:ro})),...ae("palette").map(e=>Jn(e)),...ae("progress").map(e=>Xn(e,{progress$:oo})),...ae("search").map(e=>ui(e,{index$:Ai,keyboard$:to})),...ae("source").map(e=>gi(e))),Es=C(()=>O(...ae("announce").map(e=>xn(e)),...ae("content").map(e=>zn(e,{viewport$:Oe,target$:Lt,print$:_i})),...ae("content").map(e=>B("search.highlight")?di(e,{index$:Ai,location$:Ut}):S),...ae("header").map(e=>Yn(e,{viewport$:Oe,header$:rt,main$:Ft})),...ae("header-title").map(e=>Bn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Nr(Mi,()=>Zr(e,{viewport$:Oe,header$:rt,main$:Ft})):Nr(hr,()=>Zr(e,{viewport$:Oe,header$:rt,main$:Ft}))),...ae("tabs").map(e=>yi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>xi(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Lt})),...ae("top").map(e=>Ei(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Lt})))),Ci=ot.pipe(v(()=>Es),Re(xs),G(1));Ci.subscribe();window.document$=ot;window.location$=Ut;window.target$=Lt;window.keyboard$=to;window.viewport$=Oe;window.tablet$=hr;window.screen$=Mi;window.print$=_i;window.alert$=ro;window.progress$=oo;window.component$=Ci;})(); +//# sourceMappingURL=bundle.83f73b43.min.js.map + diff --git a/assets/javascripts/bundle.83f73b43.min.js.map b/assets/javascripts/bundle.83f73b43.min.js.map new file mode 100644 index 0000000..fe920b7 --- /dev/null +++ b/assets/javascripts/bundle.83f73b43.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/findurl/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2024 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n *\n * @class BehaviorSubject\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an + +
+

A tantárgy teljesítéséhez szinte elengedhetetlen a GitHub Copilot használata. A GitHub Student Developer Pack keretében a hallgatók számára ingyenesen elérhető a GitHub Copilot. A Developer Pack részletei és a regisztráció itt érhető el: education.github.com/pack. Hallgatóként a következő lépésekkel a legegyszerűbb a GitHub Copilot beszerzése:

+
    +
  • Regisztráció Hallgatói Office 365 igénylésre, @hallgato.sze.hu email, 5GB OneDrive tárhely, Office Online és Office 365 ProPlus deskop allalmazások járnak hozzá: office365.sze.hu
  • +
  • Github regisztráció illetve, amint él @hallgato.sze.hu email, második vagy elsődleges email címként beállítani a GitHub fiókban.
  • +
  • Regisztráció a GitHub Student Developer Pack-ra: education.github.com/pack
  • +
  • Pár nap múlva a GitHub Copilot elérhetővé válik a Visual Studio Code-ban. Az extension-ök között kereshető a Copilot, a Copilot chat, csak be kell jelentkezni a VS code GitHub fiókba.
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/copilot01.png b/bevezetes/copilot01.png new file mode 100644 index 0000000..fdd19c7 Binary files /dev/null and b/bevezetes/copilot01.png differ diff --git a/bevezetes/copilot02.gif b/bevezetes/copilot02.gif new file mode 100644 index 0000000..a33f7a2 Binary files /dev/null and b/bevezetes/copilot02.gif differ diff --git a/bevezetes/df01.png b/bevezetes/df01.png new file mode 100644 index 0000000..13527be Binary files /dev/null and b/bevezetes/df01.png differ diff --git a/bevezetes/explain_video01.png b/bevezetes/explain_video01.png new file mode 100644 index 0000000..22e2427 Binary files /dev/null and b/bevezetes/explain_video01.png differ diff --git a/bevezetes/f1tenth01.png b/bevezetes/f1tenth01.png new file mode 100644 index 0000000..40b0351 Binary files /dev/null and b/bevezetes/f1tenth01.png differ diff --git a/bevezetes/foxglove01.png b/bevezetes/foxglove01.png new file mode 100644 index 0000000..283e776 Binary files /dev/null and b/bevezetes/foxglove01.png differ diff --git a/bevezetes/foxglove02.png b/bevezetes/foxglove02.png new file mode 100644 index 0000000..a8cf6ae Binary files /dev/null and b/bevezetes/foxglove02.png differ diff --git a/bevezetes/foxglove03.png b/bevezetes/foxglove03.png new file mode 100644 index 0000000..3c44ea9 Binary files /dev/null and b/bevezetes/foxglove03.png differ diff --git a/bevezetes/foxglove04.png b/bevezetes/foxglove04.png new file mode 100644 index 0000000..c970df6 Binary files /dev/null and b/bevezetes/foxglove04.png differ diff --git a/bevezetes/gepterem/index.html b/bevezetes/gepterem/index.html new file mode 100644 index 0000000..1aa445e --- /dev/null +++ b/bevezetes/gepterem/index.html @@ -0,0 +1,2727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gépterem - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Géptermi ismeretek (C100)

+

Közös meghajtó (K:\)

+

A közös meghajtó a K:\ meghajtóként található meg Winodws Fájlkezelőben (File Explorer). Ha esetleg nem látszana, akkor szintén a Fájlkezelőben elérhető:

+
\\fs-kab.eik.sze.hu\C100\kozos
+
+

gepterem01

+

A tantárgyhoz kapcsolódó fájlok pontosan a \\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása címen érhetőek el.

+

WSL és közös meghajtó

+

WSL alól szintén el kellene tudni érni a közös meghajtót mégpedig az /mnt/kozos mount ponton. Teszteljük az elérést a cd /mnt/kozos paranccsal. Ha a -bash: cd: /mnt/kozos: No such file or directory üzenetet kaptuk, akkor hozzuk létre mkdir segítségével. Ha az ls /mnt/kozos nem listáz fájlokat, akkor pedig nincs felmountolva.

+

Ha esetleg nem működne a közös meghajtó, akkor ezek a parancsok segíthetnek:

+

sudo mkdir /mnt/kozos
+echo "\\\\\\\\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása    /mnt/kozos    drvfs defaults,uid=1000,gid=1000    0    0" | sudo tee -a /etc/fstab
+
+Majd wsl --shutdown windows cmd-ből.

+

WSL a Fájlkezelőben

+

Az Ubuntu 22.04 fájljai szintén elérhetőek a Windows Fájlkezelőből. Bal oldlalt lászik egy WSL vagy Linux felirat. A ~ a /home/<gépnév> mappán belül érhető el, így a ros2_ws is.

+

gepterem01

+

VS code

+

VS code WSL elérés

+

vs code WSL

+

VS code hasznos extension-ök

+

vs code extensions

+

Windows terminal

+

A közös meghajtón található egy portable verzió. Ezt a C:\temp-be másolva használható a program.

+

win terminal

+

A következő ábra egy célszerű (nem kötelező) géptermi elrendezést mutat, bal oldalt a terminal, jobb oldalt a böngésző:

+

win layout

+

+

+

Foxglove

+

Telepítve van, az asztalon található ikonnal indítható. Ha mégse lenne telepítve, a közös meghajtón lévő portable verziót kell a C:\temp-be másolni.

+

foxglove

+

Géptermi beállítások gyors ellenőrzése

+
+

Ellenőrzés

+

A következő parancsokat futtasd le a géptermi terminálban: +

cd /mnt/kozos/script/
+./check_all.sh
+

+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/gepterem01.png b/bevezetes/gepterem01.png new file mode 100644 index 0000000..07dfa28 Binary files /dev/null and b/bevezetes/gepterem01.png differ diff --git a/bevezetes/gepterem02.png b/bevezetes/gepterem02.png new file mode 100644 index 0000000..df3732a Binary files /dev/null and b/bevezetes/gepterem02.png differ diff --git a/bevezetes/htop01.png b/bevezetes/htop01.png new file mode 100644 index 0000000..a2681aa Binary files /dev/null and b/bevezetes/htop01.png differ diff --git a/bevezetes/includepath_settings01.png b/bevezetes/includepath_settings01.png new file mode 100644 index 0000000..0101a31 Binary files /dev/null and b/bevezetes/includepath_settings01.png differ diff --git a/bevezetes/includepath_settings02.png b/bevezetes/includepath_settings02.png new file mode 100644 index 0000000..282bbc4 Binary files /dev/null and b/bevezetes/includepath_settings02.png differ diff --git a/bevezetes/index.html b/bevezetes/index.html new file mode 100644 index 0000000..9ff108e --- /dev/null +++ b/bevezetes/index.html @@ -0,0 +1,2678 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Bevezetés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Bevezetés

+

Rendszerszinten az önvezetés a következő alfunkciók összegeként írható le:

+

+Irodalom: [TU München], [Autoware], [University of Texas at Dallas], [ApolloAuto]

+
    +
  1. Érzékelés: egyszerű driver-program szintű nyers adatok előállításával foglakozik, például egy kamera szenzorból a kép előállítása a rendszer számára.
  2. +
  3. Észlelés: ez már összetettebb folyamat, a bemeneti adatokból kinyerni a rendszer számára fontos információkat, például gyalogos felismerése kamerakép alapján.
  4. +
  5. Tervezés: a jármű útját, vagy trajektóriáját tervezi meg globális szinten (a szenzorok érzékelési tartományán túl), illetve lokális szinten (a szenzorok érzékelés tartományán belül).
  6. +
  7. Szabályozás: a tervező által előállított útvonal, vagy tarjektória lekövetése, például Pure-Pursuit szabályzó, Modell Prediktív Szabályzó (Model Predictive Control, MPC) stb. segítségével.
  8. +
  9. Aktuálás: a rendszer által előállított referenciajelek (kormányszög, gáz és fékpedál) kiadása (pl. CAN bus rendszeren).
  10. +
+

A fenti beosztás megfigyelhető nagyobb rendszerek, például az Autoware összefoglaló rendszerábráján is. Robotikában ismeretes még a sense-think-act paradigma is. Itt a gondolkodás (think) foglalja össze az észlelést, a tervezést és valamennyire a szabályozást is.

+

Nézzünk minden részfeladatra egy szemléltetést, az egyetemünk egyik önvezető funkciókkal rendelkező autóján, a zalaegerszegi tesztpályán:

+ + +

Alt text

+

Önvezetés vs. vezetéstámogatás

+

SAE szintek

+

A SAE J3016 szabvány definiálja a sofőr és a jármű rendszere közötti munkamegosztást.

+
    +
  • 0. szint: L0 - No Driving Automation, azaz a vezetésautomatizáció teljes hiánya.
  • +
  • 1. szint: L1 - Driver Assistance, itt bizonyos vezetéstámogató funkciók már beleszólhatnak a jármű mozgásába.
  • +
  • 2. szint: L2 - Partial Driving Automation, azaz mindkét irányba történő manővert végez az autó, a felügyelet az emberé.
  • +
  • 3. szint: L3 - Conditional Driving Automation, itt ha a jármű kéri, a sofőrnek vissza kell vennie az irányítást.
  • +
  • 4. szint: L4 - High Driving Automation, itt már minden felelősség a járművé, de hagyományos üzemmódban is használható még.
  • +
  • 5. szint: L5 - Full Driving Automation, Autonomous, itt is a járműé a feleősség, sőt, nem is lehet hagyományos kormánnyal használni.
  • +
+

A szabvány azonban nem íjra le, hogy milyen "scope" / terület a jármű korlátja. Például egy önvezető reptéri busz nem léphet ki a reptér területéről. Ugyanígy a Waymo, Cruise vagy a Zoox robotaxija jellemzően kisebb régióban, magyar hasonlatként nagyjából 1-2 vármegyényi területen működik csak. Ezt nevezzük "geofencing"-nek is.

+

Példák

+

Ahogy láthattuk, önvezető (autonomous) járművekhez (L5) hasonló technológiák találhatók a vezetéstámogató (automated) szinteken (L2/L3) is. Azonban a feladat komplexitásban teljesen más szintet jelent.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Szint:L2/L3L5
Elnevezés:Automatizált, vezetéstámogatóAutonóm, önvezető
Jellemző szenzorok:Kamera, radarKamera, radar, LIDAR, GPS
Példák:Tesla, Audi, BMWWaymo, Zoox, Cruise
+

Önvezető járművek és robotok

+ + + + + + + + + + + + + + + + + +
RobotokRobotaxik
txtx
Nuro, Segway, Turtlebot, Clearpath, StarshipZoox, Cruise, Waymo, Navya, Sensible4
+

Nézzünk egy példát, ami a Zoox önvezető robotaxit mutaja be működés közben:

+ + +

Kódsorok

+

Az alábbi ábrából látszik, hogy egy mai átlagos (vezetéstámogatással rendelkező) személyautó igen komplex szoftvermérnöki munka eredménye, azonban az is világos, hogy a jövőben az önvezető járművek még ennél is összetettebb megoldásokat fognak igényelni.

+

---
+config:
+    themeVariables:
+        xyChart:
+            backgroundColor: transparent
+            titleColor: "#AAAAAA"
+            xAxisLabelColor: "#43AEC5"
+            yAxisLabelColor: "#43AEC5"
+            xAxisLineColor: "#AAAAAA"
+            yAxisLineColor: "#AAAAAA"
+            plotColorPalette: "#43AEC5"
+---
+xychart-beta
+
+    title "Millions of Lines of code (LOC) in 2024"
+    x-axis ["Avg. iPhone app","World of warcraft", "Linux kernel", Facebook, "Avg. new vehicle"]
+    y-axis "Average number of lines of codes (million)" 0 --> 210
+    bar [0.04, 5.5, 30, 62, 200]
+
+Forrás: statista, informationisbeautiful

+

Egyetemi járművek

+

A Széchenyi István Egyetem szerencsére relatív sok átalakított személygépjárművel, illetve robottal rendelkezik. Ezek a következőek:

+

Lexus RX450h MY2016+ (autó)

+

Szenzorai: Ouster OS2-64 LIDAR, 2x OS1-32 LIDAR, Stereolabs Zed2i mélységkamera. +További információ itt.

+
+ Image title +
Lexus
+
+

Nissan Leaf (autó)

+

Szenzorai: 2x Ouster OS1-64 LIDAR, 2x Velodyne VLP16 LIDAR, SICK LMS111 LIDAR, Stereolabs Zed / Zed2 mélységkamera. +További információ itt.

+
+ Image title +
Nissan Leaf
+
+

Szenergy (autó)

+

Szenzorai: Ouster OS1-128 LIDAR, SICK LMS111 LIDAR, Stereolabs Zed2i mélységkamera. +További információ itt.

+
+ Image title +
Szenergy
+
+

A Szenergy csapata európa legnagyobb önvezető versenyén, a Shell Eco-marathon Autonomous Urban Concept (AUC) versenyen 2023-ban első, előtte pedig második helyezést ért el. A doboogós helyezések ezekben az évek ben így alakultak:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
🏆202220232024
1.DTU Road Runners, Technical University of Denmark (Denmark)SZEnergy Team, Széchenyi István University (Hungary)SZEnergy Team, Széchenyi István University (Hungary)
2.SZEnergy Team, Széchenyi István University (Hungary)Team EVA, Hogeschool Van Amsterdam University (Netherlands)H2politO,Molecole Urbane Politecnico Di Torino University (Italy)
3.DNV Fuel Fighter, Norwegian University of Science And Technology (Norway)H2politO,Molecole Urbane Politecnico Di Torino University (Italy)Team EVA, Hogeschool Van Amsterdam University (Netherlands)
+

Forrás: shellecomarathon.com

+ + +

F1/10 (Ackermann robot) / Roboworks Rosbot mini Ackermann

+

Az F1/10 verseny egy autonóm járművekkel kapcsolatos verseny, ahol a résztvevők 1/10-es méretarányú Formula 1-es autómodelleket építenek és programoznak, hogy azok önállóan navigáljanak egy versenypályán. A cél az, hogy a járművek a lehető leggyorsabban és legbiztonságosabban teljesítsék a pályát, miközben elkerülik az akadályokat és a többi autót. A verseny során a résztvevők tesztelhetik robotikai, mesterséges intelligencia és gépi tanulási ismereteiket. A Roboworks robotja az F1/10 jármű méreéhez és szenzorozottságához nagyon hasonló. F1tenth jármű leírás itt.

+
+ Image title +
+
+ Image title +
+ + +

Segway Loomo (robot)

+

Leírás itt.

+
+ Image title +
+ + + +
+

Husarion ROSbot 2 Pro (robot)

+

Leírás itt.

+
+ Image title +
+ + + +
+

Robotis ROS TurtleBot 3 (robot)

+

Leírás itt.

+
+ Image title +
+ + + +
+

DJI Matrice 600 Pro drone (robot)

+

Szenzorai: Ouster OS1-64 LIDAR. +További információ itt.

+
+ Image title +
+ + + +
+

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/lexus01foxglove.json b/bevezetes/lexus01foxglove.json new file mode 100644 index 0000000..d424555 --- /dev/null +++ b/bevezetes/lexus01foxglove.json @@ -0,0 +1,333 @@ +{ + "configById": { + "SourceInfo!4d7rfhe": {}, + "DiagnosticSummary!msjvo7": { + "minLevel": 0, + "pinnedIds": [], + "hardwareIdFilter": "", + "topicToRender": "/diagnostics", + "sortByLevel": true + }, + "RawMessages!tahvzj": { + "topicPath": "/lexus3/gps/duro/current_pose", + "diffTopicPath": "", + "diffMethod": "custom", + "diffEnabled": false, + "showFullMessageForDiff": false + }, + "RawMessages!3jwh6ii": { + "topicPath": "/gps/nova/imu", + "diffTopicPath": "", + "diffMethod": "custom", + "diffEnabled": false, + "showFullMessageForDiff": false + }, + "Plot!2vgsd7y": { + "paths": [ + { + "value": "/vehicle_speed_kmph.data", + "enabled": true, + "timestampMethod": "receiveTime" + }, + { + "value": "/wheel_angle_deg.data", + "enabled": true, + "timestampMethod": "receiveTime" + } + ], + "minYValue": "", + "maxYValue": "", + "showXAxisLabels": true, + "showYAxisLabels": true, + "showLegend": true, + "legendDisplay": "floating", + "showPlotValuesInLegend": true, + "isSynced": true, + "xAxisVal": "timestamp", + "sidebarDimension": 240, + "title": "Plot" + }, + "Image!1kw2k8": { + "cameraState": { + "distance": 20, + "perspective": true, + "phi": 60, + "target": [ + 0, + 0, + 0 + ], + "targetOffset": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "thetaOffset": 45, + "fovy": 45, + "near": 0.5, + "far": 5000 + }, + "followMode": "follow-pose", + "scene": {}, + "transforms": {}, + "topics": {}, + "layers": {}, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.26179939 + }, + "imageMode": { + "imageTopic": "/lexus3/zed2i/zed_node/left/image_rect_color/compressed", + "synchronize": false, + "rotation": 0, + "annotations": {} + } + }, + "map!253zxmb": { + "disabledTopics": [], + "layer": "map", + "zoomLevel": 17, + "center": { + "lat": 47.69454828124264, + "lon": 17.627745866775516 + }, + "customTileUrl": "", + "followTopic": "", + "topicColors": {}, + "maxNativeZoom": 18 + }, + "3D!36rb111": { + "followTf": "lexus3/os_center_a_laser_data_frame", + "followMode": "follow-position", + "cameraState": { + "perspective": true, + "distance": 33.719421274014195, + "phi": 62.958589079695265, + "thetaOffset": -71.5272082248467, + "targetOffset": [ + -6.736080542800835, + -4.033738387454021, + 1.5020116556647845e-15 + ], + "target": [ + 0, + 0, + 0 + ], + "targetOrientation": [ + 0, + 0, + 0, + 1 + ], + "fovy": 45, + "near": 0.01, + "far": 5000 + }, + "publish": { + "type": "point", + "poseTopic": "/move_base_simple/goal", + "pointTopic": "/clicked_point", + "poseEstimateTopic": "/initialpose", + "poseEstimateXDeviation": 0.5, + "poseEstimateYDeviation": 0.5, + "poseEstimateThetaDeviation": 0.2617993877991494 + }, + "topics": { + "/left_os1/os1_cloud_node/points": { + "visible": true, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 6.300534166098594 + }, + "/right_os1/os1_cloud_node/points": { + "visible": true, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 5.999514229592996 + }, + "/lexus3/os_center/points": { + "visible": true, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 2.04, + "stixelsEnabled": false + }, + "/lexus3/os_left/points": { + "visible": true, + "colorField": "z", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 3.24, + "minValue": -0.0976 + }, + "/lexus3/zed2i/zed_node/left/image_rect_color/compressed": { + "visible": false + }, + "/lexus3/os_right/points": { + "visible": true, + "colorField": "intensity", + "colorMode": "colormap", + "colorMap": "turbo", + "pointSize": 1.87, + "explicitAlpha": 1 + } + }, + "scene": {}, + "transforms": { + "frame:map": { + "visible": true + }, + "frame:lexus3/gps": { + "visible": true + }, + "frame:lexus3/_left_camera_frame": { + "visible": false + }, + "frame:lexus3/duro_gps": { + "visible": false + }, + "frame:lexus3/duro_gps_imu": { + "visible": false + }, + "frame:lexus3/ground_link": { + "visible": false + }, + "frame:lexus3/os_center_a": { + "visible": true + }, + "frame:lexus3/os_center_a_imu_data_frame": { + "visible": false + }, + "frame:lexus3/os_center_a_laser_data_frame": { + "visible": false + }, + "frame:lexus3/os_left_a": { + "visible": false + }, + "frame:lexus3/os_left_a_imu_data_frame": { + "visible": false + }, + "frame:lexus3/os_left_a_laser_data_frame": { + "visible": false + }, + "frame:lexus3/os_right_a": { + "visible": false + }, + "frame:lexus3/os_right_a_imu_data_frame": { + "visible": false + }, + "frame:lexus3/os_right_a_laser_data_frame": { + "visible": false + } + }, + "layers": { + "7f211b70-5aec-4b56-bee3-c8656eae468a": { + "visible": true, + "frameLocked": true, + "label": "Grid", + "instanceId": "7f211b70-5aec-4b56-bee3-c8656eae468a", + "layerId": "foxglove.Grid", + "frameId": "lexus3/ground_link", + "size": 40, + "divisions": 20, + "lineWidth": 1, + "color": "#248eff40", + "position": [ + 0, + 0, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "order": 1 + } + }, + "imageMode": {} + }, + "StateTransitions!2r7jguc": { + "paths": [ + { + "value": "/lexus3/gps/duro/navsatfix.status.status", + "timestampMethod": "receiveTime" + }, + { + "value": "", + "timestampMethod": "receiveTime" + }, + { + "value": "/gps/nova/fix.status.status", + "timestampMethod": "receiveTime" + } + ], + "isSynced": true + }, + "Tab!2jrdgin": { + "activeTabIdx": 3, + "tabs": [ + { + "title": "info", + "layout": { + "first": "SourceInfo!4d7rfhe", + "second": "DiagnosticSummary!msjvo7", + "direction": "row" + } + }, + { + "title": "diagnostics", + "layout": { + "first": "RawMessages!tahvzj", + "second": "RawMessages!3jwh6ii", + "direction": "row" + } + }, + { + "title": "debug", + "layout": "Plot!2vgsd7y" + }, + { + "title": "perception", + "layout": { + "first": { + "first": "Image!1kw2k8", + "second": "map!253zxmb", + "direction": "column" + }, + "second": { + "first": "3D!36rb111", + "second": "StateTransitions!2r7jguc", + "direction": "column", + "splitPercentage": 79.19540609220817 + }, + "direction": "row" + } + } + ] + } + }, + "globalVariables": {}, + "userNodes": {}, + "linkedGlobalVariables": [], + "playbackConfig": { + "speed": 1, + "messageOrder": "receiveTime" + }, + "layout": "Tab!2jrdgin" +} \ No newline at end of file diff --git a/bevezetes/linux/index.html b/bevezetes/linux/index.html new file mode 100644 index 0000000..46c07d0 --- /dev/null +++ b/bevezetes/linux/index.html @@ -0,0 +1,3523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linux és git - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Linux, git

+

A leírásban alapvető Linux ismeretek találhatók.

+

+

Linuxban (ebben a leírásban értsd Ubuntu, Raspbian) a legtöbb munkamenetet lehetséges, vagy épp célszerű terminálból végrehajtani. +Ez a tutorial segít a linux terminál alapjainak megismertetésében.

+
+

Danger

+

Fontos, hogy a megszokott ctrl+v, ctrl+c helyett itt a ctrl+shift+v, ctrl+shift+c működik. A ctr+c(megszakítás billentyűzetről) pl. egy ROS node (program) befejezésére használható itt.

+
+

Ajánlott terminálprogramok

+

Számos program választható a szöveges parancssor elérésére. ROS/ROS2 esetén talán a következők a legjobb választások.

+

Windows Terminal

+

Ahogy a neve is mutatja, ez a megoldás WSL esetén, Windows-on releváns. Előnye, hogy egy helyen használhatunk több Linux disztribúciót akár Windows parancssorral is. Ctrl-Shift-P billentyű kombinációkkal, majd a Split down, Split left parancsokkal oszhatjuk szét hasonló módon a terminált:

+

Alt text

+

A Windows Terminal release oldalon letölthető telepítőként vagy zip formátumban portable verzióban. A portable használathoz kitömörítés után egy üres .portable fájlt kell elhelyeznünk. Így akár USB pendriveon is a megszokott beállításokkal használhatjuk. Egy ilyen portable verzió található a géptermekben a K:\ meghajtón is (\\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása)

+

Terminator

+

Linuxon értelmezett terminál, de telepíteni kell.

+
sudo apt update
+sudo apt install terminator
+
+

Terminator-ban Ctrl-Shift-O, Ctrl-Shift-E billentyű kombinációkkal oszthatjuk tovább az adott ablakot. Ctrl-Shift-W bezárja az aktív ablakot.

+

Alt text

+

VS code terminal

+

A fejlesztőkörnyezet beépített terminálja, mind Windowson, mind Linuxon működik.

+

Alt text

+

+

Fontosabb terminal parancsok

+

Korábbi parancsok

+
    +
  • Fel nyíl🔼 vagy Le nyíl🔽 - A közvetlenül ezelőtti parancsokat érhetjük el így.
  • +
  • Ctrl+R billenytűkombinációval korábbi parancsok hívhatók elő, időrenben egyre korábbiak
  • +
  • Ctrl+Shift+R billenytűkombinációval korábbi parancsok hívhatóak elő, de időrenben előre haladva
  • +
+

A megszokott ctrl+v, ctrl+c helyett itt a ctrl+shift+v, ctrl+shift+c működik. A ctr+c pl. egy ROS node (program) befejezésére használható itt.

+

Alt text

+

Automatikus kiegészítés

+
    +
  • Tab billenytűvel az elkezdett parancsok egészíthetőek ki
  • +
  • Tab Tab billenytűkombinációval az összes lehetséges parancsot fogja kilistázni
  • +
+

+

Képrnyőtörlés

+
    +
  • Ctrl+L billenytűvel törölhetőek a korábbi szövegek, így jobban átlátható lesz a terminal
  • +
+

Könyvtárak közötti navigáció

+
    +
  • cd: adott könyvtárba / mappába történő belépés
  • +
  • pl cd ~/ros2_ws/src, cd ../..
  • +
  • ls: listázás: könyvtárak, fájlok
  • +
  • mkdir: könyvtár készítése
  • +
  • pwd: aktuális munkakönyvtár kiíratása (print working directory)
  • +
  • cp: Ezzel a paranccsal tudunk másolni (cp /file/helye /ahova/másolni/akarod/, cp -r /a/könyvtár/helye /ahova másolni/akarod)
  • +
  • mv: Ezzel adott fájlt vagy könyvtárat tudunk mozgatni (áthelyezni) vagy átnevezni (mv /a/fájl/helye *fájl új neve, mv /a/fájl/helye /a/fájl/új/helye)
  • +
  • rm: Fájlok törlése (rm /a/fájl/helye, rm -r /a/fájlok/és/mappák/helye) Az rm -r parancsnál minden törlődni fog a meghatározott helyen.
  • +
  • rmdir: Egy üres könyvtár törlése
  • +
  • chmod: (change mode) Arra alkalmas, hogy megváltoztassuk a fájlok / mappák hozzáférési jogait. Tehetjük ezt például karakteres kapcsolókkal (r, w, stb.), vagy oktálisan (számjegyekkel).
  • +
  • pl chmod +x my_python_node.py: végrehajtási (execute) jog hozzáadása
  • +
  • pl chmod 777 everything.py: minden jog hozzáadása
  • +
+

chmod

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NSumrwxPermission
74(r)+ 2(w) + 1(x)rwxread, write and execute
64(r)+ 2(w)rw-read and write
54(r)+ 1(x)r-xread and execute
44(r)r--read only
32(w)+ 1(x)-wxwrite and execute
22(w)-w-write only
11(x)--xexecute only
00---none
+

Könyvtárak

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HelyMagyarázat
/A könyvtárfa kiindulópontja, gyökér
/bootRendszerindítás, bootloader
/binA futtatható parancsok, binaries
/sbinA rendszergazda parancsai, superuser/system bin
/libAz induláshoz szükséges osztott rendszerkönyvtárak -libraries- illetve, modulok, meghajtóprogramok
/devEszközök, mint például USB (ttyUSB0) - devices
/etcBeállítófájlok, helyi indító parancsok, jelszavak, hálózati beállítók stb. helye.
/homeItt található minden felhasználó saját könyvtárat. Például ha a sanyi felhasználóval vagyunk belépve, /home/sanyi tartalmazza a fájljainkat. A /home/sanyi/Desktop, vagy röviden ~/Desktop az asztalunk tartalma.
/mntA felcsatolt (mountolt) perifériák, fájlrendszerek helye, mount.
/procProcess information
/rootA root user könyvtára
/tmpTemp
/usrUniversal system resources, alkalmazások, rendszereszközök
/varVáltozó adatok, például nyomtatási munkák, email-ek
+

Verziókezelés

+
    +
  • git clone: git repo klónozása
  • +
  • git config --global user.name "Sanyika": felhsználónév beállítása
  • +
  • git config --global user.email "sanyika@gggmail.com: email beállítása
  • +
  • git init: lokális repó inicializálása
  • +
  • git add <file>: fájl hozzáadása
  • +
  • git status: aktuális státusz lekérdezése
  • +
  • git commit -m "My beautiful commit": commit, üzenettel
  • +
  • git push: push
  • +
  • git pull: pull
  • +
  • git branch <new_branch_name>: branch készítése
  • +
  • git checkout <branch_name>: új branch
  • +
  • git checkout -- .: Minden nem staged (unstaged) változás elvetése lokálisan. VS code-ban kb ez a "discard all changes" parancs. (Újabb git verziókban a git restore . is hasonló módon működik.)
  • +
  • git merge <branch_name>: a jelenlegi branch-be mergeli a branch-t
  • +
+
+

Tip

+

A legtöbb művelet VS code-dal elvégezhető terminál nélkül is. Erről bővebben itt lehet olvasni.

+
+

+

Forrás: link

+

Szöveges fájlok

+
    +
  • wget: webes tartalmak letöltése terminalból
  • +
  • cat: fájl tartalmának kiíratása
  • +
  • touch: szöveges fájl létrehozása
  • +
  • pl. touch hello.txt
  • +
  • echo: kiíratás, vagy fájlba írás (>> operátor). Amennyiben nem létezik a fájl, létrehozza (touch)
  • +
  • pl. echo "hello" >> hello.txt
  • +
  • pl. echo "n = 5; print('\n'.join(':D ' * i for i in range(1, n + 1)))" >> hello.py
  • +
  • pl. ros2 topic list >> hello.txt
  • +
  • pl. ros2 topic echo --once /scan >> hello.txt
  • +
  • find: fájl keresése, pl a find ~/ros2_ws/src/ -name *.txt minden txt fájlt megkeres a ~/ros2_ws/src könyvtárban.
  • +
  • nano: szövegszerkesztő: egyszerű, terminál-alapú
  • +
  • code: szövegszerkesztő: GUI, VS code
  • +
  • pl. code . megnyintja az aktuális mappa tartalmát
  • +
  • pl. code ~/.bashrc megnyintja a ~/.bashrc tartalmát szerkesztésre
  • +
  • colcon: wrapper a cmake és make parancsok egyszerűbb használatához, erről bővebben később
  • +
+

Telepítés

+
    +
  • sudo apt install vagy sudo apt-get install: szoftver csomagkezelővel történő telepítés, Advanced Packaging Tool (APT).
  • +
  • pl. sudo apt install tree mc - tree és mc programok telepítése
  • +
  • sudo: (Superuser do) Lehetővé teszi, hogy rendszergazdaként vagy más felhasználó nevében hajtsunk végre parancsokat.
  • +
  • sudo apt update: csomagindex frissítése, ha új verziók jönnek ki különböző szoftverekből, ezt a paracsot a telepítés (apt install) előtt célszerű kiadni.
  • +
  • sudo apt update: már telepített csomagok frissítése
  • +
  • apt list: listázza asz összes telepített csomagot
  • +
  • pl. apt list | grep ros: leszűri csak az ROS-hez kapcsolódó csomagokat
  • +
+

További hasznos eszközök

+ +
    +
  • Ctrl + a vagy home: A sor elejére dob
  • +
  • Ctrl + e vagy end: A sor végére dob
  • +
  • Ctrl + ◀ / Ctrl + ▶: Az előző / következő szóra ugrik
  • +
+

grep

+
    +
  • grep: (Global \ Regular Expression \ Print) fájlokban illetve parancsok kimenetében keres
  • +
  • pl. grep 'ROS' ~/.bashrc: listázza a bashrc fájlban az ROS szöveget tartalmazó sorokat
  • +
  • pl. ros2 topic list | grep pose: listázza az összes topicot, amiben van pose string
  • +
+

ssh

+
    +
  • ssh: (Secure Shell Protocol) linux gépektbe távoli terminal bejelentkezést tesz lehetővé
  • +
  • pl. ssh nvidia@192.168.1.5: belépés az adott user adott IP címen lévő gépébe
  • +
  • pl. ssh user01@computer4 -X: belépés -X X window használatával, így az esetleges ablakok a mi gépünkön jelennek meg, de a távoli gép hostolja őket
  • +
  • pl. ssh laptop@192.168.0.2 touch hello.txt: létrehoz az adott gépen egy fájlt, nyilván más parancsokkal is működik
  • +
+

Gyakran használt parancsok

+
    +
  • Futó folyamatokról a ps ad tájékoztatást pl: ps -A | grep ros vagy ps -eo pid,cmd | grep ros2
  • +
  • A fájlrendszer állapotáról a df -h (disk filesystem, human readable) parancs ad tájékoztatást +
  • +
+

Az ssh alapvetően jelszót is kér, de ha megbízunk egy adott gépben, elmenthetjük a privát-publikus kulcspárt, és akkor erre nincs szükség, például így.

+

rsync hálózati másolás

+

Hálózatba kötött gépek közötti másolás (remote sync), pl. egy Nvidia Jetson beágyazott számítógépről a saját gépünk /mnt/c/bag/ mappájába történő másolás progress-barral így néz ki:

+

rsync -avzh --progress /mnt/kozos/measurement_files/lexus-2023-07-18-campus.mcap  /mnt/c/temp/
+
+
rsync -avzh --progress nvidia@192.168.1.5:/mnt/storage_1tb/2023-07-02/ /mnt/c/bag/2023-07-02/
+

+

scp hálózati másolás

+

Hálózatba kötött gépek közötti másolás (az rsync alternatívája). A progress-bar sajnos nem minden rendszeren jelenik meg:

+
scp /mnt/kozos/measurement_files/lexus3sample02.mcap  /mnt/c/temp/
+
+

screen

+

Virtuális terminálokat indít, kezel, például: +

screen -m -d -S roscore bash -c roscore
+screen -m -d -S campfly bash -c 'roslaunch drone_bringup campus_fly.launch'
+screen -m -d -S rviz1 bash -c 'rosrun rviz rviz'
+

+
    +
  • list screen: screen -ls
  • +
  • restore screen: screen -r roscore / screen -r campfly / screen -r rviz1
  • +
  • detach: Ctrl-a + Ctrl-d
  • +
  • kill: killall -9 screen and screen -wipe
  • +
+

mc fájlkezelő

+

GNU Midnight Commander (mc), a Norton Commander inspirálta fájlkezelő:

+

+

nmtui

+

Az nmtui (Network Manager Text User Interface) terminal-alapú Wifi / Ethernet / Hálózat konfigurátor.

+

+

nano szövegszerkesztő

+

Terminal alapú szövegszerkesztő. Szerkesztés után Ctrl+X a kilépés, utána Y-t ütve menti a fájlt.

+

+

htop / top

+

Az htop egy interaktív folyamatfigyelő parancs (nagyjából a windows task manager funkcionalitása), amely megjeleníti és felügyeli a futó folyamatokat a rendszeren. Memória- és CPU-használat folymatonként részletezve is kilvasható, továbbá van lehetőség a kill használatára is.

+

+

~/.bashrc fájl

+

A bashrc fájl (a ~ jelentése, hogy user1 felhasználó esetén a /home/user1/ mappában található, a . jelentése pedig, hogy rejtett fájl) minden terminal indtáskor lefutó fájl. Tehát, ha pl egy parancsot írunk bele, ami echo "hello" akkor minden terminal indításkor kiír egy hello üzenetet. Szerkesztése nano/VS code szövegszerkesztőből:

+
nano ~/.bashrc
+code ~/.bashrc
+
+

Számunkra fontos környezeti változók pl: +

export ROS_DOMAIN_ID=4
+export ROS_LOCALHOST_ONLY=1
+export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models
+export TURTLEBOT3_MODEL=waffle
+source /opt/ros/humble/setup.bash
+source ~/ros2_ws/install/setup.bash
+

+

A bashrc fájl módosítása után nem kell új terminált nyitni, ha kiadjuk a következő parancsot:

+
source ~/.bashrc
+
+
ROS 1
+
+

Tip

+

A fejezetben a régi ROS 1-es könyzeteti változókról van szó, az új ROS 2-est a következő fejezet tartalmazza.

+
+

Kiírathatjuk a környezeti változókat (environment variables) echo-val / printenv-vel pl:

+

echo $ROS_MASTER_URI
+printenv ROS_MASTER_URI
+
+http://192.168.1.5:11311
+
+
echo $ROS_IP
+printenv ROS_IP
+
+192.168.1.10
+

+
ROS 2
+
+

ROS 2 fejezet

+

Ez az új, ROS 2-est tartalmazó fejezet.

+
+

Kiírathatjuk a környezeti változókat (environment variables) echo-val / printenv-vel pl:

+

echo $ROS_DISTRO
+printenv ROS_DISTRO
+
+humble
+
+
echo $AMENT_PREFIX_PATH
+printenv AMENT_PREFIX_PATH
+
+/opt/ros/humble
+

+
printenv | grep -i ROS
+
+ROS_VERSION=2
+ROS_PYTHON_VERSION=3
+ROS_DISTRO=humble
+
+
Gazebo és WSL
+

Gazebo szimulátort és WSL-t használva előfordulhat egy issue, ami egy egyszerű környezeti változó beállításával javítható. A ~/.bashrc fájlban a következőt kell beállítani.

+
export LIBGL_ALWAYS_SOFTWARE=1 ### GAZEBO IGNITION 
+
+

Új terminál vagy source után a echo $LIBGL_ALWAYS_SOFTWARE parancsra 1-et fog kiíni.

+

Branch megjelenítése Linux bash-ben

+

Opcionális, de hasznos lehet: Keressük meg és módosítsuk a ~/.bashrc fájlban a következő részt.

+

(VS code használatával a következő parancs: code ~/.bashrc)

+
if [ "$color_prompt" = yes ]; then
+    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
+else
+    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
+fi
+unset color_prompt force_color_prompt
+
+

Miután megvan, cseréljük a következő részre:

+

parse_git_branch() {
+ git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
+}
+if [ "$color_prompt" = yes ]; then
+ PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\]\n\$ '
+else
+ PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(parse_git_branch)\\n$ '
+fi
+
+vagy ugyanez új sorban kezdés nélkül: +
parse_git_branch() {
+ git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
+}
+if [ "$color_prompt" = yes ]; then
+ PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\]\$ '
+else
+ PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(parse_git_branch)\$ '
+fi
+

+

Mentsünk, majd a source ~/.bashrc, illetve minden új terminálnyitás hatására git repository-t tartalmazó könyvtárban a következőhöz hasonló bash fogad majd minket:

+

bashrc

+

Forrás: +Ubuntu magyar dokumentációs projekt CC by-sa 2.5, Óbuda University CC BY-NC-SA 4.0

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/linux_recent01.gif b/bevezetes/linux_recent01.gif new file mode 100644 index 0000000..597aec6 Binary files /dev/null and b/bevezetes/linux_recent01.gif differ diff --git a/bevezetes/mc01.png b/bevezetes/mc01.png new file mode 100644 index 0000000..8b01ecc Binary files /dev/null and b/bevezetes/mc01.png differ diff --git a/bevezetes/nano01.png b/bevezetes/nano01.png new file mode 100644 index 0000000..1a23f95 Binary files /dev/null and b/bevezetes/nano01.png differ diff --git a/bevezetes/practice/index.html b/bevezetes/practice/index.html new file mode 100644 index 0000000..d33c7bd --- /dev/null +++ b/bevezetes/practice/index.html @@ -0,0 +1,2760 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Bevezetés gyakorlat

+

A gyakorlat során meg fogunk ismerkedni az önvezető járművek jellemző tulajdonságaival és a rögzített adatok jellegzetességeivel.

+

Foxglove Studio

+

Bevezetésképpen nézzük egy önvezető jármű jellemző adatait. Példaképp célszerű az egyetemünk egyik ilyen járművével készült adatokat vizsgálni. Foxglove Studio-t fogunk használni, hiszen telepítés nélkül, vagy ~150MB méretű telepíthető állományként is hozzáférhető, valamint képes vizualizálni a számunkra fontos adatokat. A vizsgált adatok hasonló képet fognak mutatni:

+

foxglove_a +foxglove_a

+

Órán a K:\ meghajtóról (\\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása), otthon a zöld gombot használva töltsük le a fent vizualizált rosbag .bag / .mcap fájlt és a Foxglove Studio layout-ot:

+

MCAP letöltése 553 MB +Layout letöltése

+
cd /mnt/c/temp
+mkdir /mnt/c/temp # ha nem létezne
+rsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap /mnt/c/temp/
+rsync -avzh --progress /mnt/kozos/measurement_files/lexus01foxglove.json   /mnt/c/temp/
+
+
+

Tip

+

A https://jkk-research.github.io/dataset oldalról további példa adatokat lehet letölteni.

+
+

A Foxglove bemutatása

+

Amíg az .mcap töltődik, röviden bemutatjuk a Foxglove Studio programot. A Foxglove Studio egy nyílt forráskódú, robotikai adatokat vizualizáló és hibakereső eszköz. Egész pontosan a v1.87.0-ig bezárólag nyílt forráskódu volt, a v2.0.0-tól pedig ingyenesen használható, de zárt forráskódú. Elérhető számos módon:

+
    +
  • önálló asztali alkalmazásként futtatható
  • +
  • böngészőben hozzáférhető
  • +
  • saját domainen, önállóan hostolható
  • +
+

A natív robotikai eszközök (mint például az ROS ökoszisztéma részei) általában csak Linux rendszeren támogatottak, de a Studio asztali alkalmazás Linuxon, Windows-on és macOS-en is működik. Akár az ROS stack más operációs rendszeren fut, a Studio képes kommunikálni a robottal zökkenőmentesen.

+

A Studio gazdag vizuális elemeket és hibakereső panelokat kínál - interaktív diagramoktól, 3D vizuális elemekig, kameraképektől, és diagnosztikai adatfolyamokig. Legyen szó valós idejű robotkövetésről, vagy .bag / .mcap fájlban történő hibakeresésről, ezek a panelok segítenek a különböző, általános robotikai feladatok megoldásában.

+

Ezek a panelok ezután egyedi elrendezésekben konfigurálhatók és összeállíthatók a projekt egyedi igényeinek és munkafolyamatainak megfelelően.

+

Az egytemi Nissan mérésadatainak leírása

+

ROS rendszerben (de más hasonló robotikai megoldásokban is) az egyes adatok topic-okba szerveződve vannak publikálva. Egy topic lehet például egy szenzor kimenete, egy szabályzó bemenete, vizualizációs marker stb. A topicoknak típusuk van, rengeteg előre definiált típus létezik, de létrehozhatunk sajátot is, ha ezek nem lennének elegek. Példaképp pár előre definiált típus:

+ +

Ahogy látszik, a típusok különböző kategóriákba esnek, úgy mint: std_msgs, diagnostic_msgs, geometry_msgs, nav_msgs, sensor_msgs stb. Nézzük, milyen típusú üzenetek találhatók a letöltött fájlban:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicTípusHzSzenzor
/gps/duro/current_posegeometry_msgs/PoseStamped10Duro GPS (UTM)
/gps/duro/imusensor_msgs/Imu200Duro GPS
/gps/duro/magsensor_msgs/MagneticField25Duro GPS
/gps/nova/current_posegeometry_msgs/PoseStamped20Novatel GPS (UTM)
/gps/nova/imusensor_msgs/Imu200Novatel GPS
/left_os1/os1_cloud_node/imusensor_msgs/Imu100Ouster LIDAR
/left_os1/os1_cloud_node/pointssensor_msgs/PointCloud220Ouster LIDAR
/right_os1/os1_cloud_node/imusensor_msgs/Imu100Ouster LIDAR
/right_os1/os1_cloud_node/pointssensor_msgs/PointCloud220Ouster LIDAR
/velodyne_left/velodyne_pointssensor_msgs/PointCloud220Velodyne LIDAR
/velodyne_right/velodyne_pointssensor_msgs/PointCloud220Velodyne LIDAR
/cloudsensor_msgs/PointCloud225SICK LIDAR
/scansensor_msgs/LaserScan25SICK LIDAR
/zed_node/left/camera_infosensor_msgs/CameraInfo30ZED kamera
/zed_node/left/image_rect_color/compressedsensor_msgs/Image20ZED kamera
/vehicle_statusautoware_msgs/VehicleStatus100CAN adatok
/ctrl_cmdautoware_msgs/ControlCommandStamped20Referencia sebesség és kormyánszög
/current_posegeometry_msgs/PoseStamped20Aktuális GPS
/tftf2_msgs/TFMessage500+Transform
+

Házi feladat

+
+

Házi feladat

+

Otthon reprodukáljuk a gyakorlatot, és vizsgáljuk meg a letöltött adatokat a Foxglove Studio segítségével. A vizsgálat során a következő kérdésekre keressük a választ:

+
    +
  • Méterben kifejezve milyen távolságokra találhatóak az objektumok a járműtől?
  • +
  • Milyen sebességgel halad a jármű?
  • +
  • Milyen irányban halad a jármű?
  • +
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/robotaxis01.png b/bevezetes/robotaxis01.png new file mode 100644 index 0000000..5563f9c Binary files /dev/null and b/bevezetes/robotaxis01.png differ diff --git a/bevezetes/robots01.png b/bevezetes/robots01.png new file mode 100644 index 0000000..b6a19e9 Binary files /dev/null and b/bevezetes/robots01.png differ diff --git a/bevezetes/ros2/index.html b/bevezetes/ros2/index.html new file mode 100644 index 0000000..d8d5a32 --- /dev/null +++ b/bevezetes/ros2/index.html @@ -0,0 +1,2896 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - ROS 2 alapfogalmak - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 alapfoglamak

+

ROS verziók és telepítés

+

Az ROS 2, a ROS legújabb kiadása, olyan szoftverkönyvtárak és eszközök készlete (middleware), amelyek segítenek robotalkalmazások fejlesztésében. Definíció szerint a middleware egy szoftver komponenseket összekötő szoftver. Ez egy olyan réteg, amely az operációs rendszer és az alkalmazások között helyezkedik el az elosztott számítógépes hálózat mindkét oldalán. Az ROS 2 megengedő, nyílt forráskódú, Apache 2.0 licenszelést használ.

+
+ Image title +
ROS 2 áttekintés
+
+

A ROS 2007-es kiadása óta inkrementális frissítéseken esett át, tehát fundamentális változások nem, nagyobb fejlesztések viszont folyamatosan történtek. 2017-ben jött rá a robotikai közösség, hogy olyan alapvető limitációi vannak az eredeti 2007-es elképzelésnek, amit ilyen inkrementális módon sajnos nem lehet javítani. Így végül a Noetic Ninjemis (2025-ig támogatva) az ROS 1 utolsó kiadása, helyette párhuzamosan elkezdték fejleszteni az ROS 2-t. Ez egyben azt is jelenteti, hogy a korábbi forráskódokat nehezebben lehet portolni az új verzióra, cserébe rengeteg újdonságot, javítást, támogatást kaphatunk a fejlesztendő robotok, járművek számára.

+

A fentiek hatására tehát az ROS 2 átlépett az akadémiai kutatások világából az ipari fehasználásra. Érdekesség, hogy a NASA VIPER nevű holdjárója is ROS 2-t futtat. Emellett olyan autóipari óriások is használják, mint a Bosch, a BMW vagy a Volvo. Robotikai cégek közül pedig számos további példát lehetne hozni. Linkek: www.nasa.gov/viper/lunar-operations, rosindustrial.org/ric/current-members, www.bosch.com/stories/bringing-robotics-middleware-onto-tiny-microcontrollers. ROS felhasználók a világban: metrorobots.com/rosmap.html.

+

ROS 2 in space

+

Kép forrása: Robot Operating System 2: Design, Architecture, and Uses In The Wild: +Steve Macenski et al.

+

Miért használjak framework-öt robotikai projektemhez?

+

Első robotikai projektünknél választhatjuk azt az utat, hogy framework nélkül teljesen saját megoldásként feljesztünk. Nyilván ennek is vannak előnyei (tanulás, futási gyorsaság, stb.). De hamarosan kelleni fog olyan algoritmus, amit akár mások implementáltak is, csak nem kompatibilis az eredeti elképzeléssel. Itt már célszerű meggondolni egy framework (pl a ROS 2) használatát. Megjegyzés, hogy nem a ROS 2 az egyetlen lehetőség számos hasonló, kisebb framework létezik: Player, YARP, Orocos, CARMEN, Orca, MOOS, and Microsoft Robotics Studio. Niylván mindegyiknek van előnye, ebben a tárgyban a támogatottság miatt mégis az ROS 2-re szoríthozunk.

+

+

Kép forrása: ros.org/blog/ecosystem

+
    +
  • Plumbing: A ROS alapvetően egy üzenetküldő rendszert biztosít, amelyet gyakran "middleware"-nek vagy "plumbing"-nek neveznek. A kommunikáció az egyik első igény, amely felmerül egy új robotikai alkalmazás vagy bármilyen olyan szoftverrendszer implementálásakor, amelyhez hardverrel is csatlakozik. A ROS beépített és jól tesztelt üzenetküldő rendszere időt takaríthat meg, hiszen kezeli a kommunikáció részleteit a decentralizált csomópontok között, ezt nem kell külön implementálni. Sőt lehetőség van egy gépen Intra-process kommunikáció segítségével direkt memória elérésre is.
  • +
  • Eszközök: A hatékony alkalmazások fejlesztéséhez jó fejlesztői eszközökre van szükség. A ROS rendelkezik ilyen az eszközökkel, beleértve: a hibakeresést (rqt_console), a vizualizációt (Rviz2, Foxglove Studio), a diagramokat (rqt_plot, Foxglove Studio), a logolást (mcap) és a visszajátszást.
  • +
  • Képességek: Legyen szó GPS-eszköz-illesztőprogramról, négylábú robothoz való járás- és egyensúlyszabályozóról, vagy mobil robothoz való térképezőrendszerről, a ROS-nak vannak megoldásai a problémára. A driverektől az algoritmusokig, a felhasználói felületekig a ROS biztosítja azokat az építőelemeket, amelyek lehetővé teszik, hogy a saját alkalmazására koncentráljon.
  • +
  • Közösség: A ROS mögött egy nagy, globális és változatos közösség áll. Diákoktól és hobbiból űzőktől kezdve multinacionális vállalatokig és kormányzati ügynökségekig, az emberek és szervezetek minden szegmense működteti az ROS 2 projektet. Ez azért is fontos, mert a fejlesztés során rengeteg kérdés fog felmerülni. Ezek nagy részét már meg is válaszolta aközösség, az új kérdésekre pedig szívesen válaszolnak.
  • +
+

A következő ábra egy egyszerű vonalkövető robot node-jait (programjait) és topic-jait (~kommunkáció) szemléltei:

+
graph TD;
+
+    camd([/cam_driver]):::red --> im1[ /image1<br/>sensor_msgs/Image]:::light
+    im1 --> li1([ /line_detect_node]):::red
+    im1 --> st1([ /stop_detect_node]):::red
+    li1 --> li2[ /line<br/>example_msgs/Line]:::light
+    st1 --> st2[ /stop<br/>example_msgs/Stop]:::light
+    li2 --> nav([ /line_detect_node]):::red
+    st2 --> nav
+    nav --> cmd[ /cmd_vel<br/>geometry_msgs/Twist]:::light
+    cmd --> control([ /robot_control]):::red
+    n1([ /node]):::white -- publishes --> t[ /topic<br/>msg_type]:::white
+    t -- subscribes --> n2([ /node]):::white
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

Forrás: Bestmann, Marc & Fakultät, Min & Zhang, Jianwei & Hendrich, N.. (2017). Towards Using ROS in the RoboCup Humanoid Soccer League. Masterthesis

+

Nézzünk egy másik példát, ami sebességadatokból, IMU-ból, távolságadatokból készít térképeket.

+
graph LR;
+
+    odom[ /odom<br/>nav_msgs/Odometry]:::light --> slam([ /slam_node]):::red
+    speed[ /speed<br/>geometry_msgs/Twist]:::light --> slam
+    imu[ /imu<br/>sensor_msgs/Imu]:::light --> slam
+    scan[ /scan<br/>sensor_msgs/PointCloud2]:::light --> slam
+    n1([ /node]):::white -- publishes --> t[ /topic<br/>msg_type]:::white
+    slam --> pose[ /global_pose<br/>geometry_msgs/Pose]:::light
+    slam --> map_g[ /map_grid<br/>nav_msgs/OccupancyGrid]:::light
+    slam --> map_p[ /map_points<br/>sensor_msgs/PointCloud2]:::light
+    t -- subscribes --> n2([ /node]):::white
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

ROS 2 mappaszerkezet

+
~/ros2_ws$ ls
+
+build  install  log  src
+
+
graph TD;
+
+    W1{{ Workspace</br>pl. ros2_ws }}:::light --> S1{{ Source space</br>src }}:::white
+    W1 --> B1{{ Build space</br>build }}:::white
+    W1 --> I1{{ Install space</br>install }}:::white
+    W1 --> L1{{ Log space</br>log }}:::white
+    S1 --> P1{{ package1 }}:::white
+    S1 --> P2{{ package2 }}:::white
+    S1 --> P3{{ bundle_packages }}:::white
+    P1 --> LA1{{ launch }}:::white
+    P1 --> SR1{{ src }}:::white
+    P2 --> LA2{{ launch }}:::white
+    P2 --> SR2{{ src }}:::white
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
graph TD;
+
+    W2{{ other_ws }}:::light --> S2{{ src }}:::white
+    W2 --> B2{{ build }}:::white
+    W2 --> I2{{ install }}:::white
+    W2 --> L2{{ log }}:::white
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
~/ros2_ws/
+├──build  
+├──install  
+├──log
+└──src/
+    ├── bundle_packages 
+       ├── cone_detection_lidar
+          ├── launch
+          └── src
+       ├── my_vehicle_bringup
+          └── launch
+       ├── other bundle package1
+       ├── other bundle package2
+       └── img
+    └── wayp_plan_tools
+        ├── csv
+        ├── launch
+        └── src
+
+

Különbségek az ROS 1 és ROS 2 között

+
    +
  • Változások a Middleware-ben
    + A ROS 1 a Master-Slave architektúrát és az XML-RPC middleware-t használja. A ROS 2 ezzel szemben a Data Distribution Service (DDS) használ, amely nagyobb hatékonyságot és megbízhatóságot, alacsony késleltetést és skálázhatóságot, valamint konfigurálható szolgáltatásminőségi (QoS) paramétereket biztosít. Többek között így nem kell roscore-t indítani. Az XML-RPC jobb az egyszerű távoli eljáráshívásokhoz, míg a DDS hozzáadott komplexitása lehetővé teszi, hogy jobban támogassa a valós idejű rendszereket.
  • +
  • +

    Változások a ROS API-ban
    + A ROS 1 két különálló könyvtárral rendelkezik: a C++ nyelvhez készült roscpp és a Pythonhoz készült rospy. Ezek nem teljesen azonosak egymással a funkciók tekintetében. Ezzel szemben a ROS 2 egy C nyelven írt alapkönyvtárral - rcl (ROS klienskönyvtár) - rendelkezik, amelyre könyvtárak épülnek. Ez biztosítja, hogy az alapvető funkciók hamarabb elérhetők legyenek a különböző API-kban. Ez az egyik fő oka annak, hogy a ROS 2 a korábbi Pythonon és a C++-on kívül több nyelvi támogatást is képes nyújtani: például rclada Ada, rclcpp C++, rclgo Go, rclpy Python, rcljava Java, rclnodejs Node.js, rclobjc Objective C (iOS), rclc C, ros2_rust Rust, ros2_dotnet .NET, ros2cs ros2_dotnet alternatíva C# nyelven.

    +
  • +
  • +

    Változások az adatformátumban
    + A ROS 2 az MCAP formátumot használja, ami nem dedikáltan az ROS saját formátuma, hanem egy nyílt forráskódú konténerfájl-formátum multimodális log-adatokhoz. Támogatja az időbélyegzővel ellátott, előre sorba rendezett adatokat, és ideális a pub/sub vagy robotikai alkalmazásokban való használatra. Bővebben: mcap.dev

    +
  • +
+

Pár hasznos újítás

+
    +
  • Valós idejű feldolgozás
    + A fenti funkciók összegzése, valamint a DDS használata lehetővé teszi, hogy a ROS 2 kiválóan alkalmas legyen a valós idejű (real time) feldolgozásra, különösen akkor, ha determinisztikus, alacsony késleltetésű kommunikációra van szükség.
  • +
  • QoS: Quality of Service + A ROS 2 lehetővé teszi az adatáramlás konfigurálását, ami befolyásolja az adatok küldésének és fogadásának módját. Ez magában foglalja az üzenetek megbízhatóságára, határidejére és prioritására vonatkozó beállításokat, amelyek biztosíthatják, hogy a kritikus üzenetek időben kézbesítésre kerüljenek.
  • +
  • Többszálú végrehajtás
    + A ROS 2 támogatja a több csomópont valóban párhuzamos futtatását, így a modern többmagos processzorok sokkal jobban kihasználhatók, mint a ROS 1 esetében.
  • +
+

áttekintés +Forrás: husarnet.com/blog/ros2-docker

+

Egyéb változások

+
    +
  • A Catkin eltűnt, helyére az Ament (Colcon) lépett, mint build rendszer. Az overlay-ek lehetővé teszik egy másodlagos munkaterület létrehozását, amely nem befolyásolja az elsődleges munkaterületet - ez akkor hasznos, ha új csomagokkal kell kísérletezni, de úgy, hogy ez ne befolyásolja az alapkonfigurációt (ezt "underlay"-nek hívják).
  • +
  • A ROS 2 visszafelé nem kompatibilis a ROS 1-gyel. Következésképpen a ROS 1 csomagok valószínűleg nem fognak működni a ROS 2-vel, és átdolgozást igényelnének, és más szoftverek, amelyeket a ROS 1-gyel szoktál használni, már nem fognak működni.
  • +
  • A ROS 1 elsősorban az Ubuntu számára készült. A ROS 2 fut MacOS, Windows, Ubuntu és más (akár Real-Time) operációs rendszereken is.
  • +
+

Verziók

+

ROS verziók és telepítés

+

+
+gantt
+    dateFormat  YY-MM
+    title       ROS 2 Distros
+    excludes    weekends
+    tickInterval 365days
+    %% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week ("sunday") or "weekends", but not the word "weekdays".)
+    axisFormat %y
+
+    section ROS 2
+    Jazzy   :active, r012, 2024-05-23, 5y
+    .       :active, r011, 2021-01-01, 0d %% placeholder
+    Iron    :active, r010, 2023-11-01, 188d
+    .       :active, r011, 2021-01-01, 0d %% placeholder
+    Humble  :active, r009, 2022-05-23, 5y
+    .       :active, r011, 2021-01-01, 0d %% placeholder
+    Galactic:active, r008, 2021-05-23, 1y
+

Alt text

+

Distrok százalékos megoszlása az időben: metrics.ros.org/rosdistro_rosdistro.html

+

Static Badge

+

A Humble Hawksbill vagy röviden Humble egy long term support (LTS) release, 5 évig támogatott (2022 májusától 2027 májusáig)

+

További release-ek: docs.ros.org/en/humble/Releases.html

+

+ +

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/ros2distros.svg b/bevezetes/ros2distros.svg new file mode 100644 index 0000000..2cf7a1c --- /dev/null +++ b/bevezetes/ros2distros.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bevezetes/ros2gyak/index.html b/bevezetes/ros2gyak/index.html new file mode 100644 index 0000000..6b34626 --- /dev/null +++ b/bevezetes/ros2gyak/index.html @@ -0,0 +1,3441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - ROS 2 alapok - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 bevezetés és gyakorlat

+

Emlékeztető

+

Pár alapfogalom az előző alkalomról:

+
    +
  • Node: Gyakorlatilag ROS programot jelent. (pl. turtlesim_node, cmd_gen_node, foxglove_bridge)
  • +
  • Topic (topik): Nevekkel ellátott kommunikációs csatorna. (pl. /turtle1/cmd_vel, /turtle1/pose, /raw_cmd)
  • +
  • Message (üzenet): (pl. std_msgs/msg/Bool, geometry_msgs/msg/Twist, turtlesim/msg/Pose)
  • +
  • Package (csomag): ROS programok (node-ok) gyűjteménye (pl. turtlesim, arj_intro_cpp, arj_transforms_cpp)
  • +
  • Launch fájlok: Több node paraméterezett elindítására alkalmas (pl. multisim.launch.py, foxglove_bridge.launch.xml, foxglove_bridge.launch.py)
  • +
  • Publish / subscribe: Üzenetekre történő publikálás és feliratkozás.
  • +
  • Build: A package forráskódjából futtatható állományok készítésének folyamata. ROS2-ben a colcon az alapértelmezett build eszköz.
  • +
+

1. feladat - Node és publish

+

Nyissunk két terminált. Az első terminálból indítsuk a beépített turtlesim_node szimulátort, ami a turtlesim package-ben található.

+
ros2 run turtlesim turtlesim_node
+
+

Megjegyzés: ha esetleg valamiért hiányozna, telepíthető a sudo apt install ros-humble-turtlesim paranccsal.

+

A második ablakból publikáljunk egy parancsot, melynek hatására körbe fordul:

+
ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist '{linear: {x: 0.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.2}}'
+
+
+ +
Turtlesim animáció
+
+

A háttérben a turtlesim_node node (kerek jelölés) feliratkozik a /turtle1/cmd_vel topicra (szögletes jelölés), ennek hatására indul a mozgás.

+
flowchart LR
+
+C[ /turtle1/cmd_vel]:::light -->|geometry_msgs/msg/Twist| S([turtlesim_node]):::red
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Ahogy a flowcharton is látszik, a /turtle1/cmd_vel típusa geometry_msgs/msg/Twist. Ezt a következő parancsból tudhatjuk meg:

+
ros2 topic type /turtle1/cmd_vel
+
+

A geometry_msgs/msg/Twist a üzenet strutúráját pedig ez a parancs adja:

+
ros2 interface show geometry_msgs/msg/Twist
+
+

Vector3  linear
+        float64 x
+        float64 y
+        float64 z
+Vector3  angular
+        float64 x
+        float64 y
+        float64 z
+
+Az összes topic-ot így lehet listázni:

+
ros2 topic list
+
+

Az adott topic tartalmát, különböző formátumban, szűrésekkel a következőképp lehet kiíratni vagy fájlba iratni:

+
ros2 topic echo /turtle1/pose
+ros2 topic echo /turtle1/pose --csv
+ros2 topic echo /turtle1/pose --csv > turtle_data_01.csv
+ros2 topic echo /turtle1/pose --once
+ros2 topic echo /turtle1/pose --once | grep velocity
+ros2 topic echo /turtle1/pose --field x
+ros2 topic echo /turtle1/pose --field linear_velocity
+ros2 topic echo /turtle1/cmd_vel --field linear.x
+
+

Példa kimenet: +

x: 6.2
+y: 4.0
+theta: 0.0
+linear_velocity: 0.0
+angular_velocity: 0.0
+

+
+

Tip

+

A ros2 topic echo --help parancsot kiadva további használatra vonatkozó leírást kapunk. A --help kapcsoló természetesen a többi ros2 parancsnál is használható.

+
+

Workspace és build tudnivalók

+

Első lépésként az ls ~ | grep ros2 parancs segítségével ellenőrizzük, hogy létezik-e a workspace a home directoryban(~). A tantárgyban a workspace-t ros2_ws-nek nevezzük. A név igazából nem számít, de a legtöbb tutorial is ezt a nevet használja, így mi is követjük ezt a hagyományt. Több workspace is használható egyidejüleg, külön source-olható, nagyobb rendszereknél ez kényelmes megoldás lehet. Mi egyelőre maradunk az egytelen ros2_ws-nél. Ha nem létezne a mkdir -p ros2_ws/src parancs segítségével készíthetjük el a workspace és a source mappákat.

+

Colcon

+

A legfontosabb parancs talán a colcon build. Említésre méltó még a colcon list és a colcon graph. Előbbi listázza az elérhető packageket, utóbbi pedig a függőségekről ad gyors nézetet.

+

A colcon build számos hasznos kapcsolóval érkezik:

+
    +
  • --packages-select: Talán az egyik leggyakrabban használt kapcsoló, utána meggadhatunk több package-t, amit buildelni szeretnénk. Ha nincs megadva, akkor az alapértelmezett, hogy a teljes workspace-t buildeli. A gyakorlatban lesz is egy colcon build --packages-select arj_intro_cpp arj_transforms_cpp parancs, ez a két arj package-t buildeli.
  • +
  • --symlink-install: A fájlok forrásból való másolása helyett használjon szimbolikus hivatkozásokat. Így elkerülhető, hogy pl. minden egyes launch fájl módosítás esetén újra kelljen buildelni a package-t.
  • +
  • --parallel-workers 2: A párhuzamosan feldolgozható feladatok maximális száma, ebben az esetben 2. Ha nincs megadva, akkor az alapértelmezett érték a logikai CPU magok száma. Akkor érdemes korlátozni, ha a build nem fut végig erőforrás hiány miatt.
  • +
  • --continue-on-error: Nagyobb build esetén, ne álljon meg az első hibás package után. Így ha 100 packageből 1 nem működne, akkor is 99 buildelődik. Ha ez nincs megadva, akkor 0 és 99 közötti package buildelődik, a függőségek és egyéb sorrendiségek alapján.
  • +
+

Source

+

Ahhoz hogy az ROS2 futtatható fájlainkat valóban el tudjuk indítani, be kell állíani a be a környezetet (úgynevezett source-olás), tehát meg kell adni a bash számára, hogy hol keresse az adott futtatható fájlokat, azoknak milyen függőségei vannak stb. Ez egyszerűbb, mint hangzik, csak egy source <útvonal>/<név>.bash parancsot kell kiadni. Korábban írtuk, hogy a worksapce neve nem számít, és valóban, a source megadása után mindegy, hogy fizikailag hol található a futtatható állomány, kényelmesen elindítható egy paranccsal bármelyik mappából. +Mivel a packagek különböző workspace-eken belül egymásra is épülhetnek, az ROS2 bevezette az overlay / underlay elvet. Ez azt jelenti, hogy egyik workspace buildelésekor egy másik workspace már be volt source-olva, annak valamely package-e függ a az előzőleg lebuildelt package-től. Tehát annak funkcionalitása, kódja szükséges a ráépülő package-nek. Ennek megfeleően a source-olás is kétféle lehet: +- A local_setup.bash script csak a jelenlegi workspace-ben állítja be a környezetet (source-ol). Tehát nem source-ol szülő (függő) workspace-t. +- A setup.bash szkript viszont a local_setup.bash parancsfájlt adja az összes olyan workspace-hez, amely a munkaterület létrehozásakor függőség volt.

+
+

Note

+

A tantárgyban nem kell ilyen összetett rendszereket használni, legtöbbször egy ros2_ws is elég.

+
+

2. feladat - Package build és használat

+
+ Emlékeztetőül a mapparendszer. + + +
~/ros2_ws/
+├──build  
+├──install  
+├──log
+└──src/
+    ├── bundle_packages 
+       ├── cone_detection_lidar
+          ├── launch
+          └── src
+       ├── my_vehicle_bringup
+          └── launch
+       ├── other bundle package1
+       ├── other bundle package2
+       └── img
+    └── wayp_plan_tools
+        ├── csv
+        ├── launch
+        └── src
+
+
+ +

docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html

+

Nyissunk négy terminált. Az első terminálból most is indítsuk a beépített turtlesim_node szimulátort, ami a turtlesim package-ben található.

+
ros2 run turtlesim turtlesim_node
+
+
+

Success

+

A második terminálban ellenőrizzük a ros2_ws/src tartalmát, és ha szükséges klónozzuk, majd buildeljük a példa package-t.

+
+

ls ~/ros2_ws/src | grep arj_
+
+vagy

+
cd ~ && test -d "ros2_ws/src/arj_packages" && echo Letezik || echo Nem letezik
+
+
    +
  • A. opció: Ha nincs package (az előző ls nem ad vissza találatot), akkor git clone és colcon build.
  • +
  • B. opció: Ha van package, de nem a legfrissebb, akkor git pull és colcon build.
  • +
  • C. opció: Ha van package és friss is, akkor nincs külön teendőnk.
  • +
+

A. opció: +

cd ~/ros2_ws/src
+
+
git clone https://github.com/sze-info/arj_packages
+
+
cd ~/ros2_ws
+
+
colcon build --packages-select arj_intro_cpp
+

+

B. opció: +

cd ~/ros2_ws/src/arj_packages
+
+
git checkout -- .
+
+
git pull
+
+
cd ~/ros2_ws
+

+
colcon build --packages-select arj_intro_cpp
+
+

A git checkout -- . az összes esetleges lokális változás visszavonására jó.

+

A harmadik terminálban futtassuk a cmd_gen_node ROS node-ot.

+

Először source-olnunk kell, ha saját package-ket használunk:

+
source ~/ros2_ws/install/setup.bash
+
+

Ezután már futtatható a node:

+
ros2 run arj_intro_cpp cmd_gen_node
+
+

A következőképp mozog most a teknős:

+
+ Image title +
Turtle
+
+

Forráskódja elérhető a github.com/sze-info/arj_packages repon.A lényeg, hogy a loop függvény 5 Hz (200 ms) frekvencián fut le, és

+
void loop()
+{
+  // Publish transforms
+  auto cmd_msg = geometry_msgs::msg::Twist();
+  if (loop_count_ < 20)
+  {
+    cmd_msg.linear.x = 1.0;
+    cmd_msg.angular.z = 0.0;
+  }
+  else
+  {
+    cmd_msg.linear.x = -1.0;
+    cmd_msg.angular.z = 1.0;
+  }
+  cmd_pub_->publish(cmd_msg);
+  loop_count_++;
+  if (loop_count_ > 40)
+  {
+    loop_count_ = 0;
+  }
+}
+
+
+

Python megfelelője

+

A C++ kód python verziója szintén elérhető a github.com/sze-info/arj_packages címen. Érdemes összehasonlítani a C++ és a python kódokat.

+
+

Nézzük meg az utolsó terminálban a Foxglove segítségével az élő adatokat (itt se felejtsük a source-t):

+
ros2 launch arj_intro_cpp foxglove_bridge.launch.py
+
+

Vizsgáljuk meg Foxglove Studio-val is WebSocketen keresztül (Open connection ws://localhost:8765):

+

foxglove

+

Megjegyzés: gépteremben fel van téve a foxglove_bridge, otthon sudo apt install ros-humble-foxglove-bridge paranccsal (előtte update) telepíthető.

+

flowchart LR
+
+C[ /turtle1/cmd_vel]:::light --> S([turtlesim_node]):::red
+C[ /turtle1/cmd_vel] --> F([foxglove_bridge]):::red
+G([cmd_gen_node]):::red--> C
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+Mindehárom node-ot egyben a következőképp indíthatjuk:

+
ros2 launch arj_intro_cpp turtle.launch.py
+
+

Vizsgáljuk meg a package tartalmát röviden a code ~/ros2_ws/src/arj_packages/arj_intro_cpp parancs után.

+

3. feladat - Saját package készítése

+

A feladat a hivatalos ROS2 dokumentáción alapul: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html. Készítsük el a my_package nevű ROS 2 package-t.

+
+

Python megfelelője

+

Jelenleg C++ package-t készítünk, de az eredeti tutorial is taralmazza a CMake(c++) package Python megfelelőit.

+
+

Első lépés, hogy a a workspace src mappájába lépjünk:

+
cd ~/ros2_ws/src
+
+

Készítsünk egy my_package nevű package-t és egy my_node nevű node-ot.

+
ros2 pkg create --build-type ament_cmake --node-name my_node my_package
+
+

Buildeljük a szokásos módon:

+

cd ~/ros2_ws
+
+
colcon build --packages-select my_package
+

+

Majd source:

+
source ~/ros2_ws/install/setup.bash
+
+

És már futtatható is:

+

ros2 run my_package my_node
+
+
# output:
+
+hello world my_package package
+

+

Vizsgáljuk meg a my_package tartalmát!

+

ls -R ~/ros2_ws/src/my_package
+
+
# output:
+/home/he/ros2_ws/src/my_package:
+  CMakeLists.txt  include  package.xml  src
+/home/he/ros2_ws/src/my_package/include:
+  my_package
+/home/he/ros2_ws/src/my_package/include/my_package:
+  [empty]
+/home/he/ros2_ws/src/my_package/src:
+  my_node.cpp
+

+

tree ~/ros2_ws/src/my_package
+
+
# output:
+my_package
+├── CMakeLists.txt
+├── include
+   └── my_package
+├── package.xml
+└── src
+    └── my_node.cpp
+

+

cat ~/ros2_ws/src/my_package/src/my_node.cpp
+
+
#include <cstdio>
+
+int main(int argc, char ** argv)
+{
+  (void) argc;
+  (void) argv;
+
+  printf("hello world my_package package\n");
+  return 0;
+}
+
+Érdemes megfigyelni, hogy a cpp fájl még semmilyen ros2 headert nem használ.

+

Futtatása:

+

source ~/ros2_ws/install/setup.bash
+
+
ros2 run my_package my_node
+

+

Alternatívaként VS code-ból is megnyinthatjuk a teljes mappát. +

code ~/ros2_ws/src/my_package
+

+
+

Tip

+

A code parancs után fájlt megadva a fájl niytódik meg, míg mappát (könyvtárat) megadva az adott mappa tartalma nyílik meg. Gyakran forul elő, hogy például egy adott package-ben vagyunk és szeretnénk az aktuális mappát megnyitni. Ezt megtehetjük a code . paranccsal, amikoris az aktuális mappa nyitódik meg, hiszen a . karakter az aktuális mappát jelenti linuxban.

+
+

4. feladat - C++ publisher / subscriber

+
+

Házi feladat

+

Otthon készítsük el a cpp_pubsub / py_pubsub package-t, ami egy egyszerű publish/subscribe példát valósít meg.

+
+

A gyakorlat a hivatalos ROS 2 tutorialokon alapszik: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html

+ +

Hozzuk létre a cpp_pubsub package-t

+

Nyissunk egy új terminált, és source-oljunk a telepítést, hogy a ros2 parancsok működjenek.

+

Navigáljunk az már létrehozott ros2_ws könyvtárba.

+

Fontos, hogy a csomagokat az src' könyvtárban kell létrehozni, nem a munkaterület gyökerében. Tehát navigáljunk aros2_ws/src` fájlba, és futtassuk a package létrehozó parancsot:

+
ros2 pkg create --build-type ament_cmake cpp_pubsub
+
+

A terminál egy üzenetet küld vissza, amely megerősíti a cpp_pubsub csomag és az összes szükséges fájl és mappa létrehozását.

+

Írjuk meg a publisher node-ot

+

Lépjünk a ros2_ws/src/cpp_pubsub/src mappába. +Ez az a könyvtár minden CMake package-ben, ahová a forrásfájlok tartoznak (pl .cpp kiterjesztéssel).

+

Töltsük le a példa talker kódját:

+
wget -O publisher_member_function.cpp https://raw.githubusercontent.com/ros2/examples/humble/rclcpp/topics/minimal_publisher/member_function.cpp
+
+

Ez a parancs létrehozza a publisher_member_function.cpp fájlt. Nyissuk meg pl VS code segítségével a mappát (code .)

+
#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+
+#include "rclcpp/rclcpp.hpp"
+#include "std_msgs/msg/string.hpp"
+
+using namespace std::chrono_literals;
+
+/* This example creates a subclass of Node and uses std::bind() to register a
+* member function as a callback from the timer. */
+
+class MinimalPublisher : public rclcpp::Node
+{
+    public:
+    MinimalPublisher()
+    : Node("minimal_publisher"), count_(0)
+    {
+        publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
+        timer_ = this->create_wall_timer(
+        500ms, std::bind(&MinimalPublisher::timer_callback, this));
+    }
+
+    private:
+    void timer_callback()
+    {
+        auto message = std_msgs::msg::String();
+        message.data = "Hello, world! " + std::to_string(count_++);
+        RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
+        publisher_->publish(message);
+    }
+    rclcpp::TimerBase::SharedPtr timer_;
+    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
+    size_t count_;
+};
+
+int main(int argc, char * argv[])
+{
+    rclcpp::init(argc, argv);
+    rclcpp::spin(std::make_shared<MinimalPublisher>());
+    rclcpp::shutdown();
+    return 0;
+}
+
+

Függőségek hozzáadása

+

Lépjünk vissza egy szinttel a ros2_ws/src/cpp_pubsub könyvtárba, ahol a CMakeLists.txt és a package.xml fájlok már létrejöttek.

+

Nyissuk meg a package.xml fájlt a szövegszerkesztővel (pl. vs code). Tipp: a teljes könyvtárat is meg lehet, nyitni, ami később pár dolgot egyszerűsít:

+
code ~/ros2_ws/src/cpp_pubsub/
+
+

Mindig érdemes kitölteni a <description>, <maintainer> és <license> tag-eket:

+
<description>Examples of minimal publisher/subscriber using rclcpp</description>
+<maintainer email="you@email.com">Your Name</maintainer>
+<license>Apache License 2.0</license>
+
+

Adjunk hozzá egy új sort az ament_cmake buildtool függősége után, és illessze be a következő függőségeket a node include utasításainak megfelelően:

+
<depend>rclcpp</depend>
+<depend>std_msgs</depend>
+
+

Ez deklarálja, hogy a pacakge-nek szükséges az rclcpp és a std_msgs fordításkor és futtatáskor.

+

CMakeLists.txt

+

Most nyissuk meg a CMakeLists.txt fájlt. +A meglévő find_package(ament_cmake REQUIRED) függőség alá adjuk hozzá a következő sorokat:

+
find_package(rclcpp REQUIRED)
+find_package(std_msgs REQUIRED)
+
+

Ezután adjuk hozzá a végrehajtható fájlt, és nevezzük el talker-nak, hogy a ros2 run használatával futtassa a node-ot:

+
add_executable(talker src/publisher_member_function.cpp)
+ament_target_dependencies(talker rclcpp std_msgs)
+
+

Végül az install(TARGETS...) részt adjuk hozzá, hogy az ros 2 megtalálja a futtatható állományt, amit lefordítottunk

+
install(TARGETS
+talker
+DESTINATION lib/${PROJECT_NAME})
+
+

A CMakeLists.txt megtisztítható néhány felesleges szakasz és megjegyzés eltávolításával, így a következőképpen néz ki:

+
cmake_minimum_required(VERSION 3.5)
+project(cpp_pubsub)
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+set(CMAKE_CXX_STANDARD 14)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+find_package(std_msgs REQUIRED)
+
+add_executable(talker src/publisher_member_function.cpp)
+ament_target_dependencies(talker rclcpp std_msgs)
+
+install(TARGETS
+talker
+DESTINATION lib/${PROJECT_NAME})
+
+ament_package()
+
+

Már buildelhető a package, adjuk hozzá a feliratkozó (subscriber) node-ot is, hogy láthassuk a teljes rendszert működés közben.

+

cd ~/ros2_ws/
+
+
colcon build --packages-select cpp_pubsub
+

+

Írjuk meg a subscriber node-ot

+

A subscriber node elkészítését a következő tutorial 3-a pontja is leírja: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html

+

Lépjünk vissza a ros2_ws/src/cpp_pubsub/src mappába és töltsük le a sunbscriber node-ot is:

+
wget -O subscriber_member_function.cpp https://raw.githubusercontent.com/ros2/examples/humble/rclcpp/topics/minimal_subscriber/member_function.cpp
+
+

Ha most ls-el listázunk, a következőt kell lássuk:

+
publisher_member_function.cpp  subscriber_member_function.cpp
+
+

A CMakeList.txt-hez adjuk hozzá a subscribe node-ot is:

+
add_executable(listener src/subscriber_member_function.cpp)
+ament_target_dependencies(listener rclcpp std_msgs)
+
+install(TARGETS
+  talker
+  listener
+  DESTINATION lib/${PROJECT_NAME})
+
+

Fordítsuk a package-t

+

cd ~/ros2_ws/
+
+
colcon build --packages-select cpp_pubsub
+

+

Futtatás:

+

source ~/ros2_ws/install/setup.bash
+
+
ros2 run cpp_pubsub talker
+

+
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
+[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
+[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
+[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
+[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
+
+

Egy újabb terminalba: +

source ~/ros2_ws/install/setup.bash
+
+
ros2 run cpp_pubsub listener
+

+
[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
+[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
+[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
+[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
+[INFO] [minimal_subscriber]: I heard: "Hello World: 14"
+
+

5. feladat - Python publisher / subscriber

+

A gyakorlat a hivatalos ROS 2 tutorialokon alapszik: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
import rclpy      ## ROS2 Python API 
+from std_msgs.msg import String ## ROS2 Standard String
+from rclpy.node import Node 
+
+
+
+
+## MinimalPublisher osztály
+class MinimalPublisher(Node):
+
+    def __init__(self):
+        super().__init__('minimal_publisher')
+        self.publisher_ = self.create_publisher(String, 'topic', 10)
+        timer_period = 0.5  # seconds
+        self.timer = self.create_timer(timer_period, self.timer_callback)
+        self.i = 0
+
+    def timer_callback(self):
+        msg = String()
+        msg.data = 'Hello World: %d' % self.i
+        self.publisher_.publish(msg)
+        self.get_logger().info('Publishing: "%s"' % msg.data)
+        self.i += 1
+
+
+
+
+
+def main(args=None):
+    rclpy.init(args=args)
+    minimal_publisher = MinimalPublisher()
+    rclpy.spin(minimal_publisher)
+    minimal_publisher.destroy_node()
+    rclpy.shutdown()
+
+
+if __name__ == '__main__':
+    main()
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
#include "rclcpp/rclcpp.hpp" // ROS2 C++ API 
+#include "std_msgs/msg/string.hpp" // ROS2 standard String
+#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+using namespace std::chrono_literals;
+// MinimalPublisher osztály
+class MinimalPublisher : public rclcpp::Node
+{
+    public: MinimalPublisher() : Node("minimal_publisher"), count_(0) {
+        publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
+        timer_ = this->create_wall_timer(
+        500ms, std::bind(&MinimalPublisher::timer_callback, this));
+    }
+
+    private:
+    void timer_callback(){
+        auto message = std_msgs::msg::String();
+        message.data = "Hello, world! " + std::to_string(count_++);
+        RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
+        publisher_->publish(message);
+    }
+    rclcpp::TimerBase::SharedPtr timer_;
+    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
+    size_t count_;
+};
+
+int main(int argc, char * argv[]){
+    rclcpp::init(argc, argv);
+    rclcpp::spin(std::make_shared<MinimalPublisher>());
+    rclcpp::shutdown();
+    return 0;
+}
+
+
+
+
+ +

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/ros2space01.png b/bevezetes/ros2space01.png new file mode 100644 index 0000000..b8a95f7 Binary files /dev/null and b/bevezetes/ros2space01.png differ diff --git a/bevezetes/ros_overview01.svg b/bevezetes/ros_overview01.svg new file mode 100644 index 0000000..586ddf3 --- /dev/null +++ b/bevezetes/ros_overview01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bevezetes/ros_overview02.svg b/bevezetes/ros_overview02.svg new file mode 100644 index 0000000..3f4f58e --- /dev/null +++ b/bevezetes/ros_overview02.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bevezetes/ros_overview03.svg b/bevezetes/ros_overview03.svg new file mode 100644 index 0000000..ca4ca5a --- /dev/null +++ b/bevezetes/ros_overview03.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bevezetes/terminator01.png b/bevezetes/terminator01.png new file mode 100644 index 0000000..8672e44 Binary files /dev/null and b/bevezetes/terminator01.png differ diff --git a/bevezetes/turtlesim01.gif b/bevezetes/turtlesim01.gif new file mode 100644 index 0000000..1e4b014 Binary files /dev/null and b/bevezetes/turtlesim01.gif differ diff --git a/bevezetes/turtlesim02.gif b/bevezetes/turtlesim02.gif new file mode 100644 index 0000000..4de53f7 Binary files /dev/null and b/bevezetes/turtlesim02.gif differ diff --git a/bevezetes/vehcile_dji01.png b/bevezetes/vehcile_dji01.png new file mode 100644 index 0000000..631a18d Binary files /dev/null and b/bevezetes/vehcile_dji01.png differ diff --git a/bevezetes/vehcile_husarion01.png b/bevezetes/vehcile_husarion01.png new file mode 100644 index 0000000..b874eda Binary files /dev/null and b/bevezetes/vehcile_husarion01.png differ diff --git a/bevezetes/vehcile_leaf01.png b/bevezetes/vehcile_leaf01.png new file mode 100644 index 0000000..ae4a62d Binary files /dev/null and b/bevezetes/vehcile_leaf01.png differ diff --git a/bevezetes/vehcile_lexus01.png b/bevezetes/vehcile_lexus01.png new file mode 100644 index 0000000..9fed594 Binary files /dev/null and b/bevezetes/vehcile_lexus01.png differ diff --git a/bevezetes/vehcile_rosbot01.png b/bevezetes/vehcile_rosbot01.png new file mode 100644 index 0000000..bcdb47f Binary files /dev/null and b/bevezetes/vehcile_rosbot01.png differ diff --git a/bevezetes/vehcile_segway01.png b/bevezetes/vehcile_segway01.png new file mode 100644 index 0000000..f22b15c Binary files /dev/null and b/bevezetes/vehcile_segway01.png differ diff --git a/bevezetes/vehcile_turtlebot01.png b/bevezetes/vehcile_turtlebot01.png new file mode 100644 index 0000000..a6b5cef Binary files /dev/null and b/bevezetes/vehcile_turtlebot01.png differ diff --git a/bevezetes/vehicle_szenergy01.png b/bevezetes/vehicle_szenergy01.png new file mode 100644 index 0000000..42c91c5 Binary files /dev/null and b/bevezetes/vehicle_szenergy01.png differ diff --git a/bevezetes/vscodebasics01.png b/bevezetes/vscodebasics01.png new file mode 100644 index 0000000..7fafcc5 Binary files /dev/null and b/bevezetes/vscodebasics01.png differ diff --git a/bevezetes/vscodebasics02.png b/bevezetes/vscodebasics02.png new file mode 100644 index 0000000..84b5afe Binary files /dev/null and b/bevezetes/vscodebasics02.png differ diff --git a/bevezetes/vscodebasics03.png b/bevezetes/vscodebasics03.png new file mode 100644 index 0000000..0c1051c Binary files /dev/null and b/bevezetes/vscodebasics03.png differ diff --git a/bevezetes/vscodebasics04.png b/bevezetes/vscodebasics04.png new file mode 100644 index 0000000..9dadbc6 Binary files /dev/null and b/bevezetes/vscodebasics04.png differ diff --git a/bevezetes/vscodegit/index.html b/bevezetes/vscodegit/index.html new file mode 100644 index 0000000..d48559a --- /dev/null +++ b/bevezetes/vscodegit/index.html @@ -0,0 +1,2800 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VS code, git - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

VS code és Git

+

A VS code Linux, Windows és Mac rendszerekre készült egyszerű kód és szövegszerkezstő, amely különböző kiegészítésekkel egy teljes értékű IDE (integrált fejlesztőkörnyezet) lehet. Neve a Visual Studio Code rövidítése, ingyenes, nyílt forráskódú, a Microsoft fejleszti. +Népszerű fejlesztőkörnyezet (pl. 2021-ben a Stack Overflow Developer Survey alapján 82000 válaszadóból 70% használta, így az egyik legnépszerűbb IDE).

+ +

A következőkben a fontosabb feleületeket mutatjuk be.

+

vs code alapok

+

Talán az egyik legfontosabb billentyűkombináció a Ctrl-Shift-P, mellyel a Command Palette jön elő, ahol beállítások, fájlok, parancsok között böngészhetünk.

+

Source control (forráskezelés) áttetintése

+

A forráskezelő szoftvereket, mint például a Git, a következő okok miatt használjuk a modern szoftverfejlesztésben:

+
    +
  • Változáskövetés: Lehetővé teszik a forráskód minden módosításának nyomon követését, így könnyen vissza lehet térni korábbi verziókhoz, ha hibát fedeznek fel, vagy ha egy új funkció nem működik megfelelően.
  • +
  • Együttműködés: Több fejlesztő egyidejűleg dolgozhat ugyanazon a projekten. A forráskezelő szoftverek segítenek kezelni a különböző változtatásokat és megoldani az esetleges ütközéseket.
  • +
  • Biztonsági mentés: A projekt minden verzióját tárolja, így ha valami elromlik vagy elveszik, könnyen vissza lehet állítani az előző állapotot.
  • +
  • "Kísérletezés": Lehetővé teszi a fejlesztők számára, hogy különböző verziókat vagy ágakat (branch) hozzanak létre, és új funkciókat vagy javításokat próbáljanak ki anélkül, hogy befolyásolnák a fő projektkódot.
  • +
  • Dokumentálás: A forráskezelő rendszerekben lehetőség van a módosításokhoz kapcsolódó üzenetek (commit message) rögzítésére, ami segíti a változtatások okainak és céljainak dokumentálását.
  • +
  • Integráció és folyamatos fejlesztés: Segítik az automatikus tesztelést és a folyamatos integrációs folyamatokat (CI/CD), mivel biztosítják, hogy minden változtatás könnyen kezelhető és nyomon követhető legyen.
  • +
+

+

Git source control (forráskezelés) használata a VS Code-ban

+

A Visual Studio Code integrált forráskezeléssel (SCM) rendelkezik, és tartalmazza a Git támogatást. Sok más forráskezelő szolgáltató érhető el a extensions oldalon a VS Code Marketplace-en.

+ + +

Git repository

+

A Git áttekintése

+
+

Győződjön meg arról, hogy a Git telepítve van. A VS Code a számítógépe Git-telepítését fogja használni (legalább 2.0.0 verzió szükséges), ezért telepítenie kell a Git-et, mielőtt ezeket a szolgáltatásokat igénybe vehetné.

+
+

A bal oldali tevékenységsávban található Source control ikon mindig áttekintést ad arról, hogy hány változás van jelenleg a tárhelyen (repo). Az ikon kiválasztásával megjelennek az aktuális adattár-módosítások részletei: CHANGES, STAGED CHANGES és MERGE CHANGES.

+

Az egyes elemekre kattintva részletesen megtekintheti az egyes fájlokon belüli szöveges változásokat. Vegye figyelembe, hogy a nem szakaszos módosítások esetén a jobb oldali szerkesztő továbbra is lehetővé teszi a fájl szerkesztését.

+

A repo státuszára vonatkozó indikátorokat is megtalálhatók a VS Code bal alsó sarkában: az aktuális branch (current branch), dirty indicators, valamint a bejövő és kimenő commitok száma. az aktuális ágból. A tárhely bármely ágát checkout-olhatja, ha rákattint az állapotjelzőre, és kiválasztja a Git hivatkozást a listából.

+
+

Tip

+

A VS Code-ot megnyithatjuk egy Git-repo könyvtárában. Ehhez a parancs a könytárban állva: code . illetve pl: code ~/ros2_ws/src/arj_packages/, ha a tantárgy arj_packages repoját szereténk megnyitni. A VS Code Git szolgáltatásai továbbra is a szokásos módon működnek, és minden változást megjelenítenek a tárolón belül, de a hatókörű könyvtáron kívüli fájlmódosítások egy eszköztippel vannak árnyékolva, jelezve, hogy az aktuális munkaterületen kívül helyezkednek el.

+
+

Commit

+

Az staging (git add) és unstaging (git reset) végrehajtható a fájlok kontextus szerinti műveleteivel vagy húzással.

+
+

Konfigurálja a Git-felhasználónevét és e-mail-címét. Commitoláskor, figyelni kell, hogy ha a felhasználónév és/vagy e-mail-cím be legyen állítva a Git-konfigurációban. Részletek: [Git commit information] (https://git-scm.com/docs/git-commit#_commit_information).

+
+

Stage all changes button

+

Beírható egy commit üzenetet a változtatások jelzésére, ezután kbstyle(Ctrl+Enter) (macOS: kbstyle(⌘+Enter)) billentyűt kell ütni a véglegesítéshez. Ha vannak változtatások(staged chnages), csak azokat a változtatásokat hajtják végre. Ellenkező esetben a rendszer kéri, hogy válassza ki, milyen változtatásokat szeretne végrehajtani.

+

Például a korábbi képernyőképen csak az "overview.png" szakaszos módosításai szerepelnek a véglegesítésben. A későbbi szakaszolási és véglegesítési műveletek külön véglegesítésként tartalmazhatják a "versioncontrol.md" és a másik két ".png" kép módosításait.

+

A pontosabb Commit műveletek a forráskezelés nézet tetején található Views and More Actions ... menüben találhatók.

+

Nézetek és további műveletek gomb

+
+

Tipp: Ha rossz ágon (branch) hajtja végre a módosítást, vonja vissza a véglegesítést a Command Palette Git: Undo Last Commit (Utolsó commit visszavonása) paranccsal (Ctrl+Shift+P).

+
+ + +

Repo klónozása

+

Ha még nincs klónozva repository, akkor a Forráskezelés nézetben a Open Folder a helyi gépről vagy a Clone Repository (távoli gépről) lehetőségek közül választhat.

+

Forrásvezérlési első futtatása

+

A Clone Repository lehetőséget választva, a rendszer meg fogja kérni a távoli tárhely URL-címét (például a GitHubon) és azt a könyvtárat, amelybe a helyi tárat helyezi.

+

GitHub-tárhely esetén az URL-t a GitHub Kód párbeszédpanelen találja meg.

+

klón tárhely párbeszédpanel

+

Ezután illessze be ezt az URL-t a Git: Clone promptba.

+

set repository URL

+

Megjelenik a Clone from GitHub lehetőség is. Miután hitelesítette GitHub-fiókját a VS Code-ban, kereshető válnak a saját (akár privát) repók is, név alapján.

+

Beépített terminal

+

A fejlesztőkörnyezet beépített terminálja, mind Windowson, mind Linuxon működik.

+

Alt text

+

+

Hasznos tudni

+
    +
  • pl code . megnyintja az aktuális mappa tartalmát
  • +
  • pl code ~/.bashrc megnyintja a ~/.bashrc tartalmát szerkesztésre
  • +
+

WSL VS code videó

+ + +

ROS 2 ajánlott beállítások

+

ROS 2 C++ fejlesztésnél alapvetően a VS code nem ismeri fel az ROS header fájlokat, így az pl az IntelliSense se működik megfelelően:

+
+ +
Includepath VS code-ban
+
+

Erre egyszerű megoldás az includePath settings-re kattintva beállítani az /opt/ros/humble/** elérési utat. (Természetesen ugyanez működik nem humble verziónál is, ott a megfelelő elérési utat szükséges megadni). Ez a következőképp néz ki:

+
+ +
Includepath settings VS code-ban
+
+

Amennyiben mentette a VS code, az IntelliSense és egyéb funkciók is ennek megfelelően fognak működni.

+

Források: code.visualstudio.com/docs/sourcecontrol/overview

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bevezetes/windows_terminal01.png b/bevezetes/windows_terminal01.png new file mode 100644 index 0000000..8344def Binary files /dev/null and b/bevezetes/windows_terminal01.png differ diff --git a/bevezetes/windows_terminal02.png b/bevezetes/windows_terminal02.png new file mode 100644 index 0000000..fc3fad7 Binary files /dev/null and b/bevezetes/windows_terminal02.png differ diff --git a/bevezetes/windows_vs_code_terminal01.png b/bevezetes/windows_vs_code_terminal01.png new file mode 100644 index 0000000..2029ceb Binary files /dev/null and b/bevezetes/windows_vs_code_terminal01.png differ diff --git a/erzekeles/camera01.png b/erzekeles/camera01.png new file mode 100644 index 0000000..414c442 Binary files /dev/null and b/erzekeles/camera01.png differ diff --git a/erzekeles/can01.svg b/erzekeles/can01.svg new file mode 100644 index 0000000..fc61cb3 --- /dev/null +++ b/erzekeles/can01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/erzekeles/cmakelists01.png b/erzekeles/cmakelists01.png new file mode 100644 index 0000000..fef6e87 Binary files /dev/null and b/erzekeles/cmakelists01.png differ diff --git a/erzekeles/foxglove03.png b/erzekeles/foxglove03.png new file mode 100644 index 0000000..d0246b7 Binary files /dev/null and b/erzekeles/foxglove03.png differ diff --git a/erzekeles/foxglove04.png b/erzekeles/foxglove04.png new file mode 100644 index 0000000..70223db Binary files /dev/null and b/erzekeles/foxglove04.png differ diff --git a/erzekeles/gps01.png b/erzekeles/gps01.png new file mode 100644 index 0000000..cfd164c Binary files /dev/null and b/erzekeles/gps01.png differ diff --git a/erzekeles/imu01.png b/erzekeles/imu01.png new file mode 100644 index 0000000..dcb686a Binary files /dev/null and b/erzekeles/imu01.png differ diff --git a/erzekeles/index.html b/erzekeles/index.html new file mode 100644 index 0000000..f6cc20a --- /dev/null +++ b/erzekeles/index.html @@ -0,0 +1,2739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Érzékelés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Érzékelés

+

Az érzékelés nyers adatok beolvasását jelenti.

+

+

Érzékelés esetében fontos felhívi a figyelmet, hogy ez még nem jelent magas szintű adatfeldolgozást. Szenzorai lehetnek kamerák, mikrofonok, LIDAR-ok stb. Ahogy az ábra is mutatja a tananyagban az érzékeléssel együtt tárgyaljuk az aktuálást is.

+
+

Note

+

Magyar nyelven könnyű összekeverni az érzékelés (sensing) és az észlelés (perception) foglamakat. Az érzékelés egyszerű driver szintű nyers adatok előállításával foglakozik.

+
+

Kamera

+

A kamera az érzékelőjére (pl CCD CMOS szenzor) érkező fényt elektronikus jellé alakítja, diitálisan. Megkülönböztethetünk mono, sztereo vagy mélységérzékelésre képes kamerákat is.

+ +

cam

+

Mélységesztimáció:

+ + +

LIDAR

+

A LIDAR (Light Detection and Ranging) szenzor egy olyan eszköz, amely lézerpulzusokkal és azok visszaverődési idejéből távolságokat képes megállapítani. Az elve hasnoló a lézeres távolságmérőhöz, ám a mérés gyakorisága és frekvenciája is sokkal naygobb annál. Példaképp vegyünk egy forgó 64 csatornás LIDAR-t. Ez jellemzően 10 vagy 20 Hz-en mér, tehát másodpercenként 10 vagy 20 teljes 360°-os körbefordulást tesz meg. A 64 csatorna azt jelenti, hogy minden pillanatban 64 egymás alatti érzékelő érzékel. Egy körbefordulást jellemzően 512 / 1024 / 2048 mérést jelent csatornánként. Innen ki is számolható a másodpercenkénti mérésadat: pl 20*64*1024 = 1 310 720. Tehát jellemzően másodpercenként, több mint egymillió 3D pontot mér az eszköz, amihez intenzitás, ambient, reflektív tulajdonságok is társulnak.

+
    +
  • Jellemző gyártók: Velodyne, Ouster, Livox, SICK, Hokuy, Pioneer, Luminar, Hesai, Robosense, Ibeo, Innoviz, Quanenergy, Cepton, Blickfeld, Aeva
  • +
  • Jellemző interfész: GigE
  • +
  • Jellemző ROS 2 topic típusok: sensor_msgs/msg/PointCloud2, sensor_msgs/msg/LaserScan
  • +
+

LIDAR gyártókat, dataseteket, algoritmusokat tartlamazó gyűjtemény: github.com/szenergy/awesome-lidar.

+

lidar

+ + +

+

Radar

+
    +
  • Jellemző gyártók: Aptiv, Bosch, Continental, Denso
  • +
  • Jellemző interfész: CAN bus
  • +
  • Jellemző ROS 2 topic típusok: radar_msgs/msg/RadarTrack
  • +
+

A LIDAR és a kamera jellemzőinek összehasonlítása

+

IMU

+

Az IMU kis méretű elektromechanikus giroszkópokat és gyorsulásmérőket, valamint jelfeldolgozó processzorokat tartalmazó szenzor. Gyakran kombinálják további szenzorokkal, pl. barometrikus magasságmérővel, magnetométerrel, iránytűvel. Némely GPS (GNSS) rendszerben is megtalálhatók.

+ +

imu

+

GNSS (GPS)

+

A GNSS (global navigation satellite system) globális szatelit-alapú navigációs rendszert jelent, köznapi szóhasználatban ezt szokás GPS-nek nevezni. Ha pontosak szeretnénk lenni, akkor a GPS csupán az első ilyen technológia ezen kívül létezik még GLONASS, BeiDou, Galileo és QZSS rendszer is, ezek üzemeltetése különböző államokhoz / szövetségekhez kötődik.

+ +

gnss

+

Rövid, de jó leírás a GNSS pontosságról: www.sbg-systems.com/news/mastering-accurac-gnss-and-its-errors-sources/

+

CAN bus

+

A CAN bus (Controller Area Network) egy jellemően autóipari szabvány, mely lehetővé teszi a mikrokontrollerek és az eszközök számára, hogy központi egység (host) nélkül kommunikáljanak egymással. Az ethernet kommunkációval összevetve egyszerűbb megvalósítás, alacsonyabb sávszélességű, robosztus.

+ +

can

+

ROS 2 időkezelés

+

Az ROS idő kezelésre a Unix-időt, vagy a POSIX-időt használja. Ez a UTC (greenwichi idő) szerinti 1970. január 1. 00:00:00 óta eltelt másodpercek és nanoszekundumok számát jelenti (int32 sec, int32 nsec). Ez egyrészt relatív kis helyet foglal a memóriában, másrészt könnyen számolható két időpont között eltelt idő, mégpedig egy egyszerű kivonással.

+

ros2time.ipynb

+

Hátránya, hogy nem túl intuitív, nem olvasható az ember számára. Pl. a Foxglove Studio ezért is gyakran átalakítja olvashatóbb formátumra.

+

foxglove_a +foxglove_a

+

A másodpercek és nanoszekundumok a következőképp képzelhetők el:

+
import rclpy
+current_time = node.get_clock().now()
+print(current_time.to_msg())
+
+Output: 
+sec=1694595162, nanosec=945886859
+
+

Az időbélyeg több helyen is szerepet kap:

+
ros2 topic echo /clock --once
+clock:
+  sec: 1689687476
+  nanosec: 770421827
+
+
ros2 topic echo --once /lexus3/gps/duro/current_pose
+
+header:
+  stamp:
+    sec: 1694595162
+    nanosec: 945886859
+  frame_id: map
+pose:
+  position:
+    x: 640142.9676535318
+    y: 5193606.439717201
+    z: 1.7999999523162842
+  orientation:
+    x: 0.008532664424537166
+    y: 0.0018914791588597107
+    z: 0.44068499630505714
+    w: 0.8976192678279703
+
+

Ha szeretnénk átválatni a másodperceket és nanoszekundumokat, azt a következő módon tehetjük meg:

+
from datetime import datetime
+current_time_float = current_time.to_msg().sec + current_time.to_msg().nanosec / 1e9 # 1e9 is 1,000,000,000: nanosec to sec
+print("As a float:\t%.5f" % (current_time_float))
+print("ISO format:", end="\t")
+print(datetime.utcfromtimestamp(current_time_float).isoformat())
+
+
+Output:
+As a float: 1694595162.94589
+ISO format: 2023-09-13T08:52:42.945887
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/erzekeles/lidar01.png b/erzekeles/lidar01.png new file mode 100644 index 0000000..986ac6e Binary files /dev/null and b/erzekeles/lidar01.png differ diff --git a/erzekeles/lidar_camera01.svg b/erzekeles/lidar_camera01.svg new file mode 100644 index 0000000..c4ca0ab --- /dev/null +++ b/erzekeles/lidar_camera01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/erzekeles/package_xml01.png b/erzekeles/package_xml01.png new file mode 100644 index 0000000..d5f1867 Binary files /dev/null and b/erzekeles/package_xml01.png differ diff --git a/erzekeles/practice/index.html b/erzekeles/practice/index.html new file mode 100644 index 0000000..693c38f --- /dev/null +++ b/erzekeles/practice/index.html @@ -0,0 +1,3281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Érzékelés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Gyakorlat

+

A gyakorlat Ubuntu 22.04 ROS humble, Windows 10/11 WSL humble mellett működik. A különböző verziók telepítésének leírása itt található.

+
+

Előzetes ellenőrzés

+

Otthoni gépen a gyakorlat előtt érdemes ellenőrizni, hogy a megfelelő ROS 2 szoftvercsomagok telepítve vannak-e.

+
+
sudo apt install ros-humble-rosbag2 ros-humble-rosbag2-storage-mcap
+
+

Gépteremben is ellenőrizzük a check_all.sh segítségével: +

cd /mnt/kozos/script
+

+
./check_all.sh
+
+
./bag_mcap.sh
+
+

Előkészületek

+

Az előző gyakorlaton megismerkedtünk a következő rosbag-gel (ROS 2-ben a formátum már .mcap):

+

foxglove01

+

Előkészületként nézzük meg, hogy létezik-e a C:\temp könyvtár

+

test -d "/mnt/c/temp" && echo Letezik || echo Nem letezik
+
+Vagy egyszerűbben: +
ls /mnt/c/temp
+

+
    +
  • Ha nem létezik (No such file or directory), akkor hozzuk létre: mkdir /mnt/c/temp
  • +
  • Ha létezik, akkor nincs teendőnk, lépjünk a következő lépésre, másoljuk át ide az .mcap fájlokat
  • +
+

Listázzuk a mérésadatokat a mnt/kozos/measurement_files könyvtárban:

+

ls /mnt/kozos/measurement_files/ -lh
+
+Az eredmény valami hasonló lesz: +
-rwxrwxrwx 1 he he 4.9K Aug 23  2023 leaf01foxglove.json
+-rwxrwxrwx 1 he he 6.6K Sep  4  2023 lexus01foxglove.json
+-rwxrwxrwx 1 he he 2.7G Jun 10 09:17 lexus-2023-07-18-campus.mcap
+-rwxrwxrwx 1 he he 541M Apr 11 17:01 lexus3-2024-04-05-gyor.mcap
+

+

Tanteremben a másolás a következő parancs segítségével:

+
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap  /mnt/c/temp/
+
+
+

Figyelem

+

A fájl mérete miatt a másolás néhány percig is eltarthat.

+
+

Otthon a következő linkről (zöld gomb), vagy parancsként wget-el lehet letölteni:

+
wget  -O lexus3-2024-04-05-gyor.mcap https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/Eclwzn42FS9GunGay5LPq-EBA6U1dZseBFNDrr6P0MwB2w?download=1
+
+

MCAP letöltése 553 MB

+

Listázzuk a megfelelő átmásolt .mcap fájl alap információit, hasonlóan:

+
ros2 bag info /mnt/c/temp/lexus3-2024-04-05-gyor.mcap
+
+

Az eredmény hasnló lesz:

+
Files:             /mnt/c/temp/lexus3-2024-04-05-gyor.mcap
+Bag size:          540.7 MiB
+Storage id:        mcap
+Duration:          12.519s
+Start:             Apr  5 2024 14:51:02.480 (1712321462.480)
+End:               Apr  5 2024 14:51:14.999 (1712321474.999)
+Messages:          5930
+Topic information: 
+  Topic: /lexus3/gps/duro/status_string | Type: std_msgs/msg/String | Count: 124
+  Topic: /tf_static | Type: tf2_msgs/msg/TFMessage | Count: 24
+  Topic: /tf | Type: tf2_msgs/msg/TFMessage | Count: 2597
+  Topic: /lexus3/os_right/points | Type: sensor_msgs/msg/PointCloud2 | Count: 247
+  Topic: /lexus3/os_left/points | Type: sensor_msgs/msg/PointCloud2 | Count: 249
+  Topic: /lexus3/gps/duro/time_ref | Type: sensor_msgs/msg/TimeReference | Count: 124
+  Topic: /lexus3/gps/duro/status_flag | Type: std_msgs/msg/UInt8 | Count: 124
+  Topic: /lexus3/gps/duro/mag | Type: sensor_msgs/msg/MagneticField | Count: 315
+  Topic: /lexus3/gps/duro/time_diff | Type: std_msgs/msg/Float64 | Count: 124
+  Topic: /lexus3/os_center/points | Type: sensor_msgs/msg/PointCloud2 | Count: 246
+  Topic: /lexus3/gps/duro/navsatfix | Type: sensor_msgs/msg/NavSatFix | Count: 124
+  Topic: /lexus3/gps/duro/imu | Type: sensor_msgs/msg/Imu | Count: 1259
+  Topic: /lexus3/gps/duro/current_pose | Type: geometry_msgs/msg/PoseStamped | Count: 124
+  Topic: /lexus3/zed2i/zed_node/left/image_rect_color/compressed | Type: sensor_msgs/msg/CompressedImage | Count: 249
+
+

Játsszuk vissza az .mcap fájlt

+

A következőken a mérésadatfájlt visszajátsszuk és ellenőrizzük, hogy milyen adatok jelennek meg, milyen típusban és sebességgel. A --loop kapcsoló a végtelen ismétlést, a --clock kapcsoló pedig egy /clock topic hirdetéséért felel, ehhez igazítja a lejátszást.

+

ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap --clock --loop
+
+Ugyanez, csak lassabban visszajátszva pl.:

+
ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap --clock --loop --rate 0.2
+
+

A következő topic-ok jelennek meg:

+
ros2 topic list
+
+

Eredménye valami hasonló lesz:

+
/clock
+/events/read_split
+/lexus3/gps/duro/current_pose
+/lexus3/gps/duro/imu
+/lexus3/gps/duro/mag
+/lexus3/gps/duro/navsatfix
+/lexus3/gps/duro/status_flag
+/lexus3/gps/duro/status_string
+/lexus3/gps/duro/time_diff
+/lexus3/gps/duro/time_ref
+/lexus3/os_center/points
+/lexus3/os_left/points
+/lexus3/os_right/points
+/lexus3/zed2i/zed_node/left/image_rect_color/compressed
+/parameter_events
+/rosout
+/tf
+/tf_static
+
+

A ros2 topic hz az adott topic frekvenciáját mutatja. A pozíció ebben az esetben ~10Hz.

+

ros2 topic hz /lexus3/gps/duro/current_pose
+
+Az eredmény valami hasonló lesz: +
average rate: 9.994
+        min: 0.003s max: 1.005s std dev: 0.09166s window: 107
+

+

ROS 2 időkezelés

+

Az ROS idő kezelésre a Unix-időt, vagy a POSIX-időt használja. Ez a UTC (greenwichi idő) szerinti 1970. január 1. 00:00:00 óta eltelt másodpercek és nanoszekundumok számát jelenti (int32 sec, int32 nsec). Ez egyrészt relatív kis helyet foglal a memóriában, másrészt könnyen számolható két időpont között eltelt idő, mégpedig egy egyszerű kivonással.

+

ros2time.ipynb

+

Hátránya, hogy nem túl intuitív, nem olvasható az ember számára. Pl. a Foxglove Studio ezért is gyakran átalakítja olvashatóbb formátumra.

+

foxglove_a +foxglove_a

+

A másodpercek és nanoszekundumok a következőképp képzelhetők el:

+
import rclpy
+current_time = node.get_clock().now()
+print(current_time.to_msg())
+
+Output: 
+sec=1694595162, nanosec=945886859
+
+

Az időbélyeg több helyen is szerepet kap:

+
ros2 topic echo /clock --once
+clock:
+  sec: 1689687476
+  nanosec: 770421827
+
+

ros2 topic echo --once /lexus3/gps/duro/current_pose
+
+Az eredmény valami hasonló lesz:

+
header:
+  stamp:
+    sec: 1694595162
+    nanosec: 945886859
+  frame_id: map
+pose:
+  position:
+    x: 640142.9676535318
+    y: 5193606.439717201
+    z: 1.7999999523162842
+  orientation:
+    x: 0.008532664424537166
+    y: 0.0018914791588597107
+    z: 0.44068499630505714
+    w: 0.8976192678279703
+
+

Ha szeretnénk átválatni a másodperceket és nanoszekundumokat, azt a következő módon tehetjük meg:

+
from datetime import datetime
+current_time_float = current_time.to_msg().sec + current_time.to_msg().nanosec / 1e9 # 1e9 is 1,000,000,000: nanosec to sec
+print("As a float:\t%.5f" % (current_time_float))
+print("ISO format:", end="\t")
+print(datetime.utcfromtimestamp(current_time_float).isoformat())
+
+
+Output:
+As a float: 1694595162.94589
+ISO format: 2023-09-13T08:52:42.945887
+
+

Emlékeztető: a nanoszekundum a másodperc egy milliárdodrésze (10^-9 s).

+ +

A köveztkezőkben átnézünk pár jellemző szenzort (GPS, kamera, LIDAR) és azok topic-jait, node-jait (driver package-ekbe szervezve). Vessünk egy pillantást a saját fejlesztésű Duro GPS (GNSS) driverre: github.com/szenergy/duro_gps_driver. A GPS-t etherneten a számítógéphez csatlakoztatva, az ROS drivert indítva a következő topicokat fogja hirdetni:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TopicType
/gps/duro/current_pose[geometry_msgs/PoseStamped]
/gps/duro/fix[sensor_msgs/NavSatFix]
/gps/duro/imu[sensor_msgs/Imu]
/gps/duro/mag[sensor_msgs/MagneticField]
/gps/duro/odom[nav_msgs/Odometry]
/gps/duro/rollpitchyaw[geometry_msgs/Vector3]
/gps/duro/status_flag[std_msgs/UInt8]
/gps/duro/status_string[std_msgs/String]
/gps/duro/time_ref[sensor_msgs/TimeReference]
+

Inertial Measurement Unit (IMU)

+

Jellemző ROS 2 topic típusok: sensor_msgs/msg/Imu, sensor_msgs/msg/MagneticField

+

ros2 topic echo --once /lexus3/gps/duro/imu
+
+Az eredmény valami hasonló lesz:

+
header:
+  stamp:
+    sec: 1695039048
+    nanosec: 44466475
+  frame_id: duro
+orientation:
+  x: 0.0
+  y: 0.0
+  z: 0.7071067811865475
+  w: 0.7071067811865476
+orientation_covariance:
+  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+angular_velocity:
+  x: 0.01330030487804878
+  y: 0.015893864329268294
+  z: 0.037307355182926834
+angular_velocity_covariance:
+  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+linear_acceleration:
+  x: -0.5291185668945312
+  y: 0.031124621582031248
+  z: -9.610325463867188
+linear_acceleration_covariance:
+  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+
+

Kamera

+

Jellemző ROS 2 topic típusok: sensor_msgs/msg/Image, sensor_msgs/msg/CameraInfo, sensor_msgs/msg/CompressedImage

+

Attzól függően, hogy a kamera képe tömörített vagy sem, a sensor_msgs/msg/Image vagy a sensor_msgs/msg/CompressedImage típusú üzeneteket fogunk látni. Használjuk a megfelelő topic-ot.

+
ros2 topic echo --once /lexus3/zed2i/zed_node/right_raw/image_raw_color
+
+
ros2 topic echo --once /lexus3/zed2i/zed_node/left/image_rect_color/compressed
+
+

Az eredmény valami hasonló lesz:

+
header:
+  stamp:
+    sec: 1695039047
+    nanosec: 340698516
+  frame_id: zed2i_right_camera_optical_frame
+height: 720
+width: 1280
+encoding: bgra8 # vagy format: bgra8; jpeg compressed bgr8
+is_bigendian: 0
+step: 5120
+data: 21,66,93,255,21,66,94,255,25,69,94,255,14,63,90,255,31,55,80,255,19,49,75,255,26,55,76,255,24,57,80,255,35,51,72,255,30,52,74,255,57,73,88,255,55,74,90,255,64,74,93,255,52,66,86,255,56,61,76,255,25,34,48,255,25,31,52,255,16,24,43,255,14,22,41,255,19,27,46,255,13,20,38,255,23,28,45,255,31,41,65,255,36,37,59,255,23,59,82,255,45,71,91,255,51,84,116,255,70,94,122,255,57,105,141,255,42,84,117,255,42,90,126,255,36,81,116,255,..
+
+

LIDAR

+

Jellemző ROS 2 topic típusok: sensor_msgs/msg/PointCloud2, sensor_msgs/msg/LaserScan

+

ros2 topic echo --once /lexus3/os_center/points
+
+Az eredmény valami hasonló lesz:

+
header:
+  stamp:
+    sec: 1695039048
+    nanosec: 390894137
+  frame_id: lexus3/os_center_a_laser_data_frame
+height: 64
+width: 1024
+fields:
+- name: x, y, z, intensity, t, reflectivity, ring, ambient, range
+data: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,16,65,96,211,241,2,0,0,0,0,12,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,16,65,116,145,242,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,32,65,18,92,243,2,0,0,0,0,253,2,0,0,...,
+
+

Vizualizáció

+

RVIZ2

+
ros2 run rviz2 rviz2
+
+

Alakítsunk ki hasonló elrendezést:

+

+

Foxglove studio

+
ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765
+
+

+

Alakítsunk ki hasonló elrendezést:

+

+

Forrás: foxglove.dev/blog/introducing-foxglove-studios-new-navigation

+

Hozzuk létre a simple_sub_cpp package-t

+

A következőkben egy egyszerű subscriber node fog feliratkozni geometry_msgs/PoseStamped üzenetekre, majd kiírni az X és az Y koordinátákat. A gyakorlat a hivatalos ROS 2 tutorialokon alapszik felépítését tekintve.

+

Nyissunk egy új terminált, és source-oljuk a telepítést, hogy a ros2 parancsok működjenek.

+

Navigáljunk az már létrehozott ros2_ws könyvtárba.

+

Fontos, hogy a csomagokat az src könyvtárban kell létrehozni, nem a munkaterület gyökerében. Tehát navigáljunk a ros2_ws/src mappába, és futtassuk a package létrehozó parancsot:

+
cd ~/ros2_ws/src
+ros2 pkg create --build-type ament_cmake simple_sub_cpp
+
+

A terminál egy üzenetet küld vissza, amely megerősíti a simple_sub_cpp csomag és az összes szükséges fájl és mappa létrehozását.

+

Írjuk meg a subscriber node-ot (print_pose.cpp >> simple_sub_node)

+

Lépjünk a ros2_ws/src/simple_sub_cpp/src mappába.

+
cd ~/ros2_ws/src/simple_sub_cpp/src
+
+

Ez az a könyvtár minden CMake package-ben, ahová a forrásfájlok tartoznak (pl. .cpp kiterjesztéssel).

+

Töltsük le a példa feliratkozó kódját:

+
wget -O print_pose.cpp https://raw.githubusercontent.com/sze-info/arj_packages/main/etc/print_pose.cpp
+
+

Ez a parancs létrehozta a print_pose.cpp fájlt.

+

Lépjünk vissza egy szinttel: cd ~/ros2_ws/src/simple_sub_cpp könyvtárba, ahol a CMakeLists.txt és a package.xml fájlok már létrejöttek. +Nyissuk meg pl. VS code segítségével a mappát: code . parancs. Itt a . a code után az aktuális mappát jelenti. Tipp: ha nem a könyvtárban állnánk, akkor is lehetséges teljes könyvtárat megnyitni, ami később pár dolgot egyszerűsít:

+
code ~/ros2_ws/src/simple_sub_cpp/
+
+

+
// ros2 topic type /lexus3/gps/duro/current_pose
+// geometry_msgs/msg/PoseStamped
+// ros2 interface show geometry_msgs/msg/PoseStamped
+
+#include <memory>
+#include "rclcpp/rclcpp.hpp"
+#include "geometry_msgs/msg/pose_stamped.hpp"
+
+using std::placeholders::_1;
+
+class SimplePoseSub : public rclcpp::Node
+{
+public:
+  SimplePoseSub() : Node("simple_pose_sub")
+  {
+    sub1_ = this->create_subscription<geometry_msgs::msg::PoseStamped>("/lexus3/gps/duro/current_pose", 10, std::bind(&SimplePoseSub::topic_callback, this, _1));
+  }
+
+private:
+  void topic_callback(const geometry_msgs::msg::PoseStamped &msg) const
+  {
+    RCLCPP_INFO(this->get_logger(), "x: %.3f, y: %.3f", msg.pose.position.x, msg.pose.position.y);
+  }
+  rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr sub1_;
+};
+
+int main(int argc, char *argv[])
+{
+  rclcpp::init(argc, argv);
+  rclcpp::spin(std::make_shared<SimplePoseSub>());
+  rclcpp::shutdown();
+  return 0;
+}
+
+
+

Python megfelelője

+

A C++ kód python verziója szintén elérhető a github.com/sze-info/arj_packages címen. Érdemes összehasonlítani a C++ és a python kódokat.

+
+

Függőségek hozzáadása

+

Mindig érdemes kitölteni a <description>, <maintainer> és <license> tag-eket:

+
<description>Examples of minimal publisher/subscriber using rclcpp</description>
+<maintainer email="you@email.com">Your Name</maintainer>
+<license>Apache License 2.0</license>
+
+

Adjunk hozzá egy új sort az ament_cmake buildtool függősége után, és illesszük be a következő függőségeket a node include utasításainak megfelelően:

+
<depend>rclcpp</depend>
+<depend>geometry_msgs</depend>
+
+

Ez deklarálja, hogy a pacakge-nek szükséges az rclcpp és a geometry_msgs fordításkor és futtatáskor.

+

CMakeLists.txt

+

Most nyissuk meg a CMakeLists.txt fájlt. +A meglévő find_package(ament_cmake REQUIRED) függőség alá adjuk hozzá a következő sorokat:

+
find_package(rclcpp REQUIRED)
+find_package(geometry_msgs REQUIRED)
+
+

Ezután adjuk hozzá a végrehajtható fájlt (ez most a print_pose.cpp-ből fog csak állni), és nevezzük el simple_sub_node-nak, hogy az ros2 run használatával futtassa a node-ot:

+
add_executable(simple_sub_node src/print_pose.cpp)
+ament_target_dependencies(simple_sub_node rclcpp geometry_msgs)
+
+

Végül az install(TARGETS...) részt adjuk hozzá, hogy az ros 2 megtalálja a futtatható állományt, amit lefordítottunk:

+
install(TARGETS
+simple_sub_node
+DESTINATION lib/${PROJECT_NAME})
+
+

A CMakeLists.txt megtisztítható néhány felesleges szakasz és megjegyzés eltávolításával, így a következőképpen néz ki:

+
cmake_minimum_required(VERSION 3.8)
+project(simple_sub_cpp)
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+set(CMAKE_CXX_STANDARD 14)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+find_package(geometry_msgs REQUIRED)
+
+add_executable(simple_sub_node src/print_pose.cpp)
+ament_target_dependencies(simple_sub_node rclcpp geometry_msgs)
+
+install(TARGETS
+simple_sub_node
+DESTINATION lib/${PROJECT_NAME})
+
+ament_package()
+
+

Összefoglalásképp, a következő módosításokat hajtottuk végre:

+

+

+

Build és futtatás

+
+

Success

+

Már buildelhető a package:

+
+
cd ~/ros2_ws/
+
+
colcon build --packages-select simple_sub_cpp
+
+

Futtassuk a szokásos módon:

+
source ~/ros2_ws/install/setup.bash
+
+
ros2 run simple_sub_cpp simple_sub_node
+
+

Kimenet:

+
[simple_pose_sub]: x: 697201.725, y: 5285679.845
+[simple_pose_sub]: x: 697201.796, y: 5285679.548
+[simple_pose_sub]: x: 697201.838, y: 5285679.251
+[simple_pose_sub]: x: 697201.886, y: 5285678.949
+
+

Házi feladat

+
+

Házi feladat

+

Otthon készítsük el a simple_sub_py package-t, ami a simple_sub_cpp python megfelelője.

+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/erzekeles/ros2time.ipynb b/erzekeles/ros2time.ipynb new file mode 100644 index 0000000..2302757 --- /dev/null +++ b/erzekeles/ros2time.ipynb @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import rclpy\n", + "# use only once\n", + "rclpy.init()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "builtin_interfaces.msg.Time(sec=1694595162, nanosec=945886859)\n" + ] + } + ], + "source": [ + "# print current time with rclpy\n", + "node = rclpy.create_node('time_node')\n", + "current_time = node.get_clock().now()\n", + "print(current_time.to_msg())" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Type of current_time:\t\n", + "Type of current_time.to_msg():\t\n" + ] + } + ], + "source": [ + "# print current_time to ISO format\n", + "from datetime import datetime\n", + "\n", + "print(\"Type of current_time:\", end=\"\\t\")\n", + "print(type(current_time))\n", + "print(\"Type of current_time.to_msg():\", end=\"\\t\")\n", + "print(type(current_time.to_msg()))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "As a float:\t1694595162.94589\n", + "ISO format:\t2023-09-13T08:52:42.945887\n" + ] + } + ], + "source": [ + "current_time_float = current_time.to_msg().sec + current_time.to_msg().nanosec / 1e9 # 1e9 is 1,000,000,000: nanosec to sec\n", + "print(\"As a float:\\t%.5f\" % (current_time_float))\n", + "print(\"ISO format:\", end=\"\\t\")\n", + "print(datetime.utcfromtimestamp(current_time_float).isoformat())" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ISO format:\t2020-09-13T12:26:40\n" + ] + } + ], + "source": [ + "big_float = 1600000000.0\n", + "print(\"ISO format:\", end=\"\\t\")\n", + "print(datetime.utcfromtimestamp(big_float).isoformat())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/erzekeles/rviz01.png b/erzekeles/rviz01.png new file mode 100644 index 0000000..db11d7f Binary files /dev/null and b/erzekeles/rviz01.png differ diff --git a/erzekeles/terminalintro01.gif b/erzekeles/terminalintro01.gif new file mode 100644 index 0000000..29f6032 Binary files /dev/null and b/erzekeles/terminalintro01.gif differ diff --git a/erzekeles/vscode05.png b/erzekeles/vscode05.png new file mode 100644 index 0000000..32a023f Binary files /dev/null and b/erzekeles/vscode05.png differ diff --git a/eszleles/compare_vs_code01.png b/eszleles/compare_vs_code01.png new file mode 100644 index 0000000..ad74f0f Binary files /dev/null and b/eszleles/compare_vs_code01.png differ diff --git a/eszleles/ground_filter/index.html b/eszleles/ground_filter/index.html new file mode 100644 index 0000000..d9b5039 --- /dev/null +++ b/eszleles/ground_filter/index.html @@ -0,0 +1,2492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ground filter - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Ground filter

+

+

Elérhető: +- url-kaist/patchwork-plusplus-ros/tree/ROS2 +- github.com/MohamedHussein736/patchwork-plusplus-ros/tree/ROS2 +- github.com/jkk-research/patchwork-plusplus-ros az eredeti repo forkja, ami csak az ROS 2-es brenchet tartalmazza, az eredeti Urban Robotics Lab repora a SZE-JKK pull request-jét mergelték.

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/jkk-research/patchwork-plusplus-ros
+
+
cd ~/ros2_ws/src
+
+
colcon build --packages-select patchworkpp
+
+
ros2 launch patchworkpp demo.launch
+
+

TODO

+
ros2 bag play kitti_00_sample.db3
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eszleles/index.html b/eszleles/index.html new file mode 100644 index 0000000..9c647c8 --- /dev/null +++ b/eszleles/index.html @@ -0,0 +1,2660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélelt - Észlelés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Észlelés

+

Az észlelés (perception) az érzékelt nyers adatokból történő információ kinyerése.

+

+

Az észlelés célja lehet:

+
    +
  • Objektumfelismerés (detekció), pl:
      +
    • Gyalogos, biciklis jármű felimerés
    • +
    • Tábla felismerés, jelzőlámpa felismerés
    • +
    • Vezethető felület és fogalmi sáv felismerés (lokalizációhoz és tervezéshez is)
    • +
    +
  • +
  • Objektumklasszifikáció:
      +
    • A már felismert objektumok osztályzása. Pl a jelzőlámpa milyen színű éppen, melyik jármű kisteherautó és melyik lovaskocsi.
    • +
    +
  • +
  • Objektum követés és predikció:
      +
    • Merre haladtak eddig a járművek, gyalogosok illetve becslés, hogy merre haladnak majd a jövőben. Ez összefügghet a klasszifikációval, hiszen bár egy lovaskocsi méretre hasonló egy utánfutós autóhoz, mégis egész más gyorsulásra képes. Az így gyűjtött infromációnak megfeleően lehet útvonalat, tarjektóriát tevezni.
    • +
    +
  • +
  • Lokalizáció és térképépítés
      +
    • SLAM: nem illetve nem csak GNSS alapú helymeghatározás kiegészítése lokális térképp készítéssel. LOAM: LIDAR alapú odometria.
    • +
    +
  • +
+

A felhasznált szenzorok alapján lehet: +- LIDAR +- Kamera +- Radar +- IMU +- GNSS/GPS +- Mikrofon +- A fenti szenzorok tetszőleges kombinációja

+
+

Danger

+

Magyar nyelven könnyű összekeverni az érzékelés (sensing) és az észlelés (perception) foglamakat. Az észlelés összetett funkció a nyers adatokból feldolgozott, értelmezett kimenet előállításával foglakozik.

+
+
flowchart LR
+
+L[Tervezés]:::light
+
+subgraph Perception [Észlelés]
+  T[Térképezés]:::light 
+  H[Lokalizáció]:::light
+  P[Objektum
+  predikció]:::light 
+  D[Objektum
+  detekció]:::light
+  K[Objektum 
+  klasszifikáció]:::light
+  D-->K
+end
+subgraph Sensing [Érzékelés]
+  GPS[GPS/GNSS]:::light -.-> T
+  GPS -.-> H
+  LIDAR[LIDAR]:::light
+  KAM[Kamera]:::light
+  IMU[IMU]:::light
+  LIDAR -.-> D
+  LIDAR -.-> P
+  LIDAR -.-> T
+  KAM-.-> P
+  KAM-.-> D
+  IMU-.-> T
+  D-.->P
+end
+
+T -->|térkép| L
+H -->|pose| L
+P -->|obj.| L
+K -->|obj.| L
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Ez a tananyagrész a TU München Autonomous Driving Software Engineering tantárgy tananyagán alapszik, amit az Institute of Automotive Technology intézet munkatársai állítottak össze. Az órai videó elérhető német nyelven:

+ + +

Kihívások, nehézségek

+

Számos kihívás nehezítheti a felismerést illetve annak pontosságát:

+
    +
  • Időjárás (eső, hó, köd, ...)
  • +
  • Napszak (éjszaka, naplemente, napfelkelte ...)
  • +
  • Takarás (objektumok csak részlegesen látszanak)
  • +
  • Számítási idő (nagyobb sebességeknél hatványozottan)
  • +
  • Különböző könyezetek (városi, autópálya, erdős szakasz ...)
  • +
+

Use case (esettanulmányok)

+

Mivel az észlelés minden egyes aspektusát nehéz lenne bemutani, inkább pár use-case segítségével mutatnánk be.

+

Kamera-alapú jelzőlámpa klasszifikáció

+

Mesterséges intelligencia (neurális háló: YOLOv7) segítségével kamerakép feldolgozás.

+ + +

LIDAR-alapú egyszerű magasság szűrés

+

A gyakorlaton is előkerülő feladat egyszerű LIDAR szűrés, X, Y és Z koordináták szerint. Mivel a LIDAR a 3D környezet egyszerű reprezentációját adja bizonyos szempontból könnyebb dolgunk van vele, mint a kamerával. Gyakori technológia, hogy az út szintjét szűrik ki a LIDAR adatból(ground-segmentation), majd a maradék pontok (non-ground) jelentik az összes objektumot. Itt egy sokkal egyszerűbb technológiát demonstrálunk:

+

+

Klaszterezés

+

Miután az út szintjét kiszűrtük a LIDAR adatból (ground-segmentation), út pontok (ground) és maradék pontok (non-ground) keletkeztek. A non-ground pontokat természetesen klaszterezni (cluster) kell, hogy kialakuljanak az objektumokat leíró pontok. A klaszterezés lényege, hogy egy adott objektum (pl egy autó) pontjai egymáshoz közel állnak.

+

+

Forrás: codeahoy.com

+

+

Forrás: saját

+ + +

Szenzorfúzió

+

A következő videó egy való életből vett példán keresztül mutatja be az észlelést.

+ + +

LIDAR-alapú útfelület / padka detekció

+

Egyetemünk egyik saját fejlesztésű algoritmusa.

+ + +

LIDAR-alapú objektum követés és predikció

+ + +

SLAM LIDAR és kamera fúzió

+

A Simultaneous Localization and Mapping (SLAM) lényege, hogy egy mozgó rendszer (robot vagy jármű) pozícióját és a környezetét térképezze egyszerre, miközben navigál.

+ + +

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eszleles/kossuthhid01.png b/eszleles/kossuthhid01.png new file mode 100644 index 0000000..330161d Binary files /dev/null and b/eszleles/kossuthhid01.png differ diff --git a/eszleles/practice/index.html b/eszleles/practice/index.html new file mode 100644 index 0000000..3e50fa3 --- /dev/null +++ b/eszleles/practice/index.html @@ -0,0 +1,2605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat A - Észlelés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Előkészületek

+

Korábbi gyakorlaton megismerkedtünk a rosbag formátummal (ROS 2-ben a formátum már .mcap).

+

Előkészületként nézzük meg, hogy létezik-e a C:\temp könyvtár

+

test -d "/mnt/c/temp" && echo Letezik || echo Nem letezik
+
+Vagy egyszerűbben: +
ls /mnt/c/temp
+

+
    +
  • Ha nem létezik (No such file or directory), akkor hozzuk létre: mkdir /mnt/c/temp
  • +
  • Ha létezik, akkor nincs teendőnk, lépjünk a következő lépésre, másoljuk át ide az .mcap fájlokat
  • +
+

Tanteremben a másolás a következő parancsok egyike legyen:

+
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample01.mcap  /mnt/c/temp/
+
+
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample02.mcap  /mnt/c/temp/
+
+
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample03.mcap  /mnt/c/temp/
+
+
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample04.mcap  /mnt/c/temp/
+
+

Otthon a következő linkről (zöld gomb), vagy parancsként wget-el lehet letölteni:

+
wget  -O lexus3sample02.mcap https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/EakTOhcjblNInqjRMfaGVmsB0diDv0SWpXw9rwo0MD7f3w?download=1
+
+

Rosbag letöltése 300 MB

+

1. feladat

+

A feladat egyszerű LIDAR szűrés, X, Y és Z koordináták szerint.

+

+

Ha még nem tettük volna, klónozzuk az arj_packages repot és buildeljük az arj_simple_perception package-t.

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/sze-info/arj_packages
+
+

Ha már létezik, akkor az előző lépés helyett, csak frissítsük.

+
cd ~/ros2_ws/src/arj_packages/
+
+
git status
+
+
git checkout -- .
+
+

git pull
+
+A git checkout -- . az összes esetleges lokális változás visszavonására jó.

+
cd ~/ros2_ws
+
+
MAKEFLAGS="-j4" colcon build --packages-select arj_simple_perception --cmake-args -DCMAKE_BUILD_TYPE=Release
+
+
+

Tip

+

A klasszikus colcon build --packages-select arj_simple_perception is működik, csupán egy kicsit lassabb, ezért használjuk most a build flageket.

+
+
source ~/ros2_ws/install/setup.bash
+
+
ros2 run arj_simple_perception lidar_filter_simple
+
+
ros2 bag play /mnt/c/temp/lexus3sample02.mcap --loop --clock --rate 0.5 --read-ahead-queue-size 2048
+
+

Nézzük meg, hogy a következő toicok léteznek-e? +- /lexus3/os_center/points +- /lidar_filter_output

+
ros2 topic list
+
+

Kérdezzük le a topicok típusát.

+
ros2 topic type /lidar_filter_output
+
+
ros2 topic type /lexus3/os_center/points
+
+

Mindkét esetben sensor_msgs/msg/PointCloud2 kell, hogy legyen.

+

Vizsgáljuk meg közelebbről a node-ot.

+
ros2 node info /lidar_filter_simple
+
+
Subscribers:
+    /lexus3/os_center/points: sensor_msgs/msg/PointCloud2
+    /parameter_events: rcl_interfaces/msg/ParameterEvent
+Publishers:
+    /lidar_filter_output: sensor_msgs/msg/PointCloud2
+    /parameter_events: rcl_interfaces/msg/ParameterEvent
+    /rosout: rcl_interfaces/msg/Log
+
+

Új terminalban vizsgáljuk meg a gráfot:

+
ros2 run rqt_graph rqt_graph
+
+

Alt text

+

2. feladat

+

Nyissuk meg VS code-ban a package-t:

+
code ~/ros2_ws/src/arj_packages/arj_simple_perception
+
+

Hasnolítsuk össze a lidar_filter_simple_param.cpp-t a lidar_filter_simple.cpp-vel. Vs code jobb kilikk a fájlon Select for compare és Compare with Selected.

+

compare_vs_code01

+

Az előző feladatban használt egyszerű filter minimum és maximum X,Y,Z értékeit dinamikusan változtassuk.

+
source ~/ros2_ws/install/setup.bash
+
+
ros2 run arj_simple_perception lidar_filter_simple_param
+
+
source ~/ros2_ws/install/setup.bash
+
+
ros2 launch arj_simple_perception run_rviz1.launch.py
+
+

Állítsuk át a paramétereket:

+
ros2 run rqt_reconfigure rqt_reconfigure
+
+

A 3 terminal helyett használhatunk egy launch fájlt is: +

source ~/ros2_ws/install/setup.bash
+

+
ros2 launch arj_simple_perception run_all.launch.py
+
+

Nagyjából így fog kinézni az rqt_reconfigure meg az rviz2:

+

+

Önálló feladat 1

+

Írjunk egy launch fájlt, nevezzük run_fliter_and_rviz.launch.py-nak, ami a filtert és az rviz configot indítja. Így lehessen indítani:

+
ros2 launch arj_simple_perception run_fliter_and_rviz.launch.py
+
+

Önálló feladat 2

+

Módosítsuk a lidar_filter_simple_param.cpp-t, úgy, hogy amennyiben a minimum érték nagyobb, mint a maximum, akkor is működjön. Ebben az esetben kezelje a minimum értéket maximumként és fordítva.

+

Írjon ki egy warning üzenetet.

+
if ...
+RCLCPP_WARN_STREAM(this->get_logger(), "Minimum is bigger than maximum, inverse usage.");
+
+

Utolsó lépések

+

A tanteremben állítsuk vissza az eredeti állapotot. (Otthon commitolhatjuk saját repo-ba, ha szeretnénk.)

+

cd ~/ros2_ws/src/arj_packages/
+
+
git status
+
+A git checkout -- .: Minden nem staged (unstaged) változás elvetése lokálisan. VS code-ban kb ez a "discard all changes" parancs lenne. +
git checkout -- .
+
+Nézzük újra a státuszt:

+
git status
+
+
git pull
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eszleles/practice_cluster/index.html b/eszleles/practice_cluster/index.html new file mode 100644 index 0000000..59a60b7 --- /dev/null +++ b/eszleles/practice_cluster/index.html @@ -0,0 +1,2964 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat B - Észlelés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 LIDAR klaszterezés

+

A rövid gyakorlat / workshop célja, hogy a LIDAR adatok objektumokká történő szűrését bemutassa. Tehát az egyes LIDAR pontoból nagyobb objektumoat / klasztereket készítünk. Ezek az objektumok lehetnek gyalogosok, autók, épületek stb. A gyakorlat ROS 2 kompatibilis. Static Badge

+

Követelmények (magas szintű áttekintés)

+
    +
  1. ROS 2 Humble: 🟠 lásd a korábbi tananyagok vagy a docs.ros.org/en/humble/Installation.html
  2. +
  3. Logfájl nyers LIDAR adatokkal (MCAP formátum, bag) ✅
  4. +
  5. A patchworkpp csomag az alapsík kiszűrésére ✅
  6. +
  7. A lidar_cluster csomag a klaszterezés végrehajtásához ✅
  8. +
+

Videó áttekintése

+

A következő képernyőfelvétel bemutatja a szükséges lépéseket:

+ + +

1. lépés. - Ha még nincs meg korábbról, töltsük le a nyers adatokat

+

A LIDAR adatok klaszterezéséhez először – nem meglepő módon – LIDAR adatokra van szükség. Használja a következő 3 lehetőség valamelyikét, amennyiben még nincs meg az elsőző gyakorlatokból.

+

A lehetőség: MCAP letöltése az alábbi linkről

+

Download MCAP [~540MB]

+

Példáinkban az .mcap fájl a /mnt/c/bag/ mappába kerül mentésre. Ha másik könyvtárat szeretne használni, kérjük, módosítsad azt ennek megfelelően.

+

B lehetőség: Töltsük le MCAP-unkat a terminálján keresztül

+
+ Ne felejtse el először a könyvtárat módosítani. + +Esetünkben a `/mnt/c/bag/` a hely, ahova tenni fogjuk: + +
cd /mnt/c/bag/
+
+
+ +

wget https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/Eclwzn42FS9GunGay5LPq-EBA6U1dZseBFNDrr6P0MwB2w?download=1  -O lexus3-2024-04-05-gyor.mcap
+
+Tanteremben ez így néz ki: +
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap /mnt/c/temp/
+
+Windows böngészőből is meg lehet tenni, de a terminálból csak egy parancs.

+

C lehetőség: Saját MCAP használata

+

Használhatunk saját MCAP fájt, de ebben az esetben a következőket kell módosítani:

+
    +
  • A LIDAR topic
  • +
  • Példánkban ez a /lexus3/os_center/points
  • +
  • LIDAR frame
  • +
  • Példánkban ez a lexus3/os_center_a_laser_data_frame
  • +
+

Később se felejtsük el frissíteni ezeket a további lépésekben.

+

Ellenőrizzük a nyers adatokat

+

Játsszuk le a bag-et következőhöz hasonló paranccsal: +

ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap -l
+

+
+

Info

+

Az -l kapcsoló a play parancsban végtelenített lejátszást jelent.

+
+
+

Success

+

Ha minden a várt módon működik, több topicot kellene látnunk egy másik terminálon +

+ Topic-ok +Egy másik terminálkiadásban a következő parancsot adjuk ki:

+

ros2 topic list
+
+Hasonló topiclistát kellene látni:

+

/clock
+/events/read_split
+/lexus3/gps/duro/current_pose
+/lexus3/gps/duro/imu
+/lexus3/gps/duro/mag
+/lexus3/gps/duro/navsatfix
+/lexus3/gps/duro/status_flag
+/lexus3/gps/duro/status_string
+/lexus3/gps/duro/time_diff
+/lexus3/gps/duro/time_ref
+/lexus3/os_center/points
+/lexus3/os_left/points
+/lexus3/os_right/points
+/lexus3/zed2i/zed_node/left/image_rect_color/compressed
+/parameter_events
+/rosout
+/tf
+/tf_static   
+
+

+

Also there must be at least one sensor_msgs/msg/PointCloud2, check with: +

 ros2 topic type /lexus3/os_center/points
+
+Result: +
sensor_msgs/msg/PointCloud2
+

+
+

2. lépés - ROS 2 package-ek telepítése

+
+

Info

+

Amennyiben nincs ~/ros2_ws/ workspace, a következő parancsara lesz szükségünk: +

mkdir -p ~/ros2_ws/src
+
+Ettől eltérő workspace név szerint értelemszerűen módosítani kell a következő parancsokat is.

+
+

Clone patchworkpp package

+

A patchwork-plusplus-ros a Patchwork++ (@ IROS'22) ROS 2 csomagja, amely gyors és robusztus LIDAR talajszegmentálást biztosít. Javasoljuk a JKK-research fork-ot, amely néhány fejlesztést tartalmaz, vagy használhatjuk az eredeti KAIST változatát is.

+

cd ~/ros2_ws/src
+
+
git clone https://github.com/jkk-research/patchwork-plusplus-ros
+
+or +
git clone https://github.com/url-kaist/patchwork-plusplus-ros -b ROS2
+

+

Clone lidar_cluster package

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/jkk-research/lidar_cluster_ros2
+
+

Build

+
cd ~/ros2_ws
+
+
colcon build --packages-select patchworkpp lidar_cluster --symlink-install
+
+

3. lépés - Futtatás

+

Milyen az elvárt működés?

+
graph TD;
+
+    p1[ /lexus3/os_center/points<br/>sensor_msgs::PointCloud2]:::white --> patchwork([ /patchwork_node]):::light
+    patchwork --> p
+    p[ /nonground<br/>sensor_msgs::PointCloud2]:::white --> cluster([ /cluster_node]):::light
+    cluster --> f1[ /clustered_points<br/>sensor_msgs::PointCloud2]:::white
+    cluster --> f2[ /clustered_marker<br/>visualization_msgs::MarkerArray]:::white
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274
+    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+ Ne felejtsünk el source-olni + +
source ~/ros2_ws/install/setup.bash
+
+
+ +
ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap -l
+
+

ros2 launch patchworkpp demo.launch.py  cloud_topic:=/lexus3/os_center/points cloud_frame:=lexus3/os_center_a_laser_data_frame
+
+Használjuk a következő klaszterezési algoritmusok egyikét:

+

ros2 launch lidar_cluster dbscan_spatial.launch.py
+
+A DBSCAN (Density-Based Spatial Clustering of Applications with Noise) egy nem-grid-alapú klaszterezési algoritmus. +Egy modern 6 magos vagy jobb CPU-n legalább 10 Hz-es teljesítményre számíthatunk.

+

ros2 launch lidar_cluster euclidean_spatial.launch.py
+
+Nem-grid klaszterezés euklideszi távolság alapján. +Egy modern 6 magos vagy jobb CPU-n legalább 5 Hz-es teljesítményre számíthatunk.

+

ros2 launch lidar_cluster euclidean_grid.launch.py
+
+Voxel grid alapú klaszterezés az euklideszi távolság alapján. +Egy modern 6 magos vagy jobb CPU-n legalább 100 Hz-es teljesítményre számíthatunk.

+
ros2 launch lidar_cluster rviz02.launch.py
+
+
+

Success

+

Ha minden a várt módon működik, hasonló rviz ablakot kell látnunk. +lidar_cluster01

+
+

Linkek

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eszleles/road_filter/index.html b/eszleles/road_filter/index.html new file mode 100644 index 0000000..fd060a2 --- /dev/null +++ b/eszleles/road_filter/index.html @@ -0,0 +1,2475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Road filter - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Road filter

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eszleles/rqt_graph02.svg b/eszleles/rqt_graph02.svg new file mode 100644 index 0000000..69c0c78 --- /dev/null +++ b/eszleles/rqt_graph02.svg @@ -0,0 +1,1127 @@ + + +Qt SVG Document +Generated with Qt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eszleles/rqt_rviz01.png b/eszleles/rqt_rviz01.png new file mode 100644 index 0000000..b03eace Binary files /dev/null and b/eszleles/rqt_rviz01.png differ diff --git a/eszleles/slam/index.html b/eszleles/slam/index.html new file mode 100644 index 0000000..b21cd27 --- /dev/null +++ b/eszleles/slam/index.html @@ -0,0 +1,2722 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SLAM és LOAM - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

SLAM és LOAM

+

Simultaneous localization and mapping (SLAM) és LIDAR-based odometry and or mapping (LOAM).

+

Egy győri mérésből összeállított gobális pontfelhő:

+

+

Direct LIDAR-Inertial Odometry

+

A DLIO egy könnyűsúlyú LIDAR-inerciális odometra algoritmus, amely újszerű coarse-to-fine (durva-finom) megközelítéssel folytonos idejű trajektóriát generál.

+

+ + +

Telepítés

+

Elérhető:

+ +

Nézzük meg, hogy telepítve van-e a pcl-ros:

+
sudo apt install ros-humble-pcl-ros
+
+
cd ~/ros2_ws/src/
+
+
git clone https://github.com/jkk-research/direct_lidar_inertial_odometry
+
+
cd ~/ros2_ws/
+
+
colcon build --packages-select direct_lidar_inertial_odometry 
+
+

Futtatás

+
code ~/ros2_ws/src/direct_lidar_inertial_odometry/launch/dlio.launch.py
+
+
rviz = LaunchConfiguration('rviz', default='true')
+pointcloud_topic = LaunchConfiguration('pointcloud_topic', default='/lexus3/os_center/points')
+imu_topic = LaunchConfiguration('imu_topic', default='/lexus3/os_center/imu')
+
+

Első opció: Colon-nál vagy --symlink-install-t használunk: ekkor a fájlok forrásból való másolása helyett szimbolikus hivatkozásokat használ. Így elkerülhető, hogy pl. minden egyes launch fájl módosítás esetén újra kelljen buildelni a package-t.

+
cd ~/ros2_ws/ && colcon build --symlink-install --packages-select direct_lidar_inertial_odometry  
+
+

Második opció: újra buildelünk minden egyes launch fájl módosítás esetén:

+
cd ~/ros2_ws/ && colcon build --packages-select direct_lidar_inertial_odometry 
+
+

KISS-ICP

+

KISS-ICP egy LIDAR odometria pipeline megoldás, amely tegtöbb esetben komolyabb paraméter állítás nélül is jól működik.

+

KISS-ICP Demo

+

Telepítés

+
cd ~/ros2_ws/src/
+
+
git clone https://github.com/PRBonn/kiss-icp
+
+
cd ~/ros2_ws/
+
+
colcon build --packages-select kiss_icp
+
+

Futtatás

+
ros2 launch kiss_icp odometry.launch.py topic:=/lexus3/os_left/points
+
+

Linkek

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feleves_beadando/index.html b/feleves_beadando/index.html new file mode 100644 index 0000000..2102817 --- /dev/null +++ b/feleves_beadando/index.html @@ -0,0 +1,2633 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kis beadandó és nagy féléves - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + + + +
+
+ + + + + + + +

Kis beadandó és nagy féléves

+

A kis beadandó célja, hogy a hallgatók az órán megszerzett kezdő szintű elméleti tudás mellé gyakorlati tapasztalatot szerezzenek ROS 2-ről és GitHub-ról. A kis beadandó viszonylag kevés idő alatt elvégezhető: egy oktató pár óra alatt, egy átlag hallgató pár délután alatt elkészülhet vele. Terjedelme lehet rövid, tehát 30-100 kódsor node-onként.

+

Ezzel szemben a nagy féléves egy kicsit több időt vesz igénybe, de sokkal érdekesebb feladatra is van lehetőség és idő. Ráadásul a jó és jeles érdemjegyet is csak így lehet megszerezni.

+

A jegyszerzés másik lehetősége a ZH-k, erre azonban csak szerény érdemjegy kapható.

+
flowchart TD
+
+K([Kötelező</br>kis beadandó ]):::light ------> |sikertelen| X0
+K --> A([Aláírás]):::green 
+A -->|ZH irány| ZH1([ZH1]):::light
+A --> |féléves irány| N([Nagy féléves]):::light
+PZH --> |sikertelen| X1
+ZH2 --> |sikertelen| PZH([Pót ZH]):::light
+ZH1 --> ZH2([ZH2]):::light
+ZH2 --> |siker| OK1
+PZH --> |siker| OK1
+N ----> |siker| OK2
+X0([Aláírás megtagadás]):::red
+X1([1, elégtelen]):::red
+OK2([4/5 érdemjegy]):::green
+OK1([2/3 érdemjegy]):::green
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
+
+

Határidők, félév beosztása

+

Fontos, tudni, hogy a kis beadandó aláírás feltétel. A GitHub regisztráció, a beadandó link beküldés elmulasztása, már a szemeszter viszonlag korai szakszában sikeretelen félévet eredményezhet. Ezek kis feladatok, meglétüket mégis szigorúan ellenőrizzük.

+
flowchart LR
+
+H2([2 alkalom]) --- H2A([Github<br>regisztráció])--- H2B([Copilot regisztráció<br>indítása])
+H3([3 alkalom]) --- H3A([Beadandó Github<br>link elküldése]) --- H3B([Copilot<br>regisztráció kész])
+H5([5 alkalom]) --- H5A([Kis beadandó<br>véglegestése])
+H7([7 alkalom]) --- H7A([ZH1]) --- H7B([Nagy féléves Github<br>link elküldése])
+H10([10 alkalom]) --- H10A([ZH2])
+H13([13 alkalom]) --- H13A([PótZH])
+V2([Vizsgaidőszak 2. hét]) --- V2A([Nagy féléves<br>véglegesítés])
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
+
+class H2,H3,H5,H7,H10,H13,V2 white
+class H2A,H2B,H3B,H7A,H7B,H10A,V2A light
+class H3A,H5A,H13A, red
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feleves_beadando/kisbeadando/index.html b/feleves_beadando/kisbeadando/index.html new file mode 100644 index 0000000..357827f --- /dev/null +++ b/feleves_beadando/kisbeadando/index.html @@ -0,0 +1,2684 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Kis beadandó - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Kis beadandó

+

A kis beadandó célja, hogy a hallgatók az órán megszerzett kezdő szintű elméleti tudás mellé gyakorlati tapasztalatot szerezzenek ROS 2-ről és GitHub-ról. A kis beadandó viszonylag kevés idő alatt elvégezhető: egy oktató pár óra alatt, egy átlag hallgató pár délután alatt elkészülhet vele. Fontos, hogy a beadandó aláírás feltétel.

+

Elvárt kvalitások:

+
    +
  • Egy package, 1 vagy 2 node
  • +
  • Minimum 1 publisher vagy 1 subscriber (több lehet)
  • +
  • Rövid dokumentáció, ami a build menetét, a node-topic kapcsolatokat tartalmazza, a példák szerinti részletességgel
  • +
  • Helyes névadás
  • +
  • Template használata vagy saját megoldás, de a példák szerinti kidolgozottsági szint
  • +
  • Lehetőleg hiba nélkül forduljon, de a build warning sok esetben megengedhető, a lényeg a tanulás
  • +
  • Minél több commit, hogy a munkafolyamatot is lássuk
  • +
  • Terjedelem rövid: 30-100 kódsor node-onként + CMakeLists.txt, package.xml, README.md, launch fájlok (nem baj, ha hosszabb, de nem elvárt)
  • +
  • Lehetőleg képpel illusztrálva (lásd példák)
  • +
  • Lehetőleg mermaid diagram a node-ok, topic-ok viszonyáról (lásd példák, leírás)
  • +
+
+

Danger

+

A kis beadandó akkor lesz elfogadható, ha a node buildelhető és a feladatkiírásnak megfelelő kimenetet adja! Amennyiben ez nem teljesül a hallgatónak egy hete lesz a javításra az issue kiírásától számítva!

+
+

Példák

+

Példa a kis beadandóra, amit az oktatók készítettek:

+
    +
  • github.com/szepilot/sze_sw1_szinusz: A package két node-ból áll. A /gen_node színusz jelet és véletlen számokat genertál, amiket két std_msgs/float32 topicban hirdet. A /sum_node a összegzi az előállott topicokat és egy újabb std_msgs/float32 topicban hirdeti. Megvalósítás ROS 2 Humble alatt.
  • +
  • github.com/horverno/hor_d20_batman_turtle: A package egy node-ból áll, ez a turtlesim szimulátorban képes a trajektóra kirajzolásával egy "Batman logo" előállítására. A hirdetett topic geometry_msgs/twist típusú. Megvalósítás ROS 2 Humble alatt.
  • +
  • github.com/gfigneczi1/ign_b7e_array_sorter:A package egy node-ból áll. Ez az /array_sorter node feliratkozik egy std_msgs/msg/float32_multi_array típusú topicra, majd hirdeti a szintén ilyen típusú, de növekvő sorrendbe rendezett verzióját. Megvalósítás ROS 2 Humble alatt.
  • +
  • github.com/gfigneczi1/ign_b7e_temp_sens: A package két node-ból áll. A /sensor_node szimulált szenzordataokat generál: hőmérsékletet és páratartalmat, ezeket két külön sensor_msgs/Temperature és sensor_msgs/RelativeHumidity típusú topicban hirdeti. A /monitor_node ezen adatokat figyeli, és ha a hőmérséklet meghalad egy bizonyos küszöbértéket vagy a páratartalom meghalad egy másikat, egy riasztást küld egy std_msgs/String típusú topicban. Megvalósítás ROS 2 Humble alatt.
  • +
  • A package egy node-ból áll. A /minecraft_node egy visualization_msgs/Marker típusú topicot hirdet. A topicra feliratkozva egy Minecraft karaktert jeleníthetünk meg RViz2-ben. Megvalósítás ROS 2 Humble alatt.
  • +
  • github.com/umiklos/ung_isl_ajr_point_and_orientation: A package két node-ból áll. Az egyik node egy geometry_msgs/Point típust állít elő, a másik node pedig orientációval kiegészítve ebből egy geometry_msgs/Pose típusút hirdet. Megvalósítás ROS 2 Humble alatt.
  • +
  • github.com/umiklos/ung_isl_ajr_data_generation_and_control: A package két node-ból áll. Az /sensor_data_generator egy fiktív szenzorral szimulált adatokat generál, például távolságot és sebességet, ezeket két külön sensor_msgs/Range és geometry_msgs/Twist típusú topicban hirdeti. A másik node, a /control_node ezeket az adatokat figyeli és vezérlési döntéseket hoz a robot számára, amit kiír a terminalban. Megvalósítás ROS 2 Humble alatt.
  • +
  • A package két node-ból áll. Az /imu_data_publisher gyorsulásmérő és giroszkóp szenzor adatokat szolgáltat, ezeket egy sensor_msgs/Imu típusú topicban hirdeti. A másik node, a /imu_data_analyzer ezeket az IMU adatokat elemzi és jelentéseket készít a robot állapotáról egy diagnostic_msgs/DiagnosticArray típusú topicban. Megvalósítás ROS 2 Humble alatt.
  • +
+

Érdemes, de nem kötelező a diagnostic_msgs, geometry_msgs, nav_msgs, sensor_msgs, shape_msgs, std_msgs, trajectory_msgs, visualization_msgs közül választani.

+

Ajánlott módszer a kis beadandó repo létrhozására: template

+

C++ és Python nyelven is létrehoztunk egy úgynevezett template repo-t, amely megkönnyíti az első pacakage-t tartalmazó repository létrehozását:

+ +
+

Tip

+

Erről leírás itt olvasható.

+
+

+

Repo neve

+
    +
  • A repository neve a következő mintát kövesse: VVV_NNN_opcionalis, ahol
  • +
  • a VVV a vezetéknév első 3 karaktere, kisbetűvel
  • +
  • az NNN a neptunkód első 3 karaktere, kisbetűvel
  • +
  • az opcionalis pedig opcionális kiegészítés, kisbetűvel
  • +
  • a fentieket alulvonás _ karakter válassza el és kisbetű legyen mindenhol
  • +
  • Pl: Szabó István, F99AXW neptunkóddal egy véletlenszámmal foglakozó kis beadandójának url-je lehet pl: github.com/szaboistvan/sza_f99_random.
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/feleves_beadando/meme01.jpg b/feleves_beadando/meme01.jpg new file mode 100644 index 0000000..9ad6aa3 Binary files /dev/null and b/feleves_beadando/meme01.jpg differ diff --git a/feleves_beadando/meme02.jpg b/feleves_beadando/meme02.jpg new file mode 100644 index 0000000..236d907 Binary files /dev/null and b/feleves_beadando/meme02.jpg differ diff --git a/feleves_beadando/nagyfeleves/index.html b/feleves_beadando/nagyfeleves/index.html new file mode 100644 index 0000000..ddf2f6b --- /dev/null +++ b/feleves_beadando/nagyfeleves/index.html @@ -0,0 +1,2844 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Nagy féléves - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Nagy féléves

+

A nagy féléves projekt elkészítése több időt igényel, azonban lehetőség van sokkal érdekesebb feladatokat kidolgozni, ráadásul jóval több hét alatt. A félévesre alapozva, a tárgy teljesítése után akár diplomamunka, szakdolgozat, projektmunka, TDK dolgozat is készíthető, illetve van lehetőség a kötelező szakmai gyakorlat teljesítésére is.

+

Példák

+

Példa a nagy félévesre, amit az oktatók készítettek:

+
    +
  • github.com/horverno/simple_random_trees: A package egy egyszerű útvonaltervezésre használható véletlenszerű fa algoritmus. Ez a megvalósítása a vizualizációra összpontosít, nem pedig egy átfogó véletlenszerű fa-alapú útvonal tervező rendszer. A /display_tree +node egy /path_marker_topic-ot hirdet, ami visualization_msgs/marker_array típusú. A faadatstrukúrát megvalósító függvények külön header fájlban kaptak helyet. Megvalósítás ROS 2 Humble alatt.
  • +
+

Az alábbi példák nem feltétlenül féléves munkának készültek, de annak elfogadhatóak lennének:

+ +

Megjegyzés: a tárgyban az ROS 2 Humble verziót használjuk, de a féléves beadandót (indoklással) más verzióban is elfogadjuk.

+

A féléves feladatnál pozitív hatást kelt:

+
    +
  • 👍 Jól követhető magyar és/vagy angol nyelvű dokumentáció is, képekkel illusztrálva. Markdown használata.
  • +
  • 👍 Alap információk a README.md-ben, (opcionális) dokumentáció a /wiki-ben.
  • +
  • 👍 Issue-k.
  • +
  • 👍 Branch-ek.
  • +
  • 👍 Gitignore.
  • +
  • 👍 Licensz.
  • +
  • 👍 Repository topic-ok, köztük a tárgykód és a SZE. A topic-ok alapján aztán pl itt is listázódik a repository: github.com/topics/sze.
  • +
  • 👍 Plusz jegy adható, amennyiben a jelen tananyag kiegészítésre / hibajavításra kerül (temészetesen pull request által).
  • +
+

Komoly hibák, ami miatt a féléves akár több érdemjeggyel is rosszabb lehet:

+
    +
  • 😡 Tömörített állomány a GitHub repositoryban (pl. zip és még rosszabb, ha rar). Kivétel lehet, ha direkt tömörített állománykezelés a cél, de forráskód, kép, stb. soha ne kerüljön így fel.
  • +
  • 😡 Nem eredeti munka, vagy az átvett kód nincs hivatkozva.
  • +
  • 😡 Csapatban csak egy hallgató commitol. (Ez nyilván nem vonatkozis egyfős feladatokra).
  • +
  • 😡 Kevés commit. Azért lenne fontos a megfelelő számú commit, mert ebből tudjuk, megítélni, hogyan haladt előre a munkafolyamat, ki, mit és mikor dolgozott.
  • +
  • 😡 Nincs README.md, hiányzik a rövid dokumentáció vagy a képek.
  • +
  • 😡 A dokumentáció pdf / docx-ként feltöltve a /wiki helyett.
  • +
  • 😡 File upload commit helyett.
  • +
  • 😡 Forráskód kiképmetszőzve markdown szintaxis kiemelés helyett. (Mivel képként nem másolható, kereshető, stb a kód.)
  • +
+

Ötletek témaválasztáshoz

+
    +
  • Inspriráció lehet a korábbi vagy jelenlegi szakdolgozatok / diplomamunkák témái: horverno.github.io/temaajanlatok
  • +
  • Olyan témát célszerű választani, amin szívesen dolgoznál heteken/hónapokon keresztül is. Ha pl. a vizualizáció, az algoritmusok gyakorlata, a 3D vagy épp a mesterséges intelligencia vonzó, akkor ennek megfelelő témát célszerű választani.
  • +
  • Korábbi szakdolgozatok, félévesek elérhetőek, ezeket igényelni itt lehet. Fontos, hogy ezeket tilos továbbosztani, csak oktatási céllal állnak rendelkezésre.
  • +
  • Számos ROS 2 projekt itt: github.com/fkromer/awesome-ros2
  • +
+
+

Tip

+

Erősen ajánlott a GitHub Student Developer Pack beszerzése, többek között Copilot is jár hozzá. +Erről itt lehet részletesen olvasni: sze-info.github.io/ajr/bevezetes/copilot/#github-copilot-beszerzese-sze-hallgatoknak

+
+

+

Értékelési szempontok

+

A szempontok kialakításánaál az Óbudai Egyetem hasonló kurzusának értékelési szempontjait vettük alapul. +- Saját munka és fehasznált kódbázis aránya (megfelelő hivatkozások megléte) +- Értékelhető eredményeket produkáló munka +- A bemutató minősége (ppt, videók, élő demo, bármilyen plusz felhasznált eszköz) +- A megoldás teljessége +- Megfelelő ROS 2 kommunikáció / best practice alkalmazása +- A program szerkezete +- Az implementáció minősége +- A kód dokumentálása +- Konzultáció +- A választott feladat nehézsége

+

Ajánlott módszer a féléves repo létrhozására: template

+

C++ és Python nyelven is létrehoztunk egy úgynevezett template repo-t, amely megkönnyíti az első pacakage-t tartalmazó repository létrehozását:

+ +
+

Info

+

Erről leírás itt olvasható.

+
+

+

Meme

+

+

Credit: pycoders

+

+

Credit: knowyourmeme

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/a.txt b/img/a.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/img/a.txt @@ -0,0 +1 @@ + diff --git a/img/android-chrome-192x192.png b/img/android-chrome-192x192.png new file mode 100644 index 0000000..a72fa3b Binary files /dev/null and b/img/android-chrome-192x192.png differ diff --git a/img/apple-touch-icon.png b/img/apple-touch-icon.png new file mode 100644 index 0000000..4990ef3 Binary files /dev/null and b/img/apple-touch-icon.png differ diff --git a/img/bg1.png b/img/bg1.png new file mode 100644 index 0000000..1be8663 Binary files /dev/null and b/img/bg1.png differ diff --git a/img/coordinates_dataset_03.jpg b/img/coordinates_dataset_03.jpg new file mode 100644 index 0000000..3c88ed8 Binary files /dev/null and b/img/coordinates_dataset_03.jpg differ diff --git a/img/dataset01a.png b/img/dataset01a.png new file mode 100644 index 0000000..5295399 Binary files /dev/null and b/img/dataset01a.png differ diff --git a/img/dataset02A.png b/img/dataset02A.png new file mode 100644 index 0000000..fea9180 Binary files /dev/null and b/img/dataset02A.png differ diff --git a/img/dataset_03_oncoming_video.png b/img/dataset_03_oncoming_video.png new file mode 100644 index 0000000..eb12a75 Binary files /dev/null and b/img/dataset_03_oncoming_video.png differ diff --git a/img/drivers_dataset_03.png b/img/drivers_dataset_03.png new file mode 100644 index 0000000..5772819 Binary files /dev/null and b/img/drivers_dataset_03.png differ diff --git a/img/favicon-192x192.png b/img/favicon-192x192.png new file mode 100644 index 0000000..4d0a363 Binary files /dev/null and b/img/favicon-192x192.png differ diff --git a/img/favicon-32x32.png b/img/favicon-32x32.png new file mode 100644 index 0000000..4358832 Binary files /dev/null and b/img/favicon-32x32.png differ diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 0000000..0c050ca Binary files /dev/null and b/img/favicon.ico differ diff --git a/img/jkk00.svg b/img/jkk00.svg new file mode 100644 index 0000000..99a815d --- /dev/null +++ b/img/jkk00.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + diff --git a/img/jkk01.svg b/img/jkk01.svg new file mode 100644 index 0000000..24cac3f --- /dev/null +++ b/img/jkk01.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/img/jkk02.svg b/img/jkk02.svg new file mode 100644 index 0000000..795155f --- /dev/null +++ b/img/jkk02.svg @@ -0,0 +1,69 @@ + + + + + + diff --git a/img/jkk03.svg b/img/jkk03.svg new file mode 100644 index 0000000..263185a --- /dev/null +++ b/img/jkk03.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/img/jkk_dataset_02_2023_07_11-11_12.svg b/img/jkk_dataset_02_2023_07_11-11_12.svg new file mode 100644 index 0000000..1d2ee16 --- /dev/null +++ b/img/jkk_dataset_02_2023_07_11-11_12.svg @@ -0,0 +1,3803 @@ + + + + + + + + 2023-09-30T19:22:52.861111 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/jkk_dataset_02_2023_07_11-14_02.svg b/img/jkk_dataset_02_2023_07_11-14_02.svg new file mode 100644 index 0000000..9a40776 --- /dev/null +++ b/img/jkk_dataset_02_2023_07_11-14_02.svg @@ -0,0 +1,3413 @@ + + + + + + + + 2023-09-30T18:54:26.607735 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/lane_dataset_03.png b/img/lane_dataset_03.png new file mode 100644 index 0000000..43e7dd0 Binary files /dev/null and b/img/lane_dataset_03.png differ diff --git a/img/ldm1.svg b/img/ldm1.svg new file mode 100644 index 0000000..e0b5e2f --- /dev/null +++ b/img/ldm1.svg @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/leaf-2021-04-23-campus.png b/img/leaf-2021-04-23-campus.png new file mode 100644 index 0000000..cd9b10b Binary files /dev/null and b/img/leaf-2021-04-23-campus.png differ diff --git a/img/leaf-2021-07-02-zala-uni-track.png b/img/leaf-2021-07-02-zala-uni-track.png new file mode 100644 index 0000000..bba7638 Binary files /dev/null and b/img/leaf-2021-07-02-zala-uni-track.png differ diff --git a/img/leaf-2022-03-18-gyor.png b/img/leaf-2022-03-18-gyor.png new file mode 100644 index 0000000..4af5928 Binary files /dev/null and b/img/leaf-2022-03-18-gyor.png differ diff --git a/img/leaf-2022-03-26-zala-smart-city.png b/img/leaf-2022-03-26-zala-smart-city.png new file mode 100644 index 0000000..c2abc64 Binary files /dev/null and b/img/leaf-2022-03-26-zala-smart-city.png differ diff --git a/img/oncomingTraffic_dataset_03.png b/img/oncomingTraffic_dataset_03.png new file mode 100644 index 0000000..81b2a08 Binary files /dev/null and b/img/oncomingTraffic_dataset_03.png differ diff --git a/img/p1.jpg b/img/p1.jpg new file mode 100644 index 0000000..7b51c8a Binary files /dev/null and b/img/p1.jpg differ diff --git a/img/p2.jpg b/img/p2.jpg new file mode 100644 index 0000000..70e142d Binary files /dev/null and b/img/p2.jpg differ diff --git a/img/p3.jpg b/img/p3.jpg new file mode 100644 index 0000000..d3a3efe Binary files /dev/null and b/img/p3.jpg differ diff --git a/img/p4.jpg b/img/p4.jpg new file mode 100644 index 0000000..41c4de0 Binary files /dev/null and b/img/p4.jpg differ diff --git a/img/p5.jpg b/img/p5.jpg new file mode 100644 index 0000000..7c5cd44 Binary files /dev/null and b/img/p5.jpg differ diff --git a/img/p6.jpg b/img/p6.jpg new file mode 100644 index 0000000..0d85543 Binary files /dev/null and b/img/p6.jpg differ diff --git a/img/p7.jpg b/img/p7.jpg new file mode 100644 index 0000000..1d2af0b Binary files /dev/null and b/img/p7.jpg differ diff --git a/img/p8.jpg b/img/p8.jpg new file mode 100644 index 0000000..d840791 Binary files /dev/null and b/img/p8.jpg differ diff --git a/img/road61_2.png b/img/road61_2.png new file mode 100644 index 0000000..0e6628a Binary files /dev/null and b/img/road61_2.png differ diff --git a/img/road61_map.png b/img/road61_map.png new file mode 100644 index 0000000..4578282 Binary files /dev/null and b/img/road61_map.png differ diff --git a/img/road62_1.png b/img/road62_1.png new file mode 100644 index 0000000..e6d418d Binary files /dev/null and b/img/road62_1.png differ diff --git a/img/site.webmanifest b/img/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/img/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/img/sze00.svg b/img/sze00.svg new file mode 100644 index 0000000..61b55b1 --- /dev/null +++ b/img/sze00.svg @@ -0,0 +1,74 @@ + + + + + + + diff --git a/img/sze01.svg b/img/sze01.svg new file mode 100644 index 0000000..da381c0 --- /dev/null +++ b/img/sze01.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + diff --git a/img/sze02.svg b/img/sze02.svg new file mode 100644 index 0000000..103cb58 --- /dev/null +++ b/img/sze02.svg @@ -0,0 +1,53 @@ + + + + + + diff --git a/img/workshop1_a.jpg b/img/workshop1_a.jpg new file mode 100644 index 0000000..81547f9 Binary files /dev/null and b/img/workshop1_a.jpg differ diff --git a/img/workshop1_b.jpg b/img/workshop1_b.jpg new file mode 100644 index 0000000..9a4cab5 Binary files /dev/null and b/img/workshop1_b.jpg differ diff --git a/img/workshop2_a.jpg b/img/workshop2_a.jpg new file mode 100644 index 0000000..7bf7878 Binary files /dev/null and b/img/workshop2_a.jpg differ diff --git a/img/workshop2_b.jpg b/img/workshop2_b.jpg new file mode 100644 index 0000000..1bb303d Binary files /dev/null and b/img/workshop2_b.jpg differ diff --git a/img/workshop3_a.jpg b/img/workshop3_a.jpg new file mode 100644 index 0000000..123b824 Binary files /dev/null and b/img/workshop3_a.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..3e3bc8c --- /dev/null +++ b/index.html @@ -0,0 +1,2874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + +
    +
  • Tantárgy neve magyarul: Autonóm járművek és robotok programozása
  • +
  • Tantárgy neve angolul: Autonomous robots and vehicles software engineering
  • +
  • Neptun tárgykód: GKNB_AUTM078
  • +
+

A tantárgy több mérnöki szakon indul és meglévő minimális programozási tudásra épít. Járműmérnöki (BSc) szakon GKNB_INTM023 Programozás alapjai, Programtervező informatikus (BSc) GKNB_MSTM032 Python programozás, Mérnökinformatikus (BSc) szakon GKNB_INTM114 Programozás, Mechatronikai mérnök (BSc) szakon GKNB_MSTM032 Python programozás, Villamosmérnök (BSc) szakon GKNB_INTM023 Programozás alapjai előkövetleményekkel indul.

+
+

A tantárgy célja

+

A tárgy sikeres teljesítése után a hallgatók átfogó képet kapnak az önvezető (autonóm) járművek szoftver moduljairól és további lényeges összetevőiről.

+

C++ és python nyelven egyszerűbb ehhez kapcsolódó szoftvermodulokat tudnak fejleszteni. Ezen túlmenően a hallgatók képesek a megfelelő kód alkalmazására, valamint annak funkcióinak értelmezésére és továbbfejlesztésére ROS 2 keretrendszerben.

+
+

A tárgy összeállítása során olyan nemzetközileg is elismert egyetemek tananyagát vettük alapul, mint az MIT, ETH Zürich, TU München, Univerisity of Virginia vagy a Stanford University. A megfelelő licenc betarása mellett bizonyos tanangyag részeket át is vettünk, másokat inspirációként használtunk, erről részletesen itt lehet olvasni. 2023-ban a tantárgy az ROS 2 Humble verzióját használja, ez a disztribúció 2027 májusáig támogatott.

+

A tantárgy teljesítése például következő autóipari / autonóm járműves cégeknél előnyt jelenthet (ABC sorrendben):

+ +

További karrierrel kapcsolatos érdekességek például a statista-n, a glassdoor-on, linkedin-en olvashatók.

+
+

Note

+

A tárgyban bemutatott ismeretekre alapozva diplomamunka, szakdolgozat, projektmunka, TDK dolgozat is készíthető, illetve van lehetőség a kötelező szakmai gyakorlat teljesítésére is.

+
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Oktatók.
Dr. Horváth Ernő
Tárgyfelelős
github.com/horverno
Dr. Ballagi Áron
Tematika, nem oktat
github.com/aronball
Krecht Rudolf
Szimuláció, robotika
github.com/rudolfkrecht
Unger Miklós
Környezetérzékelés
github.com/umiklos
Ignéczi Gergő
Szabályozástechnika
github.com/gfigneczi1
Markó Norbert
AI, neurális hálók
github.com/norbertmarko
+

+

2024/25 őszi félévében az A2-es teremben (hétfő), illetve a B6-as gépteremben (kedd 8:30) tartunk órákat.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ÓraDátumTananyagMegj.
1szept. 9-10.Bevezetés
2szept. 16-17.ROS 2 alap, telepítés
3szept. 23-24.Érzékelés
4szept. 30-okt. 1.ROS 2 haladó
5okt. 7-8.Transzformációkokt. 13-ig kis beadandó
6okt. 14-15.Észlelés
7okt. 21.Szimuláció22-én B6 terem felújítás
8okt. 28-29.TervezésZH 1
9nov. 4-5.Szabályozás
10nov. 11-12.AI
+1nov. 19.?ZH 2?
+2-Pót ZH?
+

Elmélet

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ÓraTananyag
1Bevezetés: A tantárgy felépítése. Robotikai és önvezető járműves ismeretek. Érzékelés, észlelés, tervezés, szabályozás, aktuálás.
2ROS2 koncepciók: Egyetemi robotok és járművek ismertetése. ROS 2 alapismeretek.
3Érzékelés: Kamera, LIDAR, GNSS (GPS), IMU, CAN szenzorok működése, jelfeldolgozása, főbb ROS 2 topicok, ROS 2 időkezelés.
4Féléves beadandó: féléves beadandó ismertetése, osztályzási szempontok, ötletek, kérdések-válaszok
5Transzformációk: Merev test mozgása, mátrix szorzás ismétlése, homogén koordináták szemléltetése rövid progamkódokkal, quaternion (kvaterniók) fogalma.
6Észlelés: objektumfelismerés, objektumklasszifikáció, objektum követés és predikció, SLAM és LOAM.
7Szimuláció: ROS 2 kompatibilis szimulátorok áttekintése (pl Gazebo, Carla, SVL, OSSDC SIM, AirSim, AWSIM, CoppeliaSim, MVSim)
8Tervezés: Globális tervezés, lokális tervezés. Lokális tervezés: keresztirányú és hosszirányú tervezés.
9Szabályozás: Járműirányítási megoldások (inverz-modellek, prediktív modellek, zárhurkú modellek).
10Mesterséges intelligencia: Neurális hálózatok járműves és robotikai fókusszal.
+

Gyakorlat

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ÓraTananyag
1Bevezetés + Linux + Géptermi ismeretek: WSL2 használata Windows operációs rendszeren. Géptermi alapismeretek. Linux parancsok, amelyek szükségesek lehetnek a későbbiekben.
2Telepítés+ Fejlesztőkörnyezet beállítása + ROS2 kommunikáció: Első ROS 2 node-ok, ROS parancsok használata, build és source.
3Érzékelés gyakorlat: Szenzor adatok jellemzőbb formátumai: sensor_msgs/PointCloud2, sensor_msgs/Image, geometry_msgs/Pose, stb. Bag .mcap fájlok kezelése, lejátszása. Egyszerű pacakge készítése, amely pozíció adatokra iratkozik fel.
4Verziókezelés, Git, Copilot, vs code, ROS 2 launch: Copilot használata ROS 2 fejlesztéshez, Template repo ismertetése, használata, launch fájlok írása python nyelven
5Transzformációk gyakorlat: Node létrehozása, amely transzformációkat hirdet. Markerek megjelenítése, launch önálló feladat.
6Észlelés gyakorlat: egyszerű LIDAR szűrés, X, Y és Z koordináták szerint.
7Szimuláció bevezetés: Gazebo Fortress és ROS 2, szimuláció gyakorlat: saját robotszimuláció létrehozása.
8Tervezés gyakorlat: Polinom alapú lokális tervező megvalósításás. Nav2 használata szimulátorral.
9Szabályozás gyakorlat: PID hangolás. Trajektóriakövetés Gazebo szimulátorral. Saját fejlesztésű szabályzó és jármű modell.
10Mesterséges intelligencia gyakorlat: Neurális hálózatok gyakorlat.
+

Érdemjegy

+
    +
  • Aláírás: Kis beadandó teljesítése (egyszerű otthoni programozási feladat)
  • +
  • 1 (elégtelen): \(0\% \leq ZH_{átlag} < 60\%\)
  • +
  • 2 (elégséges): \(60\% \leq ZH_{átlag} < 85\%\)
  • +
  • 3 (közepes): \(85\% \leq ZH_{átlag} \leq 100\%\)
  • +
  • 4 (jó): Nagy féléves beadandó a megadott irányelvek mentén, nagyobb hibákkal teljesítve
  • +
  • 5 (jeles): Nagy féléves beadandó a megadott irányelvek mentén, csak néhány kisebb hibával teljesítve
  • +
+

Konvenciók

+
    +
  • gyakorlati tananyag
  • +
  • elméleti tananyag
  • +
  • kiegészítő tananyag, a teljes kép megértéséhez szükséges lehet
  • +
+

Érintett témakörök (nem a feldolgozás szerinti sorrendben)

+
    +
  • Bevezetés: Önvezető / autonóm járművek bevezetése: az aktuális helyzet, múlt és jövő. Szenzorok, aktuátorok kommunikációs technológiák. (LIDAR, radar, aktív és passzív kamera, GPS, odometria, IMU, CAN) Foxglove studio és saját mérések szemlétetésképp
  • +
  • Szoftverrendszer: Önvezető / autonóm járművek szoftverei: érzékelés, észlelés, tervezés, követés. Szimulációs technológiák, felhasználói felületek. Keretrendszerek: ROS/ROS2/MATLAB/LabVIEW szererepe, valós idejű rendszerek (FPGA, real-time operációs rendszerek).
  • +
  • Érzékelés: SLAM, objektumdetekció, objektumkövetés és előrejelzés. Padkadetekció, sávdetekció, úthibadetekció, jármű és gyalogosdetekció/követés stb. Mesterséges intelligencia (különösen neurális hálózatok) és hagyományos (pl C++ nyelven készült) algoritmusok előnyei hátrányai, fúziója.
  • +
  • Technológiai ismeretek: Linux, Git: Linux ismeretek: Terminal kezelése, Git kezelése, VS code, ROS telepítése
  • +
  • Technológiai ismeretek: ROS 2 alapok: topicok és üzenetek, MCAP (Rosbag) visszajátszása, Topicok kezelése, Topic tartalmának elérése pythonból, rviz, rqt_plot, MCAP (Rosbag) készítés. +ROS 2 ökoszisztéma és fejlesztés ROS 2 node-ok készítése pythonban és C++-ban: ROS 2 node-ok, rqt_graph, Publisher / Subscriber node pythonban, Publisher / Subscriber node C++-ban. +Első egyeztetés az egyéni projektfeladatról.
  • +
  • ROS 2 programozás:ROS szenzoradatok feldolgozása C++ node-al: ROS node-ok írása, visualization_msgs, LIDAR szenzoradatok: sensor_msgs/PointCloud2, sensor_msgs/LaserScan, stb.
  • +
  • Szimuláció és szabályzás: Szimuláció: ROS node-ok használata szimulációhoz (gazebo) F1/10, rviz, egyéni projektfeladatok véglegesítése. Tervezés blokk: trajektória tervezők típusai, kinematikai kihívások, Szabályzás blokk: járműmodellezés, szabályzók bemutatása, jármű- és aktuátorszintű szabályzás, a mozgás megvalósítása (fékrendszerek, kormányrendszerek…stb)
  • +
  • Kitekintés, doktori kutatások, egyetemi hallgatói csapatok: Nissan Leaf, Lexus és Szenergy önvezető projektek, bemutatása, kiragadott kódrészletekkel +Érzékelés: pontfelhő kezelés vagy objektum detektálás kamera alapon +Észlelés / tervezés: útvonalmeghatározás, szabad terület meghatározás, trajektória tervezés +Szabályzás: zárthurkú modellezett jármű, szabályzó építése (pl PID vagy pure pursuit)
  • +
  • Mesterséges intelligencia: Önvezető / autonóm járművek szoftverei, összefoglalás, kitekintés neurális hálózatok (mesterséges intelligencia, AI)
  • +
  • Technológiai ismeretek: ROS 2 használata, újdonságai ROS-hez képest
  • +
  • Projektmunka: Egyéni projektfeladat bemutatása
  • +
+

+




+

+

sze-info.github.io/ajr

+

+




+ + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/kalman_filter/index.html b/kalman_filter/index.html new file mode 100644 index 0000000..0ca737f --- /dev/null +++ b/kalman_filter/index.html @@ -0,0 +1,2480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Kálmán filter - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Kálmán filter

+

Kálmán Rudolf Emil (Budapest, 1930. május 19. – Gainesville, 2016. július 2.) amerikai magyar villamosmérnök, matematikus, a műszaki tudományok doktora, a Magyar Tudományos Akadémia tiszteleti tagja. Munkássága a matematikai eljárások folyamatirányítási és szabályozáselméleti alkalmazásában, az operációkutatásban jelentős, többek között a nevéhez fűződik a Kálmán-szűrő elvének kidolgozása.

+

+

Newton's Equations of Motion

+
\[ x = x_0 + v_{x0} * t + \frac{1}{2}a_x * t^2 \]
+
\[ y = y_0 + v_{y0} * t + \frac{1}{2}a_y * t^2 \]
+

State Transition (no control input)

+
\[x_{k+1} = \begin{bmatrix}1 & 0 & \Delta t & 0 & \frac{1}{2}\Delta t^2 & 0 \\ 0 & 1 & 0 & \Delta t & 0 & \frac{1}{2}\Delta t^2 \\ 0 & 0 & 1 & 0 & \Delta t & 0 \\ 0 & 0 & 0 & 1 & 0 & \Delta t \\ 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1\end{bmatrix} \cdot \begin{bmatrix} x \\ y \\ \dot x \\ \dot y \\ \ddot x \\ \ddot y\end{bmatrix}_{k}\]
+
\[y = H \cdot x\]
+

Acceleration (IMU) and position (GNSS) (x˙˙, y˙˙, x, y) sensors are used.

+
\[y = \begin{bmatrix}0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 \end{bmatrix} \cdot x\]
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/kalman_filter/practice/index.html b/kalman_filter/practice/index.html new file mode 100644 index 0000000..779bd5a --- /dev/null +++ b/kalman_filter/practice/index.html @@ -0,0 +1,2863 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Kálmán filter - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Gyakorlat

+

GitHub link

+

Import

+
import numpy as np
+import matplotlib.pyplot as plt
+from scipy.stats import norm
+%matplotlib inline
+plt.rcParams["figure.figsize"] = [16, 9]
+plt.rc("xtick", labelsize=20)
+plt.rc("ytick", labelsize=20)
+
+

Kalman Filter for Constant Acceleration Model

+

Kalman Filter Step

+

State Vector - Constant Acceleration

+

Constant Acceleration Model for Ego Motion in Plane

+
\[x_{k+1} = A \cdot x_{k} + B \cdot u\]
+

Newton's Equations of Motion

+

$$ x = x_0 + v_{x0} * t + \frac{1}{2}a_x * t^2 $$ +

+
\[ y = y_0 + v_{y0} * t + \frac{1}{2}a_y * t^2 \]
+

State Transition (no control input)

+
\[x_{k+1} = \begin{bmatrix}1 & 0 & \Delta t & 0 & \frac{1}{2}\Delta t^2 & 0 \\ 0 & 1 & 0 & \Delta t & 0 & \frac{1}{2}\Delta t^2 \\ 0 & 0 & 1 & 0 & \Delta t & 0 \\ 0 & 0 & 0 & 1 & 0 & \Delta t \\ 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1\end{bmatrix} \cdot \begin{bmatrix} x \\ y \\ \dot x \\ \dot y \\ \ddot x \\ \ddot y\end{bmatrix}_{k}\]
+
\[y = H \cdot x\]
+

Acceleration (IMU) and position (GNSS) (\(\ddot x\), \(\ddot y\), \(x\), \(y\)) sensors are used.

+
\[y = \begin{bmatrix}0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 \end{bmatrix} \cdot x\]
+

Initial State

+
plt.figure(figsize=(18, 10))
+x = np.matrix([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]).T
+n = x.size  # States
+plt.scatter(float(x[0]), float(x[1]), s=100)
+plt.title("Initial Location", fontsize=20)
+plt.ylabel("y in m", fontsize=20)
+plt.xlabel("x in m", fontsize=20)
+plt.grid(True)
+#### Initial Uncertainty
+P = np.matrix(
+    [
+        [10.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+        [0.0, 10.0, 0.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 10.0, 0.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 10.0, 0.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0, 10.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0, 0.0, 10.0],
+    ]
+)
+print(P)
+
+fig = plt.figure(figsize=(6, 6))
+im = plt.imshow(P, interpolation="none", cmap=plt.get_cmap("binary"))
+plt.title("Initial Covariance Matrix $P$")
+ylocs, ylabels = plt.yticks()
+# set the locations of the yticks
+plt.yticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.yticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+xlocs, xlabels = plt.xticks()
+# set the locations of the yticks
+plt.xticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.xticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+plt.xlim([-0.5, 5.5])
+plt.ylim([5.5, -0.5])
+
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+
+divider = make_axes_locatable(plt.gca())
+cax = divider.append_axes("right", "5%", pad="3%")
+plt.colorbar(im, cax=cax)
+
+plt.tight_layout()
+
+

Dynamic Matrix

+

It is calculated from the dynamics of the Egomotion.

+

\(\(x_{k+1} = x_{k} + \dot x_{k} \cdot \Delta t + \ddot x_k \cdot \frac{1}{2}\Delta t^2\)\) +

+
\[y_{k+1} = y_{k} + \dot y_{k} \cdot \Delta t + \ddot y_k \cdot \frac{1}{2}\Delta t^2\]
+

\(\(\dot x_{k+1} = \dot x_{k} + \ddot x \cdot \Delta t\)\) +

+
\[\dot y_{k+1} = \dot y_{k} + \ddot y \cdot \Delta t\]
+

\(\(\ddot x_{k+1} = \ddot x_{k}\)\) +

+
\[\ddot y_{k+1} = \ddot y_{k}\]
+
dt = 0.1  # Time Step between Filter Steps
+
+A = np.matrix(
+    [
+        [1.0, 0.0, dt, 0.0, 1 / 2.0 * dt ** 2, 0.0],
+        [0.0, 1.0, 0.0, dt, 0.0, 1 / 2.0 * dt ** 2],
+        [0.0, 0.0, 1.0, 0.0, dt, 0.0],
+        [0.0, 0.0, 0.0, 1.0, 0.0, dt],
+        [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
+    ]
+)
+print(A)
+## Measurement Matrix
+This matrix determines how the sensor measurements map to the vehicle state. In this example, the position and the accelerations are measured ($x$, $y$, $\ddot x$, $\ddot y$).
+H = np.matrix(
+    [
+        [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
+        [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
+        [1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
+        [0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
+    ]
+)
+print(H)
+## Measurement Noise Covariance
+ra = 10.0 ** 2
+rp = 2.0 ** 2
+
+R = np.matrix(
+    [[ra, 0.0, 0.0, 0.0], [0.0, ra, 0.0, 0.0], [0.0, 0.0, rp, 0.0], [0.0, 0.0, 0.0, rp]]
+)
+print(R)
+
+

Process Noise Covariance Matrix Q for CA Model

+

The Position of an object can be influenced by a force (e.g. wind), which leads to an acceleration disturbance (noise). This process noise has to be modeled with the process noise covariance matrix Q.

+
\[Q = \begin{bmatrix} + \sigma_{x}^2 & 0 & \sigma_{x \dot x} & 0 & \sigma_{x \ddot x} & 0 \\ + 0 & \sigma_{y}^2 & 0 & \sigma_{y \dot y} & 0 & \sigma_{y \ddot y} \\ + \sigma_{\dot x x} & 0 & \sigma_{\dot x}^2 & 0 & \sigma_{\dot x \ddot x} & 0 \\ + 0 & \sigma_{\dot y y} & 0 & \sigma_{\dot y}^2 & 0 & \sigma_{\dot y \ddot y} \\ + \sigma_{\ddot x x} & 0 & \sigma_{\ddot x \dot x} & 0 & \sigma_{\ddot x}^2 & 0 \\ + 0 & \sigma_{\ddot y y} & 0 & \sigma_{\ddot y \dot y} & 0 & \sigma_{\ddot y}^2 + \end{bmatrix} \cdot \sigma_{j}\]
+

Symbolic Calculation

+
from sympy import Symbol, Matrix
+from sympy.interactive import printing
+
+dts = Symbol("\Delta t")
+sj = 0.1
+
+Q = (
+    np.matrix(
+        [
+            [(dt ** 6) / 36, 0, (dt ** 5) / 12, 0, (dt ** 4) / 6, 0],
+            [0, (dt ** 6) / 36, 0, (dt ** 5) / 12, 0, (dt ** 4) / 6],
+            [(dt ** 5) / 12, 0, (dt ** 4) / 4, 0, (dt ** 3) / 2, 0],
+            [0, (dt ** 5) / 12, 0, (dt ** 4) / 4, 0, (dt ** 3) / 2],
+            [(dt ** 4) / 6, 0, (dt ** 3) / 2, 0, (dt ** 2), 0],
+            [0, (dt ** 4) / 6, 0, (dt ** 3) / 2, 0, (dt ** 2)],
+        ]
+    )
+    * sj ** 2
+)
+
+print(Q)
+fig = plt.figure(figsize=(6, 6))
+im = plt.imshow(Q, interpolation="none", cmap=plt.get_cmap("binary"))
+plt.title("Process Noise Covariance Matrix $Q$")
+ylocs, ylabels = plt.yticks()
+# set the locations of the yticks
+plt.yticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.yticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+xlocs, xlabels = plt.xticks()
+# set the locations of the yticks
+plt.xticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.xticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+plt.xlim([-0.5, 5.5])
+plt.ylim([5.5, -0.5])
+
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+
+divider = make_axes_locatable(plt.gca())
+cax = divider.append_axes("right", "5%", pad="3%")
+plt.colorbar(im, cax=cax)
+
+plt.tight_layout()
+## Identity Matrix
+I = np.eye(n)
+## Measurement
+import pandas as pd
+from pyproj import Proj
+
+# Read data
+
+# Use every 5th value to get GPS updates in every timestep
+n_rows = 10800  # len(df)
+skip = np.arange(n_rows)
+skip = np.delete(skip, np.arange(0, n_rows, 5))
+df = pd.read_csv("data/2014-03-26-000-Data.csv", skiprows=skip)
+
+# Extract values
+ax = df["ax"].dropna()
+ay = df["ay"].dropna()
+px = df["latitude"].dropna()
+py = df["longitude"].dropna()
+
+m = len(df["ax"])  # Measurements
+
+# Lat Lon to UTM
+utm_converter = Proj(
+    "+proj=utm +zone=33U, +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
+)
+
+for i in range(len(px)):
+    py[i], px[i] = utm_converter(py[i], px[i])
+    px[i] = px[i] + np.random.normal(0, 2.0, 1)
+    py[i] = py[i] + np.random.normal(0, 2.0, 1)
+    # px[i] = 0 #TODO
+    # py[i] = 0 #TODO
+
+# Start from position (0 ,0)
+py_offset = py[0]
+px_offset = px[0]
+px = px - px_offset
+py = py - py_offset
+
+# Stack measurement vector
+measurements = np.vstack((ax, ay, px, py))
+fig = plt.figure(figsize=(16, 9))
+plt.step(range(m), ax, label="$a_x$")
+plt.step(range(m), ay, label="$a_y$")
+plt.ylabel("Acceleration in m / $s^2$", fontsize=20)
+plt.xlabel("Number of measurements", fontsize=20)
+plt.title("IMU Measurements", fontsize=20)
+plt.ylim([-20, 20])
+plt.legend(loc="best", prop={"size": 18})
+fig = plt.figure(figsize=(16, 9))
+plt.step(px, py, label="$GNSS$")
+plt.xlabel("x in m", fontsize=20)
+plt.ylabel("y in m", fontsize=20)
+plt.title("GNSS Measurements", fontsize=20)
+plt.xlim([min(px), max(px)])
+plt.ylim([min(py), max(py)])
+plt.legend(loc="best", prop={"size": 18})
+# Preallocation for Plotting
+xt = []
+yt = []
+dxt = []
+dyt = []
+ddxt = []
+ddyt = []
+Zx = []
+Zy = []
+Px = []
+Py = []
+Pdx = []
+Pdy = []
+Pddx = []
+Pddy = []
+Kx = []
+Ky = []
+Kdx = []
+Kdy = []
+Kddx = []
+Kddy = []
+
+

Kalman Filter

+

Kalman Filter Step +

for n in range(m):
+
+    # Time Update (Prediction)
+    # ========================
+    # Project the state ahead
+    x = A * x
+
+    # Project the error covariance ahead
+    P = A * P * A.T + Q
+
+    # Measurement Update (Correction)
+    # ===============================
+    # Compute the Kalman Gain
+    S = H * P * H.T + R
+    K = (P * H.T) * np.linalg.pinv(S)
+
+    # Update the estimate via z
+    Z = measurements[:, n].reshape(H.shape[0], 1)
+    y = Z - (H * x)  # Innovation or Residual
+    x = x + (K * y)
+
+    # Update the error covariance
+    P = (I - (K * H)) * P
+
+    # Save states for Plotting
+    xt.append(float(x[0]))
+    yt.append(float(x[1]))
+    dxt.append(float(x[2]))
+    dyt.append(float(x[3]))
+    ddxt.append(float(x[4]))
+    ddyt.append(float(x[5]))
+    Zx.append(float(Z[0]))
+    Zy.append(float(Z[1]))
+    Px.append(float(P[0, 0]))
+    Py.append(float(P[1, 1]))
+    Pdx.append(float(P[2, 2]))
+    Pdy.append(float(P[3, 3]))
+    Pddx.append(float(P[4, 4]))
+    Pddy.append(float(P[5, 5]))
+    Kx.append(float(K[0, 0]))
+    Ky.append(float(K[1, 0]))
+    Kdx.append(float(K[2, 0]))
+    Kdy.append(float(K[3, 0]))
+    Kddx.append(float(K[4, 0]))
+    Kddy.append(float(K[5, 0]))
+## Plots
+### Covariance Matrix
+fig = plt.figure(figsize=(6, 6))
+im = plt.imshow(P, interpolation="none", cmap=plt.get_cmap("binary"))
+plt.title("Covariance Matrix $P$ (after %i Filter Steps)" % (m), fontsize=20)
+ylocs, ylabels = plt.yticks()
+# set the locations of the yticks
+plt.yticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.yticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+xlocs, xlabels = plt.xticks()
+# set the locations of the yticks
+plt.xticks(np.arange(7))
+# set the locations and labels of the yticks
+plt.xticks(
+    np.arange(6),
+    ("$x$", "$y$", "$\dot x$", "$\dot y$", "$\ddot x$", "$\ddot y$"),
+    fontsize=22,
+)
+
+plt.xlim([-0.5, 5.5])
+plt.ylim([5.5, -0.5])
+
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+
+divider = make_axes_locatable(plt.gca())
+cax = divider.append_axes("right", "5%", pad="3%")
+plt.colorbar(im, cax=cax)
+
+
+plt.tight_layout()
+## State Vector
+fig = plt.figure(figsize=(16, 12))
+
+plt.subplot(311)
+plt.step(range(len(measurements[0])), ddxt, label="$\ddot x$")
+plt.step(range(len(measurements[0])), ddyt, label="$\ddot y$")
+
+plt.title("Estimate (Elements from State Vector $x$)", fontsize=20)
+plt.legend(loc="best", prop={"size": 22})
+plt.ylabel("Acceleration in m/ $s^2$", fontsize=20)
+
+plt.subplot(312)
+plt.step(range(len(measurements[0])), dxt, label="$\dot x$")
+plt.step(range(len(measurements[0])), dyt, label="$\dot y$")
+
+plt.ylabel("")
+plt.legend(loc="best", prop={"size": 22})
+plt.ylabel("Velocity in m/s", fontsize=20)
+
+plt.subplot(313)
+plt.step(range(len(measurements[0])), xt, label="$x$")
+plt.step(range(len(measurements[0])), yt, label="$y$")
+
+plt.xlabel("Filter Step", fontsize=20)
+plt.ylabel("Position in m", fontsize=20)
+plt.legend(loc="best", prop={"size": 22})
+## Position x/y
+fig = plt.figure(figsize=(16, 9))
+
+plt.step(px, py, label="$GNSS$")
+
+plt.scatter(xt[0], yt[0], s=100, label="Start", c="g")
+plt.scatter(xt[-1], yt[-1], s=100, label="Goal", c="r")
+plt.plot(xt, yt, label="State", alpha=0.5)
+plt.xlabel("x in m", fontsize=20)
+plt.ylabel("y in m", fontsize=20)
+plt.title("Position", fontsize=20)
+plt.legend(loc="best", fontsize=20)
+plt.xlim(min(xt), max(xt))
+plt.ylim(min(yt), max(yt))
+

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/kalman_filter/rudolf-kalman.jpg b/kalman_filter/rudolf-kalman.jpg new file mode 100644 index 0000000..f90fe6e Binary files /dev/null and b/kalman_filter/rudolf-kalman.jpg differ diff --git a/linkek/index.html b/linkek/index.html new file mode 100644 index 0000000..b9b96c2 --- /dev/null +++ b/linkek/index.html @@ -0,0 +1,3106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Linkek - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + +

Linkek

+

Linux ismeretek

+ + +
    +
  • Egyszerű linux parancsok - [hun]
  • +
  • ROS training - 0.1 Intro to Ubuntu GUI - [eng]
  • +
  • ROS training - 0.2 The Linux File System - [eng]
  • +
  • ROS training - 0.3 Using the Terminal - [eng]
  • +
  • Terminal kezelése - [hun]
  • +
  • 60 Linux Commands you need to know [video, eng]
  • +
  • The 50 Most Popular Linux & Terminal Commands, freeCodeCamp [video, eng]
  • +
  • Raspberry Pi-hez készült segédanyag: [hun]
  • +
  • Git kezelése:
  • +
  • Beadandó leírás, Git és GitHub - [hun]
  • +
  • GitHub first-contributions magyar fordítás - [hun]
  • +
  • GitHub Learning Lab - [eng]
  • +
  • VS code - [hun], [vid]
  • +
  • Python [hun]
  • +
  • Python freeCodeCamp video [eng]
  • +
  • Python 60 days with python videos [eng]
  • +
  • C++ [hun]
  • +
  • C++ Optimizations Diary [eng]
  • +
  • C++ Code for yourself videos [eng]
  • +
+

Robotikai ismeretek

+
    +
  • Alap robotikai ismeretek [eng]
  • +
  • Kálmán filter [eng]
  • +
  • Universitat Politècnica de Catalunya BarcelonaTech (UPC) - [eng]
  • +
  • Pozna Tanár Úr és Antonya Csaba által írt angol nyelvű oktatóanyag - Autocarsim [eng]
  • +
+

Stanford University

+ + + +

TU München

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NumberSessionDescriptionVideoLecture Slides
1Python introSome basics of programming in python for beginners. ResearchGate
2Basics of mapping and localizationExemplary implementation of a Kalman filter and application for localization via GNSS-signal.YouTubeResearchGate
3SLAMThe google cartographer SLAM algorithm is applied to data from the KITTI-dataset. Note, that this lecture is held in Linux and has its own dependencies, please refer to the local readme.YouTubeResearchGate
4DetectionOverview about the YOLO-approach from network architecture to exemplary usage.YouTubeResearchGate
5PredictionImplementation of the pipeline to setup a motion prediction algorithm based on a Encoder-Decoder architecture.YouTubeResearchGate
6Global planningsA global optimal race line optimization is shown. This lecture has its own dependencies, please refer to the local readme.YouTubeResearchGate
7Local planningA local planning algorithm based on a graph-based approach is presented.YouTubeResearchGate
8ControlThe design of a velocity controller and numerical solver for differential equation are covered.YouTubeResearchGate
9Safety assessmentThe evaluation of the criticality of planned trajectories based on various metrics and their sensitivity is discussed.YouTubeResearchGate
10Teleoperated drivingHow to send and receive data via MQTT over network is shown in this practice session.YouTubeResearchGate
11End-to-EndThe exemplary pipeline of data collection from expert demonstration, training and application are treated in this session. This lecture has its own dependencies, please refer to the localYouTubeResearchGate
+ + +

Magyar nyelvű ROS oktatóanyagok

+ +

Angol nyelvű ROS oktatóanyagok

+ +

Apex AI

+ + + +

ETH Zürich

+ + + +
2021
Topics
Material
22.02.
    +
  • ROS architecture & philosophy
  • +
  • ROS master, nodes, and topics
  • +
  • Console commands
  • +
  • Catkin workspace and build system
  • +
  • Launch-files
  • +
  • Gazebo simulator
  • +
  • Programming Tools
  • +
24.02.
    +
  • ROS package structure
  • +
  • Integration and programming with Eclipse
  • +
  • ROS C++ client library (roscpp)
  • +
  • ROS subscribers and publishers
  • +
  • ROS parameter server
  • +
  • RViz visualization
  • +
26.02.
    +
  • TF Transformation System
  • +
  • rqt User Interface
  • +
  • Robot models (URDF)
  • +
  • Simulation descriptions (SDF)
  • +
01.03.
    +
  • ROS services
  • +
  • ROS actions (actionlib)
  • +
  • ROS time
  • +
  • ROS bags
  • +
  • Debugging strategies
  • +
  • Introduction to ROS2
  • +
05.03.
    +
  • Case study: Using ROS in complex real-world applications
  • +
+
+ 2021: +
+ +
+ 2020: +
+ +
+ 2018: +
+ 2017: +
+ +

University of Bonn

+

Link: ipb.uni-bonn.de/sdc-2021

+

Self-Driving Cars: An Introduction (Cyrill Stachniss) +Introduction lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi.

+ + +

Self-Driving Cars: Localization (Daniel Wilbers) +Localization lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. Further Information on Deep Learning and CNNs, see our Machine Learning for Robotics and Computer Vision Course: Youtube Link

+

Self-Driving Cars: Control (Nived Chebrolu) +Control lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

+

Model Predictive Control – Part 1: Introduction to MPC (Lasse Peters) +Introduction to Model Predictive Control; lecture presented by Lasse Peters. Youtube Link

+

Model Predictive Control – Part 2: Numerical Methods for MPC (Lasse Peters) +Numerical Methods for Model Predictive Control; lecture presented by Lasse Peters. Youtube Link

+

Self-Driving Cars: Planning (Benedikt Mersch) +Planning lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

+

Self-Driving Cars: Behavior Estimation (Benedikt Mersch) +Behavior estimation lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi, Lasse Peters. Youtube Link

+

Self-Driving Cars: Perception – Part 1 (Jens Behley) +Youtube Link +Perception lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. +Further Information on Deep Learning and CNNs, see our Machine Learning for Robotics and Computer Vision Course: +Youtube playlist

+

Self-Driving Cars: Perception – Part 2 (Jens Behley) +Perception lecture for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. Youtube Link

+

Self-Driving Cars: View from Practice (Igor Bogoslavskyi) +Lecture giving a view from practice for the course “Techniques for Self-Driving Cars” taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

+

Articulated Robotics

+

ROS 2

+ + + +

The Robotics Back-End

+

ROS 2

+ +

Foxglove ROS 2 tutorials

+ +

Official ROS 2 documentation

+ +

Egyéb

+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mesterseges_intelligencia/ai01.png b/mesterseges_intelligencia/ai01.png new file mode 100644 index 0000000..bff016b Binary files /dev/null and b/mesterseges_intelligencia/ai01.png differ diff --git a/mesterseges_intelligencia/ai02.png b/mesterseges_intelligencia/ai02.png new file mode 100644 index 0000000..aa7d8c9 Binary files /dev/null and b/mesterseges_intelligencia/ai02.png differ diff --git a/mesterseges_intelligencia/assets/arj-ai.pptx b/mesterseges_intelligencia/assets/arj-ai.pptx new file mode 100644 index 0000000..054f1bb Binary files /dev/null and b/mesterseges_intelligencia/assets/arj-ai.pptx differ diff --git a/mesterseges_intelligencia/index.html b/mesterseges_intelligencia/index.html new file mode 100644 index 0000000..6900096 --- /dev/null +++ b/mesterseges_intelligencia/index.html @@ -0,0 +1,2482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Mesterséges intelligencia - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Mesterséges intelligencia

+

Az AI az észlelés mellett akár a tervezésnél vagy a szabályozásnál is megjelenhet.

+

+

Bár legfontosabb autonóm alkamazási köre az észlelés, ahogy a fenti ábrán is látszik: tervezési illetve szabályozási felhasználása is van.

+

A mesterséges intelligencia (AI) órai prezentáció itt található meg: Link

+

Példa videók:

+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mesterseges_intelligencia/practice/index.html b/mesterseges_intelligencia/practice/index.html new file mode 100644 index 0000000..0950990 --- /dev/null +++ b/mesterseges_intelligencia/practice/index.html @@ -0,0 +1,2638 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Mesterséges intelligencia - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Mesterséges intelligencia gyakorlat

+

Gyakorlati anyag letöltése

+

A gyakorlati anyag frissítéséhez adjuk ki a következő parancsokat:

+

cd ~/ros2_ws/src/arj_packages
+
+
git checkout -- .
+
+
git pull
+

+

Conda környezet telepítése

+

Az anaconda (miniconda) egy izolált virtuális környezetet biztosít, ahol az éppen aktuális munkához szükséges verziószámú Python csomagokat tudjuk telepíteni.

+

mkdir -p ~/miniconda3
+
+
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
+
+
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
+
+
rm -rf ~/miniconda3/miniconda.sh
+
+
~/miniconda3/bin/conda init bash
+

+

A solver hangolja össze a verziókat az előre definiált környezethez (environment.yml) szükséges csomagok között. A libmamba-solver az alapértelmezetthez solverhez képest egy gyorsabb hangolást tesz lehetővé. +

source ~/.bashrc
+
+
conda config --set auto_activate_base false
+
+
conda update -n base conda
+
+
conda install -n base conda-libmamba-solver
+
+
conda config --set solver libmamba
+

+

Miután a Conda települt, létrehozzuk a saját virtuális környezetünket: +

cd ~/ros2_ws/src/arj_packages/arj_ai
+
+
conda env create -f environment.yml
+

+

Gyakorlat megnyitása

+

Az anyag a következőképpen nyitható meg: +

conda activate gyakorlat
+
+
cd ~/ros2_ws/src/arj_packages/arj_ai 
+
+
code .
+

+

+

Válassszuk ki a környezetet:

+

+

Hibaelhárítás

+

TODO

+
ImportError                               Traceback (most recent call last)
+Cell In[1], line 10
+      8 import matplotlib.patches as patches
+      9 import matplotlib.pyplot as plt
+---> 10 import torch
+     11 import torchvision.transforms as transforms
+     12 from PIL import Image
+
+File ~/miniconda3/envs/gyakorlat/lib/python3.8/site-packages/torch/__init__.py:189
+    187     if USE_GLOBAL_DEPS:
+    188         _load_global_deps()
+--> 189     from torch._C import *
+    191 # Appease the type checker; ordinarily this binding is inserted by the
+    192 # torch._C module initialization code in C
+    193 if False:
+
+ImportError: /home/he/miniconda3/envs/gyakorlat/lib/python3.8/site-packages/torch/lib/libtorch_cpu.so: undefined symbol: iJIT_IsProfilingActive
+
+

Conda deaktiválás

+
conda deactivate
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/bashalias/index.html b/onallo/bashalias/index.html new file mode 100644 index 0000000..d10cada --- /dev/null +++ b/onallo/bashalias/index.html @@ -0,0 +1,2487 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bash aliases - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Bash aliases

+

A .bash_aliases egy konfigurációs fájl a Bash számára, amely lehetővé teszi aliasok (parancs átnevezések/alternatívák) létrehozását és egyéni parancsok definiálását. Az aliasok használatával rövidítheted a gyakran használt parancsokat, vagy megadhatsz olyan parancsokat, amelyeket gyakran szeretnél ugyanúgy futtatni, de hosszabb vagy bonyolultabb paraméterekkel.

+

Arra jó, hogy pl. a gyakran használt source ~/ros2_ws/install/setup.bash parancsot az r2 rövidítéssel futtathatod.

+

Nézzük meg mi található jelenleg a .bash_aliases fájlban:

+
cat ~/.bash_aliases
+
+

Az előretelepített verzókban hasonló tartalom fogad:

+
# some more ls aliases for JKK, Szenergy and friends
+alias r2='source ~/ros2_ws/install/setup.bash && echo "source ~/ros2_ws/install/setup.bash"'
+alias aw='source ~/autoware/install/setup.bash && echo "source ~/autoware/install/setup.bash"'
+alias r1='screen -mdS roscore1 bash -c 'roscore' && echo "screen roscore1"'
+
+

Ha nincs ilyen fájl, akkor hozzuk létre és töltsük le a fenti tartalmat:

+
cd ~; wget https://raw.githubusercontent.com/jkk-research/jkk_utils/ros2/.bash_aliases
+
+

Ha van ilyen fájl, de szeretnéd frissíteni, akkor töröld és töltsd le újra:

+
cd ~; rm .bash_aliases; wget https://raw.githubusercontent.com/jkk-research/jkk_utils/ros2/.bash_aliases
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/create_repo01.png b/onallo/create_repo01.png new file mode 100644 index 0000000..46852db Binary files /dev/null and b/onallo/create_repo01.png differ diff --git a/onallo/git_pull01.png b/onallo/git_pull01.png new file mode 100644 index 0000000..e229593 Binary files /dev/null and b/onallo/git_pull01.png differ diff --git a/onallo/git_push01.png b/onallo/git_push01.png new file mode 100644 index 0000000..d5d3542 Binary files /dev/null and b/onallo/git_push01.png differ diff --git a/onallo/git_status01.png b/onallo/git_status01.png new file mode 100644 index 0000000..f0430f6 Binary files /dev/null and b/onallo/git_status01.png differ diff --git a/onallo/git_status02.png b/onallo/git_status02.png new file mode 100644 index 0000000..637aaed Binary files /dev/null and b/onallo/git_status02.png differ diff --git a/onallo/git_status03.png b/onallo/git_status03.png new file mode 100644 index 0000000..0de2ef8 Binary files /dev/null and b/onallo/git_status03.png differ diff --git a/onallo/index.html b/onallo/index.html new file mode 100644 index 0000000..818f5a5 --- /dev/null +++ b/onallo/index.html @@ -0,0 +1,2449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Önálló feladatok - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Önálló feladatok, otthoni gyakorlás

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/joy1.gif b/onallo/joy1.gif new file mode 100644 index 0000000..c379a00 Binary files /dev/null and b/onallo/joy1.gif differ diff --git a/onallo/joystick/index.html b/onallo/joystick/index.html new file mode 100644 index 0000000..da63294 --- /dev/null +++ b/onallo/joystick/index.html @@ -0,0 +1,2580 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Joystick - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Joystick bevezetés

+

Todo

+

Joystick WSL alatt

+

Töltsük le a foxe extension-t Foxglove Studio-hoz, majd drag and drop módszerrel húzzuk bele a foxglove-joystick csomagot.

+

Letölthető a github.com/joshnewans/foxglove-joystick/releases GitHub oldalról.

+
ros2 topic echo /joy --csv
+
+

alt text

+

Josytick Linux alatt

+
$ lsusb
+Bus 001 Device 004: ID 046d:c219 Logitech, Inc. Cordless RumblePad 2
+$ ls -l /dev/input/js0 
+$ sudo chmod a+rw /dev/input/js0
+
+
ros2 topic echo /joy
+
+

ROS 2 joy package

+
sudo apt install ros-humble-joy
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/linux/index.html b/onallo/linux/index.html new file mode 100644 index 0000000..03de1e2 --- /dev/null +++ b/onallo/linux/index.html @@ -0,0 +1,2652 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linux - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Linux gyakorlás

+

Mapparendszer létrehozása - terminal

+

A feladathoz telepítsük a tree parancsot: +

sudo apt install tree
+

+

A feladathoz megoldásához touch, chmod, mkdir parancsok kellenek.

+

Hozzuk létre a következő mapparendszert, ami a cd ~ && tree tmp_dir/ parancsra a következőképp néz ki:

+
~/tmp_dir/
+├── animals
+│   ├── cat
+│   └── dog
+│       ├── komondor
+│       ├── puli
+│       └── vizsla
+├── colors
+│   ├── blue
+│   ├── green
+│   └── red
+├── py_exec.py
+├── simple_text.txt
+└── top
+    └── middle
+        └── bottom
+            └── hello.txt
+13 directories, 3 files
+
+

Az ls -l ~/tmp_dir/ parancsra pedig a következőhöz hasonló rwx értékeket mutatja:

+
drwxr-xr-x 4 he he 4096 Feb 17 14:54 animals
+drwxr-xr-x 5 he he 4096 Feb 17 14:55 colors
+-rwxrwxrwx 1 he he    0 Feb 17 14:52 py_exec.py
+-rw-r--r-- 1 he he    0 Feb 17 14:53 simple_text.txt
+drwxr-xr-x 3 he he 4096 Feb 17 14:43 top
+
+

Megoldás segédlet

+
mkdir -p top/middle/bottom
+mkdir -p colors/{red,green,blue}
+mkdir -p animals/{cat,dog/{vizsla,puli,komondor}}
+
+

Szöveges fájlok

+

Ha még nem hozuk létre, akkor készítsünk egy ~/tmp_text/ mappát.

+

A mappán belül készítsünk egy hello.py fájlt, majd terminálból töltsük fel a következő tartalommal:

+
import sys
+print('\nHello vilag!\nA verzio pedig:\n' + sys.version)
+
+

Tegyük futtathatóvá és futtassuk.

+

Megoldás segédlet

+
echo "import sys" >> hello.py
+echo "print('\nHello vilag!\nA verzio pedig:\n' + sys.version)" >> hello.py
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/mermaid/index.html b/onallo/mermaid/index.html new file mode 100644 index 0000000..21110d6 --- /dev/null +++ b/onallo/mermaid/index.html @@ -0,0 +1,2791 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mermaid gráf - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Mermaid gyakorlás

+

A mermaid hasznos kiegészője lehet a markdown fájlainknak (pl README.md). Különböző grafikononokat, flowchartokat tudunk vele viszonylag könnyen létrehozni.

+

VS code extension

+

Bal oldalt az Extension ikonra kattintva vagy a Ctrl + Shift + X után a meraid kulcsszót beírva előjön a Markdown Preview kiegészítő, ez egy katintással telepíthető és használhat is. Ezután a Markdown előnézetében (Ctrl + Shift + V vagy felső ikon) már látható is lesz az előlnézet.

+
+ Image title +
Mermaid, VS code extension
+
+
+ Image title +
Mermaid, VS code
+
+

Célszerű a Mermaid Markdown Syntax Highlighting és a Color Highlight extension-t is használni, ekkor a következőképp jelenik meg a gráf kódja:

+
+ Image title +
Mermaid, VS code highlight
+
+

Példák

+

Egyszerű példa

+

Ay egyik legegyszerűbb flowchart kódja következő 2 sorból áll:

+
graph LR;
+node1 --> topic --> node2
+
+

Az első sor a gráf típusa, a második (vagy további) sorokban a kapcsolatokat --> a nyilak definiálják.

+
graph LR;
+node1 --> topic --> node2
+

Téglalap helyett formákkal

+

Az LR a left-right rövidítése. A formák lehetnek lekerekítettek ([ ]), szögletesek [ ], hexagonok {{ }} paralellogrammák [/ /] és továbbiak is. ROS-ben megtanultuk, hogy a node lekerekített, míg a topic szögletes. Az azonosítókat itt pl: id1, id2, id3 a zárójel elé lehet írni. A kapcsolatkoat vagy külön sorban (mint itt) vagy egy sorban (későbbi példa) is definiálhatjuk.

+
graph LR;
+id1([node1])
+id2([node2])
+id3[topic]
+
+id1 --> id3 --> id2
+
+
graph LR;
+id1([node1])
+id2([node2])
+id3[topic]
+
+id1 --> id3 --> id2
+

Balról jobbra helyett fentről lefele

+

Az TD a top-down rövidítése:

+
graph TD;
+id1([node1])
+id2([node2])
+id3[topic]
+
+id1 --> id3 --> id2
+
+
graph TD;
+id1([node1])
+id2([node2])
+id3[topic]
+
+id1 --> id3 --> id2
+

Színek használata

+

classDef segítségével színeket, vonalakat, definálhatunk, majd 3 db kettőspont után ::: azonosíthatjuk a megfelelő osztályhoz:

+
graph TD;
+id1([node1]):::red
+id2([node2]):::red
+id3[topic]:::light
+
+id1 --> id3 --> id2
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+
graph TD;
+id1([node1]):::red
+id2([node2]):::red
+id3[topic]:::light
+
+id1 --> id3 --> id2
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

Több node és topic

+

További, több node-ot és topicot tartalmazó példa:

+
graph LR;
+
+gen([ /gen_node]) --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32]
+sine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])
+sum --> out[ /out<br/>std_msgs/Float32]
+rand --> sum
+in[ /in<br/>std_msgs/Float32] --> sum
+
+
graph LR;
+
+gen([ /gen_node]) --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32]
+sine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])
+sum --> out[ /out<br/>std_msgs/Float32]
+rand --> sum
+in[ /in<br/>std_msgs/Float32] --> sum
+

Az előbbi példa, csak színekkel

+
graph LR
+
+gen([ /gen_node]):::red --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32]:::light 
+sine[ /sine<br/>std_msgs/Float32]:::light --> sum([ /sum_node]):::red
+sum --> out[ /out<br/>std_msgs/Float32]:::light 
+rand --> sum
+in[ /in<br/>std_msgs/Float32]:::light --> sum
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+
graph LR
+
+gen([ /gen_node]):::red --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32]:::light 
+sine[ /sine<br/>std_msgs/Float32]:::light --> sum([ /sum_node]):::red
+sum --> out[ /out<br/>std_msgs/Float32]:::light 
+rand --> sum
+in[ /in<br/>std_msgs/Float32]:::light --> sum
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Alternatív verzió class használatára

+

A három ::: pont helyett egyszerűen a class kulcsszó után felsorolhatjuk az osztályokat:

+
graph LR
+
+gen([ /gen_node]) --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32] 
+sine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])
+sum --> out[ /out<br/>std_msgs/Float32]
+rand --> sum
+in[ /in<br/>std_msgs/Float32] --> sum
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+class gen,sum red
+class rand,sine,in,out light
+
+
graph LR
+
+gen([ /gen_node]) --> sine
+gen --> rand[ /rand<br/>std_msgs/Float32] 
+sine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])
+sum --> out[ /out<br/>std_msgs/Float32]
+rand --> sum
+in[ /in<br/>std_msgs/Float32] --> sum
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+class gen,sum red
+class rand,sine,in,out light
+
+
flowchart LR
+
+A[/ max_deg</br>param /]:::gray --> D([display_tree</br>node]):::gray
+B[/ max_dist</br>param /]:::gray --> D
+C[/ seed_size</br>param /]:::gray --> D
+D --> |visualization_msgs/marker_array| P[ /path_marker_topic</br>topic]:::gray
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef gray fill:#f6f8fa,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Paraméterek

+

Gyakran jól jön a definiált paraméterek vizualizálása. Erre jelen tudásunk szerint nincs szabványos jelölés hexagonok {{ }} vagy paralellogrammák [/ /] lehetnek az opciók.

+
flowchart LR
+
+A[/ max_deg</br>param /]:::gray --> D([display_tree</br>node]):::gray
+B[/ max_dist</br>param /]:::gray --> D
+C[/ seed_size</br>param /]:::gray --> D
+D --> |visualization_msgs/marker_array| P[ /path_marker_topic</br>topic]:::gray
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef gray fill:#f6f8fa,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
+

Rendszerterv

+
flowchart TD
+    S[State Machine <br>/plan_state_machine] -.->|/plan_state*| LS[LIDAR segementation<br>/prcp_ground_obstacle_segm_lidar]
+    S -.-> CS[Cone detection camera<br> and de-projection]
+    S -.-> O[Object fusion]
+    CS -->|/prcp_obj_list_camera| O
+    LS -->|/prcp_obj_list_lidar| O
+    O -->|/prcp_obj_list_fused| T[Trajectory planner<br>/plan_trajectory_planner]
+    T --> C[Control<br>/ctrl_vehicle_control]
+    S -.-> T
+    S -.-> C
+    O --> M[Map Creation<br>/prc_slam]
+    M -->|/prcp_map| T
+    L[Localization<br>/prcp_odometry_kf_prediction] --> T
+    C --> CAN[To CAN]
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274
+    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+    classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
+    class CS,LS,L,T,M,C white
+    class O light
+    class S dash
+    class CAN red
+
+
flowchart TD
+    S[State Machine <br>/plan_state_machine] -.->|/plan_state*| LS[LIDAR segementation<br>/prcp_ground_obstacle_segm_lidar]
+    S -.-> CS[Cone detection camera<br> and de-projection]
+    S -.-> O[Object fusion]
+    CS -->|/prcp_obj_list_camera| O
+    LS -->|/prcp_obj_list_lidar| O
+    O -->|/prcp_obj_list_fused| T[Trajectory planner<br>/plan_trajectory_planner]
+    T --> C[Control<br>/ctrl_vehicle_control]
+    S -.-> T
+    S -.-> C
+    O --> M[Map Creation<br>/prc_slam]
+    M -->|/prcp_map| T
+    L[Localization<br>/prcp_odometry_kf_prediction] --> T
+    C --> CAN[To CAN]
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274
+    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+    classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
+    class CS,LS,L,T,M,C white
+    class O light
+    class S dash
+    class CAN red
+

Körcikk

+

Az metrics.ros.org/rosdistro_rosdistro.html alapján egy körcikk diagram:

+
pie title ROS distros used
+    "Melodic (ROS 1)" : 0.0010
+    "Noetic (ROS 1)" : 0.0951
+    "Humble" : 0.3333
+    "Iron" : 0.1905
+    "Rolling" : 0.1904
+
+
pie title ROS distros used
+    "Melodic (ROS 1)" : 0.001
+    "Noetic (ROS 1)" : 0.095
+    "Humble" : 0.33
+    "Iron" : 0.19
+    "Rolling" : 0.19
+

Linkek

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/mermaid01.png b/onallo/mermaid01.png new file mode 100644 index 0000000..3c31cd0 Binary files /dev/null and b/onallo/mermaid01.png differ diff --git a/onallo/mermaid02.png b/onallo/mermaid02.png new file mode 100644 index 0000000..6f7c247 Binary files /dev/null and b/onallo/mermaid02.png differ diff --git a/onallo/mermaid03.png b/onallo/mermaid03.png new file mode 100644 index 0000000..b3918c1 Binary files /dev/null and b/onallo/mermaid03.png differ diff --git a/onallo/ros2git/index.html b/onallo/ros2git/index.html new file mode 100644 index 0000000..70034e1 --- /dev/null +++ b/onallo/ros2git/index.html @@ -0,0 +1,2653 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Git és ROS 2 - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Git alapismeretek

+

Pár parancs

+
    +
  • git clone: git repo klónozása
  • +
  • git config --global user.name "Sanyika": felhsználónév beállítása
  • +
  • git config --global user.email "sanyika@gggmail.com: email beállítása
  • +
  • git init: lokális repó inicializálása
  • +
  • git add <file>: fájl hozzáadása
  • +
  • git status: aktuális státusz lekérdezése
  • +
  • git commit -m "My beautiful commit": commit, üzenettel
  • +
  • git push: push
  • +
  • git pull: pull, változások lokális lefrissítése
  • +
  • git branch <new_branch_name>: branch készítése
  • +
  • git checkout <branch_name>: új branch
  • +
  • git checkout -- .: Minden nem staged (unstaged) változás elvetése lokálisan. VS code-ban kb ez a "discard all changes" parancs. (Újabb git verziókban a git restore . is hasonló módon működik.)
  • +
  • git merge <branch_name>: a jelenlegi branch-be mergeli a branch-t
  • +
+

+

Forrás: link

+

Terminológia

+
    +
  • Local repository: a helyi munka repo, pl lokálisan a ~/ros2_ws/src/my_repo
  • +
  • Remote repository: általában online távoli backup repo pl: github.com/my_name/my_repo
  • +
+

Előkészületek

+

Ha még nem tetted volna meg, regisztrálj GitHub-ra.

+

A template használata

+

Navigálj a https://github.com/sze-info/ros2_cpp_template URL-re.

+

Itt használd a zöld gombot, hozd létre a saját felhasználóddal a my_awesome_package nevű package-t:

+

+

Utána ez az oldal fogad, itt ki kell tölteni a repo nevét, utána pedig a zöld gombra kattintva létrejön a repo:

+

Alt text

+

Klónozd git clone segítségével a saját package-d

+

Ha a Github userneved mycoolusername a repo (és egyben a package) neve pedig my_awesome_package, akkor pl így tudod megtenni:

+

cd ~/ros2_ws/src
+
+
git clone https://github.com/mycoolusername/my_awesome_package
+
+
git clone https://github.com/horverno/my_awesome_package
+

+

VS code-ban cserélj ki mindent

+

cd ~/ros2_ws/src/my_awesome_package
+
+
code .
+

+
    +
  1. ros2_cpp_template >> my_awesome_package
  2. +
  3. sze-info >> mycoolusername
  4. +
  5. todo >> értelemszerűen
  6. +
+

+

Build

+

Már buildelhető a package:

+

cd ~/ros2_ws/
+
+
colcon build --packages-select my_awesome_package
+
+A terminál egy üzenetet küld vissza, amely megerősíti, hogy a my_awesome_package csomag lebuildelt.

+

Futtatás

+

Futtatás a szokásos módon:

+

source ~/ros2_ws/install/local_setup.bash
+
+
ros2 launch my_awesome_package launch_example1.launch.py
+

+

Változások követése git status segítségével

+

Amikor lecseréltük a package nevet, több fájl is módosult:

+

cd ~/ros2_ws/src/my_awesome_package
+
+
git status
+

+
+ Image title +
Git status
+
+

Ugyanez VS code-ban így néz ki:

+
+ Image title +
Git status VS code
+
+

Távoli repo frissítése git push segítségével

+

Minden módosítást szeretnnk a commithoz adni:

+
git add .
+
+

Töltsük ki az üzenetet:

+
git commit -m "Initial commit of my_awesome_package"
+
+

Ténylegesen push-oljuk a módosítást a GitHub szervereire:

+
git push
+
+
+ Image title +
Git status add után
+
+

VS code-ban ez is egyszerűbb, Commit, majd Sync Changes:

+
+ Image title +
Git status Sync (push)
+
+

Lokális repo frissítése git pull segítségével

+

Abban az esetben, ha nem a legfrissebb verzió lenne lokálisan, a github-on online tárolt remote lefrissítehető:

+
+ Image title +
Git status (pull)
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onallo/ros2launchmarker/index.html b/onallo/ros2launchmarker/index.html new file mode 100644 index 0000000..d5a6e5a --- /dev/null +++ b/onallo/ros2launchmarker/index.html @@ -0,0 +1,2709 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROS 2 marker és launch - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Leírás

+

Önálló feladatként készítsünk egy my_launch_pkg nevű package-t, amiben egy run_transforms_and_markers.launch.py elindítja a:

+
    +
  • node-ot, ami a map, orbit1 és orbit2 frame-ket publikálja (ros2 run arj_transforms_cpp pub_transforms)
  • +
  • az rqt_reconfigure-t (ros2 run rqt_reconfigure rqt_reconfigure)
  • +
  • a statikus orbit3 frame-et (ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3)
  • +
  • és az Rviz2-t indító launch-t is (ros2 launch arj_transforms_cpp rviz1.launch.py)
  • +
+

Ellenőrizzük rviz2-ben a helyes működést.

+

Tehát indítható legyen az önálló feladat végén a következő paranccsal:

+
ros2 launch my_launch_pkg run_transforms_and_markers.launch.py
+
+

Hozzuk létre a my_launch_pkg package-t

+

Előkövetelmény, hogy a arj_transforms_cpp package már buildelve és futtatható legyen.

+

Ha esetleg már létezne a my_launch_pkg package akkor töröljük. (Gépteremben elképzelehető, hogy előző félévben valaki létrehozta.)

+
cd ~ && test -d "ros2_ws/src/my_launch_pkg" && echo Letezik || echo Nem letezik
+
+
rm -r  ~/ros2_ws/src/my_launch_pkg
+
+

Nyissunk egy új terminált, és source-oljuk a telepítést (ha nincs bashrc-ben), hogy a ros2 parancsok működjenek.

+

Navigáljunk az már létrehozott ros2_ws könyvtárba.

+

Fontos, hogy a csomagokat az src könyvtárban kell létrehozni, nem a munkaterület gyökerében. Tehát navigáljunk a ros2_ws/src mappába, és futtassuk a package létrehozó parancsot:

+
cd ~/ros2_ws/src
+
+
ros2 pkg create --build-type ament_cmake my_launch_pkg
+
+

A terminál egy üzenetet küld vissza, amely megerősíti a my_launch_pkg csomag és az összes szükséges fájl és mappa létrehozását.

+

Launch mappa

+

Hozzunk létre egy mappát a launch fájlok részére:

+
cd ~/ros2_ws/src/my_launch_pkg
+
+
mkdir launch
+
+

Launch fájl létrehozása

+
cd launch
+
+
code run_transforms_and_markers.launch.py
+
+

Állítsunk össze egy launch fájlt:

+
from launch import LaunchDescription
+from launch_ros.actions import Node
+from launch.actions import IncludeLaunchDescription
+from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description():
+    return LaunchDescription([
+        # ros2 run arj_transforms_cpp pub_transforms
+        Node(
+            package='arj_transforms_cpp',
+            executable='pub_transforms',
+        ),
+        # ros2 run rqt_reconfigure rqt_reconfigure
+        Node(
+            package='rqt_reconfigure',
+            executable='rqt_reconfigure',
+        ),
+        # ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3
+        Node(
+            package='tf2_ros',
+            executable='static_transform_publisher',
+            arguments=['1.0', '0.2', '1.4','0', '0', '0', '1', 'orbit2','orbit3'],
+        ),     
+        # ros2 launch arj_transforms_cpp rviz1.launch.py
+        IncludeLaunchDescription(
+            PythonLaunchDescriptionSource([
+                FindPackageShare("arj_transforms_cpp"), '/launch/', 'rviz1.launch.py'])
+        ),
+    ])
+
+

ROS2 launch használata

+

A létrehozott launch fájl elindítása az alábbi módon történik:

+

cd ~/ros2_ws/src/my_launch_pkg/launch # belépünk a launch fájlt tartalmazó mappába
+
+
ros2 launch run_transforms_and_markers.launch.py
+

+

A fent bemutatott direkt módon kívül egy launch fájl futtatható csomag által is:

+
ros2 launch <csomag_megnevezése> <launch_fájl_neve>
+
+

Olyan csomagok esetében, amelyek launch fájlt tartalmaznak, érdemes létrehozni egy exec_depend függőséget a ros2launch csomagra vonatkozóan a csomag package.xml fájljában:

+
<exec_depend>ros2launch</exec_depend>
+
+

Ezzel biztosítható, hogy az ros2 launch parancs elérhető a csomag buildelése után.

+

Adjuk hozzá a package-hez, hogy bárhonnan indíthassuk

+
cd ~/ros2_ws/src/my_launch_pkg
+
+
code .
+
+

A package.xml-hez a <test_depend> elé szúrjuk be következő sort:

+
<exec_depend>ros2launch</exec_depend>
+
+

A CMakeLists.txt-hez a ament_package() elé szúrjuk be következő 2 sort:

+
install(DIRECTORY launch
+  DESTINATION share/${PROJECT_NAME})
+
+

Buildeljük a szokáso módon:

+
cd ~/ros2_ws
+
+
colcon build --packages-select my_launch_pkg
+
+
source ~/ros2_ws/install/setup.bash
+
+

Ez a parancs most már bárhonnan kiadható:

+
ros2 launch my_launch_pkg run_transforms_and_markers.launch.py
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/docker/index.html b/ros2halado/docker/index.html new file mode 100644 index 0000000..40d1950 --- /dev/null +++ b/ros2halado/docker/index.html @@ -0,0 +1,2480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Docker - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/foxglove05.png b/ros2halado/foxglove05.png new file mode 100644 index 0000000..e03af84 Binary files /dev/null and b/ros2halado/foxglove05.png differ diff --git a/ros2halado/index.html b/ros2halado/index.html new file mode 100644 index 0000000..f39568a --- /dev/null +++ b/ros2halado/index.html @@ -0,0 +1,3410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROS 2 haladó - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 haladó

+ +

ROS 2 haladó funkciók

+

Ellenőrző kérdések

+
    +
  • Melyik ROS verziót használjuk a félévben?
  • +
  • Mi a node?
  • +
  • Mi a topic?
  • +
  • Milyen típusú adatokat küldhetünk a topicokon keresztül? (példák)
  • +
+

ROS 2 launch fájlok

+

ROS 2 launch szemléltetés

+

flowchart LR
+    %% Launch file
+    A[LAUNCH<br>FILE]:::dark --o B1
+    A ---o B2
+    A ---o B3
+    D --o C1
+
+    %% SENSE THINK ACT PACKAGE
+    subgraph sense_think_act_package["SENSE THINK ACT<br>PACKAGE"]
+        direction TB
+        B1([Sensor<br>Node]) 
+        B2([Compute<br>Node])
+        B3([Motor<br>Node])
+    end
+
+    %% PARAMS PACKAGE
+    subgraph params_package["PARAMS PACKAGE"]
+        direction TB
+        C1([Robot<br>Node])
+    end
+
+    %% Configuration parameters
+    A --o D[Configuration parameters]
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+Forrás: foxglove.dev

+

ROS 2 launch fájlok

+

Több ROS 2 node futtatása sok időt vesz igénybe és több terminálablakra van szükség. Még a kisebb projektek vagy robotok is egyszerre több node-ot futtathatnak.

+

Képzeljünk el egy robotot, amely a "érzékel-gondolkodik-cselekszik" (sense-think-act) modell alapján működik, és minden lépéshez külön node-ot futtat. Egy sensor_node felelős az érzékelő adatainak olvasásáért, egy compute_node fogadja ezeket az adatokat, és parancsot küld a kerekeknek, végül pedig egy motor_node fogadja a parancsot, és a szükséges feszültséget adja a motoroknak.

+

Ahelyett, hogy minden egyes node-ot külön terminálablakban futtatnánk minden alkalommal, amikor elindítjuk a robotot, használhatunk egy indítófájlt, hogy mindezeket egyszerre futtassuk – egyetlen parancs segítségével, egyetlen terminálablakban.

+

Hogyan tehetjük ezt meg?

+

Három lehetőségünk van launch fájlt írni, pythonban, yaml-ben vagy xml-ben. Ebből kettőt bemutatunk: az xml fájlok egyszerűbbek, de a python fájlok sokkal rugalmasabbak és könnyebben kezelhetőek.

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
# This function is always needed
+def generate_launch_description():
+
+# Declare a variable Node for each node
+compute_node = Node(
+    package="launch_pkg",
+    executable="compute_node"
+)
+sensor_node = Node(
+    package="launch_pkg",
+    executable="sensor_node"
+)
+motor_node = Node(
+    package="launch_pkg",
+    executable="motor_node"
+)
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
<launch>
+    <node pkg="launch_pkg" type="sensor_node" name="sensor_node" output="screen"/>
+    <node 
+        pkg="launch_pkg" 
+        type="compute_node" 
+        name="compute_node" 
+        output="screen"/>
+    <node 
+        pkg="launch_pkg" 
+        type="motor_node" 
+        name="motor_node" 
+        output="screen"/>
+</launch>
+
+
+
+
+
flowchart LR
+    A([sensor_node]):::red
+    B[ /sensor_data]:::light
+    C([compute_node]):::red
+    D[ /cmd_vel]:::light
+    E([motor_node]):::red
+
+
+    A --> B --> C --> D --> E
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Namespace

+

Az launch fájlok csoportokba vagy névterekbe is csoportosíthatják a node-okat. Ez megkönnyíti a node-ok viselkedésének nyomon követését és figyelemmel kísérését.

+

Egy node-nak csak egy neve van, de a névterek több szintjéhez is tartozhat. Ezeket a névtereket perjellel (/) lehet összekapcsolni – minden névtér nélküli csomópontban mindig egyetlen / szerepel a neve előtt (pl. /sensor_node). A deklaráció során megadott névtér nélküli témakörök öröklik a csomópont névterét, ahogy az az előző ábrán is látható.

+

Adjuk hozzá három node-ot a sense_think_act névteréhez:

+
sensor_node = Node(
+  namespace="sense_think_act",
+  package="launch_pkg",
+  executable="sensor_node"
+)
+
+compute_node = Node(
+  namespace="sense_think_act",
+  package="launch_pkg",
+  executable="compute_node"
+)
+
+motor_node = Node(
+  namespace="sense_think_act",
+  package="launch_pkg",
+  executable="motor_node"
+)
+
+
flowchart TD
+    A([sense_think_act/sensor_node]):::red
+    B[ sense_think_act/sensor_data]:::light
+    C([sense_think_act/compute_node]):::red
+    D[ sense_think_act/cmd_vel]:::light
+    E([sense_think_act/motor_node]):::red
+
+
+    A --> B --> C --> D --> E
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

Megjegyzés: A balról jobbra elrendezés helyett a helykihasználás miatt most a fentről lefelé elrendezést használtunk.

+

Más package-ből származó node-ok, paraméterek

+
robot_node = Node(
+  namespace="core",
+  package="params_pkg",
+  executable="robot_node",
+  parameters=[{
+    "robot_name":"RobotA",
+    "max_speed":4.2,
+    "waypoints":["Home", "Room 1", "Corridor", "Home"]
+  }]
+)
+foxglove_bridge = Node(
+    package='foxglove_bridge',
+    executable='foxglove_bridge',
+    parameters=[{
+        'port': 8765,
+        },
+    ]
+)
+
+ld = [compute_node,
+    foxglove_bridge,
+    sensor_node,
+    motor_node,
+    robot_node]
+
+
flowchart TD
+    A([sense_think_act/sensor_node]):::red
+    B[ sense_think_act/sensor_data]:::light
+    C([sense_think_act/compute_node]):::red
+    D[ sense_think_act/cmd_vel]:::light
+    E([sense_think_act/motor_node]):::red
+    F([foxglove_bridge]):::red
+    G([core/robot_node]):::red
+
+    A --> B --> C --> D --> E
+    B --> F
+    D --> F
+    %% D --> G
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

További példa

+
    +
  • robot_a namespace:
      +
    • sensor_node_a: Érzékelő adatokat publikál a /robot_a/sensor_data topicra.
    • +
    • control_node_a: Feliratkozik a /robot_a/sensor_data topicra, és parancsokat küld a /robot_a/cmd_vel topicra.
    • +
    • motor_node_a: Feliratkozik a /robot_a/cmd_vel topicra, hogy fogadja a motor parancsokat.
    • +
    +
  • +
  • robot_b namespace:
      +
    • sensor_node_b: Érzékelő adatokat publikál a /robot_b/sensor_data topicra.
    • +
    • control_node_b: Feliratkozik a /robot_b/sensor_data topicra, és parancsokat küld a /robot_b/cmd_vel topicra.
    • +
    • motor_node_b: Feliratkozik a /robot_b/cmd_vel topicra, hogy fogadja a motor parancsokat.
    • +
    +
  • +
  • Megosztott:
      +
    • Mindkét robot megoszt egy topicot, a/shared/environment_data-t, ahol a sensor_node_a és a sensor_node_b is publikálhat vagy feliratkozhat.
    • +
    • Mindkét robot megoszt egy topicot, a /shared/map_data-t, ahol a map_server publikál és a sensor_node_a és a sensor_node_b feliratkozhat.
    • +
    +
  • +
+
flowchart TB
+    %% Robot A
+    subgraph robot_a["Namespace: robot_a"]
+        direction TB
+        sensor_a([sensor_node_a]):::red
+        control_a([control_node_a]):::red
+        motor_a([motor_node_a]):::red
+
+        sensor_a --> |/robot_a/sensor_data| control_a
+        control_a --> |/robot_a/cmd_vel| motor_a
+    end
+
+    %% Robot B
+    subgraph robot_b["Namespace: robot_b"]
+        direction TB
+        sensor_b([sensor_node_b]):::red
+        control_b([control_node_b]):::red
+        motor_b([motor_node_b]):::red
+
+        sensor_b --> |/robot_b/sensor_data| control_b
+        control_b --> |/robot_b/cmd_vel| motor_b
+    end
+
+    map_sever([map_sever]):::red
+    /shared/map_data[ /shared/map_data]:::light
+
+    %% Shared Topic between Robot A and Robot B
+    sensor_a <--> |/shared/environment_data| sensor_b
+    map_sever --> /shared/map_data
+    /shared/map_data --> sensor_a
+    /shared/map_data --> sensor_b
+
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Videó

+ + +

Vizualizáció és debug

+

Foxglove Studio / Lichtblick Suite

+

A Foxglove Studio egy nyílt forráskódú, robotikai adatokat vizualizáló és hibakereső eszköz. Létezik Windows, Linux és MacOS rendszerekre. A v1.87.0-ig bezárólag nyílt forráskódu volt, a v2.0.0-tól pedig ingyenesen használható, de zárt forráskódú. Az open source fejlesztést több fork, például a Lichtblick Suite vette át. Elérhető számos módon:

+
    +
  • önálló asztali alkalmazásként futtatható
  • +
  • böngészőben hozzáférhető
  • +
  • saját domainen, önállóan hostolható
  • +
+

A natív robotikai eszközök (mint például az ROS ökoszisztéma részei) általában csak Linux rendszeren támogatottak, de a Studio asztali alkalmazás Linuxon, Windows-on és macOS-en is működik. Akár az ROS stack más operációs rendszeren fut, a Studio képes kommunikálni a robottal zökkenőmentesen.

+

foxglove_a +foxglove_a

+

A Studio gazdag vizuális elemeket és hibakereső panelokat kínál - interaktív diagramoktól, 3D vizuális elemekig, kameraképektől, és diagnosztikai adatfolyamokig. Legyen szó valós idejű robotkövetésről, vagy .bag / .mcap fájlban történő hibakeresésről, ezek a panelok segítenek a különböző, általános robotikai feladatok megoldásában.

+

Ezek a panelok ezután egyedi elrendezésekben konfigurálhatók és összeállíthatók a projekt egyedi igényeinek és munkafolyamatainak megfelelően.

+ + + +

Rviz

+

Az Rviz2 a ROS 2 natív, nyílt forráskódú, robotikai adatokat vizualizáló és hibakereső eszköze. Ennek értelmében leginkább Linux rendszeren használható, de a Windows és macOS támogatás is folyamatosan fejlődik.

+
ros2 run rviz2 rviz2
+
+

rviz

+

ros2 run rviz2 rviz2 --help
+
+Parancs segítségével megtudhatjuk, hogy pl. -d kapcsolóval betölthetünk egy .rviz konfigurációs fájlt, vagy -f fix frame-et adhatunk meg.

+

Bővebben: docs.ros.org/en/humble/Tutorials/Intermediate/RViz/RViz-User-Guide/RViz-User-Guide.html

+

rqt_graph

+

Az rqt_graph a node-ok és topic-ok vizualizációjára használható.

+
ros2 run rqt_graph rqt_graph
+
+

rqt_reconfigure

+

rqt_console

+

Az rqt_console log (info, debug, warn, error, fatal) üzenetek megjelenítésre, szűrésére és elemzésére használható.

+
ros2 run rqt_console rqt_console
+
+

+

rqt_tf_tree

+

Az rqt_tf_tree a transzformációk vizualizációjára használható.

+
ros2 run rqt_tf_tree rqt_tf_tree
+
+

rqt_

+

rqt_reconfigure

+

Az rqt_reconfigure a node-ok paramétereinek módosítására használható.

+
ros2 run rqt_reconfigure rqt_reconfigure
+
+

rqt_reconfigure

+

Publish, Subscribe, Timer

+

Három alapvető műveletet célszerű ismerni, amelyeket a ROS 2-ben a node-ok használnak a kommunikációhoz:

+
    +
  • Timer: Időzített eseményeket hoz létre a következő példánál ez a timer_callback() függvény. Ezen a függvényen belül például publikálhatunk egy üzenetet vagy elvégezhetünk egy számítást.
  • +
  • Subscribe: Feliratkozik egy topic-ra, és fogadja az adatokat. Ezt úgy éri el, hogy a példánál maradva a callback1() függvény minden új üzenet érkezéskor meghívódik.
  • +
  • Publish: Adatokat küld a topic-on keresztül. Ezt általában ismétlődően tessszük, jó lehet erre a subscriber callback függvénye, vagy a timer callback függvénye.
  • +
+

Példa C++

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
#include <chrono>
+#include <functional>
+#include <memory>
+#include <string>
+#include "rclcpp/rclcpp.hpp"
+#include "std_msgs/msg/float32.hpp"
+using namespace std::chrono_literals;
+
+class CoolNode : public rclcpp::Node
+{
+public:
+  CoolNode() : Node("my_cool_node")
+  {
+    pub1_ = this->create_publisher<std_msgs::msg::Float32>("topic1", 10);
+    sub1_ = this->create_subscription<std_msgs::msg::Float32>("topic2", 10, std::bind(&CoolNode::callback1, this, std::placeholders::_1));
+    timer_ = this->create_wall_timer(50ms, std::bind(&CoolNode::timer_callback, this)); // 20 hz = 50 ms
+    RCLCPP_INFO_STREAM(get_logger(), this->get_name() << " has been started.");
+  }
+
+private:
+  void timer_callback()
+  {
+    // create message and publish e.g. pub1_->publish(my_msg);
+  }
+
+  void callback1(const std_msgs::msg::Float32::SharedPtr msg)
+  {
+    // do something with the message
+  }
+  rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr pub1_;
+  rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr sub1_;
+  rclcpp::TimerBase::SharedPtr timer_;
+};
+
+int main(int argc, char *argv[])
+{
+  rclcpp::init(argc, argv);
+  rclcpp::spin(std::make_shared<CoolNode>());
+  rclcpp::shutdown();
+  return 0;
+}
+
+

Példa python

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
import rclpy
+from rclpy.node import Node
+from std_msgs.msg import Float32
+
+class CoolNode(Node):
+    def __init__(self):
+        super().__init__('my_cool_node')
+        self.pub1_ = self.create_publisher(Float32, 'topic1', 10)
+        self.sub1_ = self.create_subscription(Float32, 'topic2', 10, self.callback1)
+        self.timer_ = self.create_timer(0.05, self.timer_callback)  # 20 Hz = 50 ms
+        self.get_logger().info(f'{self.get_name()} has been started.')
+
+    def timer_callback(self):
+        # create message and publish e.g. self.pub1_.publish(my_msg)
+        pass
+
+    def callback1(self, msg):
+        # do something with the message
+        pass
+
+def main(args=None):
+    rclpy.init(args=args)
+    node = CoolNode()
+    rclpy.spin(node)
+    rclpy.shutdown()
+
+if __name__ == '__main__':
+    main()
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/mcap/index.html b/ros2halado/mcap/index.html new file mode 100644 index 0000000..ede67cc --- /dev/null +++ b/ros2halado/mcap/index.html @@ -0,0 +1,2586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MCAP fájlok - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

MCAP fájlok

+

Az ROS 2 az log adatokhoz az MCAP formátumot használja. Ez a formátum nem dedikáltan az ROS saját formátuma, hanem egy nyílt forráskódú konténerfájl típus tetszőleges multimodális log-adatokhoz. Támogatja az időbélyegzővel ellátott, előre sorba rendezett adatokat. Így ideális a pub/sub vagy robotikai alkalmazásokban való használatra is, a ROS 2 is ezért döntött mellette. A következőkben arról lesz szó, hogyan lehetséges a formátum C++, Go, Python, Rust, Swift vagy TypeScript nyelven történő szerkesztése. Illetve egy python példán keresztül gyakorlati oldalról is szemléltetjük ezt.

+

Az MCAP egy fejlett logfájlformátum, amely kifejezetten a pub/sub üzenetek és multimodális szenzoradatok időbélyeggel ellátott csatornáinak tárolására szolgál. Nem kötődik egyetlen sorosítási formátumhoz sem, így képes bármilyen formátumú bináris üzenetek, például Protobuf, DDS (CDR), ROS, JSON és mások rögzítésére és visszajátszására. Az MCAP nagy teljesítményű írást tesz lehetővé a sororientált, csak hozzáfűző tervezésének köszönhetően, amely minimalizálja a lemez I/O műveleteket és csökkenti az adatvesztés kockázatát nem tiszta leállítások esetén.

+

Az MCAP önálló formátum, mivel az üzenetek sémáit is az adatok mellett tárolja, így a fájlok a jövőben is olvashatóak maradnak, még akkor is, ha a kódbázis időközben változik. Az MCAP fájlok opcionális indexet tartalmaznak, ami gyors és hatékony adatolvasást tesz lehetővé, még alacsony sávszélességű internetkapcsolaton keresztül is. Opcionális tömörítést is kínál, például LZ4 vagy Zstandard formájában, miközben továbbra is támogatja a hatékony indexelt olvasást.

+

Az MCAP széles körű nyelvi támogatást nyújt, natív olvasó és író könyvtárakkal C++, Go, Python, Rust, Swift és TypeScript nyelveken. A formátum rugalmasan konfigurálható opcionális funkciókkal, mint a darabolás, indexelés, CRC ellenőrzőösszegek és tömörítés, hogy a megfelelő kompromisszumokat kínálja az adott alkalmazáshoz. Az MCAP gyártásra kész formátum, amelyet széles körben használnak különböző cégek, például autonóm járművek és drónok esetében, és ez az alapértelmezett logformátum a ROS 2-ben.

+

Az MCAP fájlformátum ROS 2 agnosztikus, tehát nem függ magától az ROS 2-től, így bármilyen Python projektben használható. Fontos megjegyezni, hogy a rosbag2-api python csomag viszont ROS 2 függő. Így célszerű inkább az mcap-ros2-support python csomag használata, amely nem igényel ROS 2-t, így például Windowson is futtatható.

+

A Python MCAP ROS2 support csomag (mcap-ros2-support) lehetővé teszi a ROS2 támogatást a Python MCAP fájlformátum olvasó számára. Telepítsük a következő parancshoz hasonló módon:

+
pip install mcap mcap-ros2-support matplotlib numpy pandas scipy
+
+

MCAP fájl olvasása példa

+

A github.com/jkk-research/jkk_utils/tree/ros2/mcap_scripts elérésen több hasonló példa is megtalálható:

+
from mcap_ros2.decoder import DecoderFactory
+from mcap.reader import make_reader
+def main():
+    with open('C:\\temp\\test.mcap', "rb") as f:
+        reader = make_reader(f, decoder_factories=[DecoderFactory()])
+        #list all topics and types
+        channels = reader.get_summary().channels.items()
+        print("Available topics are the following:")
+        for index, (channel_key, channel_value) in enumerate(channels):
+            print("%2d. topic: %s" % (index+1, channel_value.topic))
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/pointcloud_to_grid/index.html b/ros2halado/pointcloud_to_grid/index.html new file mode 100644 index 0000000..27d086e --- /dev/null +++ b/ros2halado/pointcloud_to_grid/index.html @@ -0,0 +1,2473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pointcloud to grid - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

pointcloud_to_grid ROS 2 package

+

This package converts sensor_msgs/PointCloud2 LIDAR data to nav_msgs/OccupancyGrid 2D map data based on intensity and / or height.

+

+

Link: github.com/jkk-research/pointcloud_to_grid

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/py_cpp/index.html b/ros2halado/py_cpp/index.html new file mode 100644 index 0000000..f2b7154 --- /dev/null +++ b/ros2halado/py_cpp/index.html @@ -0,0 +1,2606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Python és C++ összehasonlítása - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Python és C++ összehasonlítása

+ +
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
#  ros2 topic type /lexus3/gps/duro/current_pose
+#  geometry_msgs/msg/PoseStamped
+#  ros2 interface show geometry_msgs/msg/PoseStamped
+
+import rclpy
+from rclpy.node import Node
+from geometry_msgs.msg import PoseStamped
+
+
+class SimplePoseSub(Node):
+
+    def __init__(self):
+        super().__init__('simple_pose_sub')
+        self.sub1_ = self.create_subscription(PoseStamped, '/lexus3/gps/duro/current_pose', self.topic_callback, 10)
+
+
+
+    def topic_callback(self, msg):
+
+        self.get_logger().info('x: %.3f, y: %.3f', msg.pose.position.x, msg.pose.position.y)
+
+
+
+
+def main(args=None):
+
+    rclpy.init(args=args)                   ## Initialize the ROS 2 client library
+    simple_pose_sub = SimplePoseSub()
+    rclpy.spin(simple_pose_sub)             ## Create a node and spin
+    simple_pose_sub.destroy_node()
+    rclpy.shutdown()                        ## Shutdown the ROS 2 client library
+
+if __name__ == '__main__':
+    main()
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
// ros2 topic type /lexus3/gps/duro/current_pose
+// geometry_msgs/msg/PoseStamped
+// ros2 interface show geometry_msgs/msg/PoseStamped
+
+#include "rclcpp/rclcpp.hpp"
+#include <memory>
+#include "geometry_msgs/msg/pose_stamped.hpp"
+using std::placeholders::_1;
+
+class SimplePoseSub : public rclcpp::Node{
+public:
+    SimplePoseSub() : Node("simple_pose_sub")
+    {
+        sub1_ = this->create_subscription<geometry_msgs::msg::PoseStamped>("/lexus3/gps/duro/current_pose", 10, std::bind(&SimplePoseSub::topic_callback, this, _1));
+    }
+
+private:
+    void topic_callback(const geometry_msgs::msg::PoseStamped &msg) const
+    {
+        RCLCPP_INFO(this->get_logger(), "x: %.3f, y: %.3f", msg.pose.position.x, msg.pose.position.y);
+    }
+    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr sub1_;
+    };
+
+int main(int argc, char *argv[])
+{
+    rclcpp::init(argc, argv);               // Initialize the ROS 2 client library
+    rclcpp::spin(
+        std::make_shared<SimplePoseSub>()); // Create a node and spin
+
+    rclcpp::shutdown();                     // Shutdown the ROS 2 client library
+    return 0;
+
+}
+
+
+
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/qos/index.html b/ros2halado/qos/index.html new file mode 100644 index 0000000..06616ff --- /dev/null +++ b/ros2halado/qos/index.html @@ -0,0 +1,2731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + QoS szolgáltatásminőség - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

DDS protokoll

+

A DDS (Data Distribution Service) az Object Management Group (OMG) által standardizált kommuinkációs protokoll.

+

+

A DDS protokoll széles körben használt az ipari automatizálásban, a hálózatosított rendszerekben és más területeken, ahol az elosztott adatkommunikáció és a valós idejű adatfeldolgozás kiemelt fontossággal bír. DDS-átvitel rugalmasságából profitál veszteséges vezeték nélküli hálózatokkal rendelkező környezetekben, ahol a "legjobb erőfeszítés" (best effort) elv lenne megfelelőbb vagy valós idejű számítástechnikai rendszerekben, ahol pedig a megfelelő minőség. Az időzítések betartásához szükség van a szolgáltatási profilra. +A QoS "házirendek" halmaza egy QoS "profilt" alkot. Tekintettel az adott forgatókönyvhöz megfelelő QoS-irányelvek kiválasztásának bonyolultságára, a kommunikáció előre definiált QoS-profilokat biztosít általános használati esetekre (pl. szenzoradatok).

+

Szolgáltatásminőség (QoS)

+

A szolgáltatásminőség angol szóval Quality of Service vagy röviden QoS. Az alap QoS-profil a következő házirendek beállításait tartalmazza:

+

Múlt (history)

+
    +
  • Utolsó megtartása (keep last): legfeljebb N mintát tárolhat, a sormélység opcióval konfigurálható.
  • +
  • Mind megtartása (keep all): az összes mintát tárolja, az alapul szolgáló köztes szoftver konfigurált erőforrás-korlátjaitól függően.
  • +
+

Mélység (depth)

+
    +
  • Sor mérete: csak akkor teljesül, ha az "előzmények" házirend "utolsó megőrzésre" van állítva.
  • +
+

Megbízhatóság (relyability)

+
    +
  • Legjobb erőfeszítés (best effort): próbáljon meg mintákat szállítani, de elveszítheti azokat, ha a hálózat nem robusztus.
  • +
  • Megbízható (reliable): garantálja a minták kiszállítását, többször is próbálkozhat.
  • +
+

Tartósság (durability)

+
    +
  • Átmeneti helyi (transient local): a kiadó felelős a „későn csatlakozó” előfizetések tartós mintáiért.
  • +
  • Illékony: nem történik kísérlet a minták fennmaradására.
  • +
+

Határidő, időzítés (deadline)

+
    +
  • Időtartam: a várható maximális időtartam a következő üzenetek közzététele között egy témában
  • +
+

Élettartam (lifespan)

+
    +
  • Időtartam: az üzenet közzététele és fogadása közötti maximális időtartam anélkül, hogy az üzenet elavultnak vagy lejártnak minősülne (a lejárt üzeneteket a rendszer eldobja, és gyakorlatilag soha nem érkezik meg).
  • +
+

Élénkség (liveliness)

+
    +
  • Automatikus: a rendszer a node összes publisherjét élőnek tekinti egy újabb "elengedési időtartamra", ha valamelyik kiadója közzétett egy üzenetet.
  • +
  • Manuális: a rendszer a publishert egy másik " elengedési időtartamra" élőnek tekinti, ha manuálisan (a publisher API-jának hívásával) azt állítja, hogy még életben van.
  • +
+

Elengedési időtartam (lease duration)

+
    +
  • Időtartam: az a maximális időtartam, ameddig a kommunikációs adónak jeleznie kell, hogy életben van, mielőtt a rendszer úgy ítélné meg, hogy elvesztette az élőségét.
  • +
+

QoS kompatibilitás

+

Gyakorlat

+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/ros2launch/index.html b/ros2halado/ros2launch/index.html new file mode 100644 index 0000000..341fcbf --- /dev/null +++ b/ros2halado/ros2launch/index.html @@ -0,0 +1,3015 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROS 2 launch - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 launch és ROS 2 egyéb haladó koncepciók

+

Bevezető

+

Az ROS 2 launch rendszere segíti a felhasználó által definiált rendszer konfigurációjának megadását, majd a konfiguráció szerinti végrehajtását. A konfigurációs lépés a következőket tartalmazza:

+
    +
  • mely programok kerüljenek futtatásra,
  • +
  • milyen argumentumokat kapjanak a futtatott programok,
  • +
  • ROS-specifikus konvencióknak megfelelő összetevők, amelyek a komponensek könnyű újrahasznosíthatóságát teszik lehetővé.
  • +
+

Fontos megemlíteni továbbá, hogy a megoldás felügyeli az elindított folyamatokat, és képes reagálni a folyamatok futási állapotában bekövetkező változásokra.

+

Launch fájlok készítése történhet Python, XML, vagy YAML segítségével.

+

Előkészületek

+

Hozzuk létre a example_launch_cpp package-t

+

Ha esetleg már létezne a example_launch_cpp package akkor töröljük. (Gépteremben elképzelehető, hogy előző félévben valaki létrehozta.)

+
cd ~ && test -d "ros2_ws/src/example_launch_cpp" && echo Letezik || echo Nem letezik
+
+
rm -r  ~/ros2_ws/src/example_launch_cpp
+
+

Nyissunk egy új terminált, és source-oljuk a telepítést (ha nincs bashrc-ben), hogy a ros2 parancsok működjenek.

+

Navigáljunk az már létrehozott ros2_ws könyvtárba.

+

Fontos, hogy a csomagokat az src könyvtárban kell létrehozni, nem a munkaterület gyökerében. Tehát navigáljunk a ros2_ws/src mappába, és futtassuk a package létrehozó parancsot:

+
cd ~/ros2_ws/src
+
+
ros2 pkg create --build-type ament_cmake example_launch_cpp
+
+

A terminál egy üzenetet küld vissza, amely megerősíti a example_launch_cpp csomag és az összes szükséges fájl és mappa létrehozását.

+

Launch mappa

+

Hozzunk létre egy mappát a launch fájlok részére:

+
cd ~/ros2_ws/src/example_launch_cpp
+
+
mkdir launch
+
+

Launch fájl létrehozása

+
cd launch
+
+
code turtlesim_mimic_launch.py
+
+

Állítsunk össze egy launch fájlt a turtlesim csomag elemeivel, Python nyelv alkalmazásával.

+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
from launch import LaunchDescription
+from launch_ros.actions import Node
+
+def generate_launch_description():
+    return LaunchDescription([
+        Node(
+            package='turtlesim',
+            namespace='turtlesim1',
+            executable='turtlesim_node',
+        ),
+        Node(
+            package='turtlesim',
+            namespace='turtlesim2',
+            executable='turtlesim_node',
+            name='turtle2_green',
+            parameters=[{'background_b': 160, 'background_g': 230, 'background_r': 0}],
+        ),
+        Node(
+            package='turtlesim',
+            executable='mimic',
+            name='mimic',
+            remappings=[
+                ('/input/pose', '/turtlesim1/turtle1/pose'),
+                ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
+            ]
+        )
+    ])
+
+
+
+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
<launch>
+    <node
+        pkg="turtlesim"
+        ns="turtlesim1"
+        exec="turtlesim_node"
+        name="turtle1"/>
+
+    <node
+        pkg="turtlesim"
+        ns="turtlesim2"
+        exec="turtlesim_node"
+        name="turtle2_green">
+        <param name="background_b" value="160"/>
+        <param name="background_g" value="230"/>
+        <param name="background_r" value="0"/>
+    </node>
+
+    <node
+        pkg="turtlesim"
+        exec="mimic"
+        name="mimic">
+        <remap from="/input/pose" to="/turtlesim1/turtle1/pose"/>
+        <remap from="/output/cmd_vel" to="/turtlesim2/turtle1/cmd_vel"/>
+    </node>
+</launch>
+
+
+
+
+

A fent leírt módon létrehozott launch fájl a korábbiakban megismert turtlesim csomag három node-ját indítja el. A cél két turtlesim ablak megnyitása, majd az egyik teknős mozgásának megismétlése a másik teknőssel. A két turtlesim node indításában mindössze a névtér (namespace) tér el. Az egyedi névterek alkalmazása lehetővé teszi két azonos node egyidejű elindítását névkonfliktus nélkül. Így mindkét teknős ugyanazon a topicon fogad utasításokat, és ugyanazon a topicon közli a helyzetét. Az egyéni névterek lehetővé teszik a két teknős üzeneteinek megkülönböztetését.

+

Az utolsó node szintén a turtlesim csomagból van, viszont a futtatható fájl eltér: mimic. Ez a csomópont ki van egészítve névmegfeleltetésekkel. Például az egyszerű /input/pose megfelelője ezesetben /turtlesim1/turtle1/pose és a korábban megismert /output/cmd_vel most /turtlesim2/turtle1/cmd_vel. Ez azt jelenti, hogy mimic feliratkozik a /turtlesim1/sim pose topic-ra, és újra publisholja úgy, hogy /turtlesim2/sim sebesség utasítása feliratkozzon rá. Tehát, turtlesim2 utánozni fogja turtlesim1 mozgását.

+

Kód részleteinek áttekintése

+

Ezek a kifejezések Python launch modulokat importálnak.

+
from launch import LaunchDescription
+from launch_ros.actions import Node
+
+

Ezt követően kezdődik a launch leírása:

+
def generate_launch_description():
+  return LaunchDescription([
+
+  ])
+
+

A launch leírásban szereplő első két utasítás indítja a két turtlesim ablakot:

+
Node(
+    package='turtlesim',
+    namespace='turtle1',
+    executable='turtlesim_node',
+),
+Node(
+    package='turtlesim',
+    namespace='turtle2',
+    executable='turtlesim_node',
+    name='turtle2_green',
+    parameters=[{'background_b': 160, 'background_g': 230, 'background_r': 0}],
+),
+
+

Végül megtörténik a mozgás utánzását megvalósító node indítása is:

+
Node(
+    package='turtlesim',
+    executable='mimic',
+    name='mimic',
+    remappings=[
+      ('/input/pose', '/turtlesim1/turtle1/pose'),
+      ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
+    ]
+)
+
+

ROS2 launch használata

+

A létrehozott launch fájl elindítása az alábbi módon történik:

+

cd ~/ros2_ws/src/example_launch_cpp/launch # belépünk a launch fájlt tartalmazó mappába
+
+
ros2 launch turtlesim_mimic_launch.py
+

+

Két turtlesim ablak fog megnyílni, és a következő [INFO] kimenet lesz látható, felsorolva az indított node-okat: +

[INFO] [launch]: Default logging verbosity is set to INFO
+[INFO] [turtlesim_node-1]: process started with pid [11714]
+[INFO] [turtlesim_node-2]: process started with pid [11715]
+[INFO] [mimic-3]: process started with pid [11716]
+

+

Hogy kipróbáljuk az elindított rendszer működését, egy új terminálban hirdessünk olyan üzenetet, amellyel a turtle1 mozgatható:

+
ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}"
+
+

Turtlesim

+

A fent bemutatott direkt módon kívül egy launch fájl futtatható csomag által is:

+
ros2 launch <csomag_megnevezése> <launch_fájl_neve>
+
+

Olyan csomagok esetében, amelyek launch fájlt tartalmaznak, érdemes létrehozni egy exec_depend függőséget a ros2launch csomagra vonatkozóan a csomag package.xml fájljában:

+
<exec_depend>ros2launch</exec_depend>
+
+

Ezzel biztosítható, hogy az ros2 launch parancs elérhető a csomag buildelése után.

+

Tanulmányozzuk az elindított rendszert

+

Úgy, hogy minden eddig elindított node fut, egy újabb terminálban futtassuk az rqt_graph eszközt, amely grafikusan szemlélteti a launch fájl segítségével kialakított rendszert:

+
rqt_graph
+
+

vagy a ros2 run paranccsal:

+
ros2 run rqt_graph rqt_graph
+
+
graph TD
+    T1([turtlesim1/turtlesim]):::red --> P1[ /turtlesim1/turtle1/pose]:::light --> M1([mimic]):::red
+    M1 --> C2[ /turtlesim2/turtle1/cmd_vel]:::light 
+    C2 --> T2([turtlesim2/turtle2_green]):::red 
+
+    n1([ /node]):::white -- publishes --> t[ /topic]:::white
+    t -- subscribes --> n2([ /node]):::white
+
+
+    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Adjuk hozzá a package-hez, hogy bárhonnan indíthassuk

+
cd ~/ros2_ws/src/example_launch_cpp
+
+
code .
+
+
+ Image title +
VS code fájlok
+
+

A package.xml-hez a <test_depend> elé szúrjuk be következő sort:

+
<exec_depend>ros2launch</exec_depend>
+
+

A CMakeLists.txt-hez a ament_package() elé szúrjuk be következő 2 sort:

+
install(DIRECTORY launch
+  DESTINATION share/${PROJECT_NAME})
+
+

Buildeljük a szokáso módon:

+
cd ~/ros2_ws
+
+
colcon build --packages-select example_launch_cpp --symlink-install
+
+

+
+
source ~/ros2_ws/install/setup.bash
+
+

Ez a parancs most már bárhonnan kiadható:

+
ros2 launch example_launch_cpp turtlesim_mimic_launch.py
+
+

Házi feladat

+
+

Házi feladat

+

Készíts egy launch fájlt, amely a turtlesim csomagból elindít egy turtlesim ablakot, és egy teleop_turtle csomagból egy teleop_turtle_keyboard node-ot. A teleop_turtle_keyboard node segítségével a turtlesim ablakban mozgatható a teknős a billentyűzetről. A turtlesim háttere legyen piros. Készítsünk hozzá egy example_launch_py python csomagot, és indítsuk el a launch fájlt a csomagból.

+
+

Megjegyzés python csomagok esetén

+

Amennyiben SetuptoolsDeprecationWarning: setup.py install is deprecated hibaüzenetet kapunk, akkor a setuptools csomag downgrade-elése szükséges. Ellenőrizzük a setuptools csomag verzióját:

+
pip3 list | grep setuptools
+
+

Ha az eredmény újabb, mint 58.2.0, akkor downgrade-elni kell a setuptools csomagot:

+
pip install setuptools==58.2.0
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/rqt/index.html b/ros2halado/rqt/index.html new file mode 100644 index 0000000..00a9102 --- /dev/null +++ b/ros2halado/rqt/index.html @@ -0,0 +1,2574 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Rqt - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

rqt használata

+

rqt_console a log üzenetek megjelenítésre

+

+

rqt_tf_tree a transzformációk vizualizációjára

+

rqt_graph a node-ok és topic-ok vizualizációjára

+

+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/state/index.html b/ros2halado/state/index.html new file mode 100644 index 0000000..287b8ea --- /dev/null +++ b/ros2halado/state/index.html @@ -0,0 +1,2482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Behavior tree, State machine - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/turtlesim03.gif b/ros2halado/turtlesim03.gif new file mode 100644 index 0000000..64c0477 Binary files /dev/null and b/ros2halado/turtlesim03.gif differ diff --git a/ros2halado/vizualizacio/index.html b/ros2halado/vizualizacio/index.html new file mode 100644 index 0000000..670f167 --- /dev/null +++ b/ros2halado/vizualizacio/index.html @@ -0,0 +1,2671 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROS2 vizualizáció - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ROS 2 vizualizáció

+

visualization_msgs/msg/Marker típus

+

visualization_msgs/msg/Marker dokumentáció

+

visualization_msgs/msg/MarkerArray típus

+

visualization_msgs/msg/MarkerArray dokumentáció

+

Mesh

+
git clone https://github.com/szenergy/rviz_markers
+git checkout ros2-humble
+cd ~/ros2_ws 
+colcon build --packages-select rviz_markers
+source ~/ros2_ws/install/setup.bash
+
+

+

A mesheket Foxglove Studio-ban is megjeleníthetjük, csak állítsuk a package path-t a megfelelő helyre, pl:

+

alt text

+

Színek

+

A Google Material Design színrendszer egy átfogó tervezési rendszer, amely pl. ROS-ban és Rviz-ben is használható. A kényelem kedvéért a következőkben felsoroljuk a hexadecimális értékeket (pl. #F44336) és az rgb-vé alakított értékeket (pl. 0,96 0,26 0,21), ami a ROS 2-ben általánosan elfogadott.

+

Bővebben: +- github.com/jkk-research/colors

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
100500900
1.00 0.80 0.82
md_red_100
0.96 0.26 0.21
md_red_500
0.72 0.11 0.11
md_red_900
0.97 0.73 0.82
md_pink_100
0.91 0.12 0.39
md_pink_500
0.53 0.05 0.31
md_pink_900
0.82 0.77 0.91
md_deep_purple_100
0.40 0.23 0.72
md_deep_purple_500
0.19 0.11 0.57
md_deep_purple_900
0.73 0.87 0.98
md_blue_100
0.13 0.59 0.95
md_blue_500
0.05 0.28 0.63
md_blue_900
0.70 0.87 0.86
md_teal_100
0.00 0.59 0.53
md_teal_500
0.00 0.30 0.25
md_teal_900
0.78 0.90 0.79
md_green_100
0.30 0.69 0.31
md_green_500
0.11 0.37 0.13
md_green_900
0.94 0.96 0.76
md_lime_100
0.80 0.86 0.22
md_lime_500
0.51 0.47 0.09
md_lime_900
1.00 0.93 0.70
md_amber_100
1.00 0.76 0.03
md_amber_500
1.00 0.44 0.00
md_amber_900
1.00 0.88 0.70
md_orange_100
1.00 0.60 0.00
md_orange_500
0.90 0.32 0.00
md_orange_900
0.84 0.80 0.78
md_brown_100
0.47 0.33 0.28
md_brown_500
0.24 0.15 0.14
md_brown_900
0.96 0.96 0.96
md_grey_100
0.62 0.62 0.62
md_grey_500
0.13 0.13 0.13
md_grey_900
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ros2halado/vscode06.png b/ros2halado/vscode06.png new file mode 100644 index 0000000..7fac91d Binary files /dev/null and b/ros2halado/vscode06.png differ diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..ee849b1 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Kezd\u0151lap","text":"
  • Tant\u00e1rgy neve magyarul: Auton\u00f3m j\u00e1rm\u0171vek \u00e9s robotok programoz\u00e1sa
  • Tant\u00e1rgy neve angolul: Autonomous robots and vehicles software engineering
  • Neptun t\u00e1rgyk\u00f3d: GKNB_AUTM078

A tant\u00e1rgy t\u00f6bb m\u00e9rn\u00f6ki szakon indul \u00e9s megl\u00e9v\u0151 minim\u00e1lis programoz\u00e1si tud\u00e1sra \u00e9p\u00edt. J\u00e1rm\u0171m\u00e9rn\u00f6ki (BSc) szakon GKNB_INTM023 Programoz\u00e1s alapjai, Programtervez\u0151 informatikus (BSc) GKNB_MSTM032 Python programoz\u00e1s, M\u00e9rn\u00f6kinformatikus (BSc) szakon GKNB_INTM114 Programoz\u00e1s, Mechatronikai m\u00e9rn\u00f6k (BSc) szakon GKNB_MSTM032 Python programoz\u00e1s, Villamosm\u00e9rn\u00f6k (BSc) szakon GKNB_INTM023 Programoz\u00e1s alapjai el\u0151k\u00f6vetlem\u00e9nyekkel indul.

A tant\u00e1rgy c\u00e9lja

A t\u00e1rgy sikeres teljes\u00edt\u00e9se ut\u00e1n a hallgat\u00f3k \u00e1tfog\u00f3 k\u00e9pet kapnak az \u00f6nvezet\u0151 (auton\u00f3m) j\u00e1rm\u0171vek szoftver moduljair\u00f3l \u00e9s tov\u00e1bbi l\u00e9nyeges \u00f6sszetev\u0151ir\u0151l.

C++ \u00e9s python nyelven egyszer\u0171bb ehhez kapcsol\u00f3d\u00f3 szoftvermodulokat tudnak fejleszteni. Ezen t\u00falmen\u0151en a hallgat\u00f3k k\u00e9pesek a megfelel\u0151 k\u00f3d alkalmaz\u00e1s\u00e1ra, valamint annak funkci\u00f3inak \u00e9rtelmez\u00e9s\u00e9re \u00e9s tov\u00e1bbfejleszt\u00e9s\u00e9re ROS 2 keretrendszerben.

A t\u00e1rgy \u00f6ssze\u00e1ll\u00edt\u00e1sa sor\u00e1n olyan nemzetk\u00f6zileg is elismert egyetemek tananyag\u00e1t vett\u00fck alapul, mint az MIT, ETH Z\u00fcrich, TU M\u00fcnchen, Univerisity of Virginia vagy a Stanford University. A megfelel\u0151 licenc betar\u00e1sa mellett bizonyos tanangyag r\u00e9szeket \u00e1t is vett\u00fcnk, m\u00e1sokat inspir\u00e1ci\u00f3k\u00e9nt haszn\u00e1ltunk, err\u0151l r\u00e9szletesen itt lehet olvasni. 2023-ban a tant\u00e1rgy az ROS 2 Humble verzi\u00f3j\u00e1t haszn\u00e1lja, ez a disztrib\u00faci\u00f3 2027 m\u00e1jus\u00e1ig t\u00e1mogatott.

A tant\u00e1rgy teljes\u00edt\u00e9se p\u00e9ld\u00e1ul k\u00f6vetkez\u0151 aut\u00f3ipari / auton\u00f3m j\u00e1rm\u0171ves c\u00e9gekn\u00e9l el\u0151nyt jelenthet (ABC sorrendben):

  • AiMotive Kft. (Budapest)
  • AVL Hungary Kft. (Budapest, \u00c9rd, Kecskem\u00e9t)
  • Bosch: Robert Bosch Kft. (Budapest, Gy\u0151r, Zalaegerszeg)
  • Continental Autonomous Mobility Hungary Kft. (Budapest, Gy\u0151r, Debrecen)
  • J\u00e1rm\u0171ipari Kutat\u00f3k\u00f6zpont, SZE (Gy\u0151r)

Tov\u00e1bbi karrierrel kapcsolatos \u00e9rdekess\u00e9gek p\u00e9ld\u00e1ul a statista-n, a glassdoor-on, linkedin-en olvashat\u00f3k.

Note

A t\u00e1rgyban bemutatott ismeretekre alapozva diplomamunka, szakdolgozat, projektmunka, TDK dolgozat is k\u00e9sz\u00edthet\u0151, illetve van lehet\u0151s\u00e9g a k\u00f6telez\u0151 szakmai gyakorlat teljes\u00edt\u00e9s\u00e9re is.

Oktat\u00f3k . Dr. Horv\u00e1th Ern\u0151 T\u00e1rgyfelel\u0151s github.com/horverno Dr. Ballagi \u00c1ron Tematika, nem oktat github.com/aronball Krecht Rudolf Szimul\u00e1ci\u00f3, robotika github.com/rudolfkrecht Unger Mikl\u00f3s K\u00f6rnyezet\u00e9rz\u00e9kel\u00e9s github.com/umiklos Ign\u00e9czi Gerg\u0151 Szab\u00e1lyoz\u00e1stechnika github.com/gfigneczi1 Mark\u00f3 Norbert AI, neur\u00e1lis h\u00e1l\u00f3k github.com/norbertmarko

2024/25 \u0151szi f\u00e9l\u00e9v\u00e9ben az A2-es teremben (h\u00e9tf\u0151), illetve a B6-as g\u00e9pteremben (kedd 8:30) tartunk \u00f3r\u00e1kat.

\u00d3ra D\u00e1tum Tananyag Megj. 1 szept. 9-10. Bevezet\u00e9s 2 szept. 16-17. ROS 2 alap, telep\u00edt\u00e9s 3 szept. 23-24. \u00c9rz\u00e9kel\u00e9s 4 szept. 30-okt. 1. ROS 2 halad\u00f3 5 okt. 7-8. Transzform\u00e1ci\u00f3k okt. 13-ig kis beadand\u00f3 6 okt. 14-15. \u00c9szlel\u00e9s 7 okt. 21. Szimul\u00e1ci\u00f3 22-\u00e9n B6 terem fel\u00faj\u00edt\u00e1s 8 okt. 28-29. Tervez\u00e9s ZH 1 9 nov. 4-5. Szab\u00e1lyoz\u00e1s 10 nov. 11-12. AI +1 nov. 19.? ZH 2? +2 - P\u00f3t ZH?"},{"location":"#elmelet","title":"Elm\u00e9let","text":"\u00d3ra Tananyag 1 Bevezet\u00e9s: A tant\u00e1rgy fel\u00e9p\u00edt\u00e9se. Robotikai \u00e9s \u00f6nvezet\u0151 j\u00e1rm\u0171ves ismeretek. \u00c9rz\u00e9kel\u00e9s, \u00e9szlel\u00e9s, tervez\u00e9s, szab\u00e1lyoz\u00e1s, aktu\u00e1l\u00e1s. 2 ROS2 koncepci\u00f3k: Egyetemi robotok \u00e9s j\u00e1rm\u0171vek ismertet\u00e9se. ROS 2 alapismeretek. 3 \u00c9rz\u00e9kel\u00e9s: Kamera, LIDAR, GNSS (GPS), IMU, CAN szenzorok m\u0171k\u00f6d\u00e9se, jelfeldolgoz\u00e1sa, f\u0151bb ROS 2 topicok, ROS 2 id\u0151kezel\u00e9s. 4 F\u00e9l\u00e9ves beadand\u00f3: f\u00e9l\u00e9ves beadand\u00f3 ismertet\u00e9se, oszt\u00e1lyz\u00e1si szempontok, \u00f6tletek, k\u00e9rd\u00e9sek-v\u00e1laszok 5 Transzform\u00e1ci\u00f3k: Merev test mozg\u00e1sa, m\u00e1trix szorz\u00e1s ism\u00e9tl\u00e9se, homog\u00e9n koordin\u00e1t\u00e1k szeml\u00e9ltet\u00e9se r\u00f6vid progamk\u00f3dokkal, quaternion (kvaterni\u00f3k) fogalma. 6 \u00c9szlel\u00e9s: objektumfelismer\u00e9s, objektumklasszifik\u00e1ci\u00f3, objektum k\u00f6vet\u00e9s \u00e9s predikci\u00f3, SLAM \u00e9s LOAM. 7 Szimul\u00e1ci\u00f3: ROS 2 kompatibilis szimul\u00e1torok \u00e1ttekint\u00e9se (pl Gazebo, Carla, SVL, OSSDC SIM, AirSim, AWSIM, CoppeliaSim, MVSim) 8 Tervez\u00e9s: Glob\u00e1lis tervez\u00e9s, lok\u00e1lis tervez\u00e9s. Lok\u00e1lis tervez\u00e9s: keresztir\u00e1ny\u00fa \u00e9s hosszir\u00e1ny\u00fa tervez\u00e9s. 9 Szab\u00e1lyoz\u00e1s: J\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si megold\u00e1sok (inverz-modellek, predikt\u00edv modellek, z\u00e1rhurk\u00fa modellek). 10 Mesters\u00e9ges intelligencia: Neur\u00e1lis h\u00e1l\u00f3zatok j\u00e1rm\u0171ves \u00e9s robotikai f\u00f3kusszal."},{"location":"#gyakorlat","title":"Gyakorlat","text":"\u00d3ra Tananyag 1 Bevezet\u00e9s + Linux + G\u00e9ptermi ismeretek: WSL2 haszn\u00e1lata Windows oper\u00e1ci\u00f3s rendszeren. G\u00e9ptermi alapismeretek. Linux parancsok, amelyek sz\u00fcks\u00e9gesek lehetnek a k\u00e9s\u0151bbiekben. 2 Telep\u00edt\u00e9s+ Fejleszt\u0151k\u00f6rnyezet be\u00e1ll\u00edt\u00e1sa + ROS2 kommunik\u00e1ci\u00f3: Els\u0151 ROS 2 node-ok, ROS parancsok haszn\u00e1lata, build \u00e9s source. 3 \u00c9rz\u00e9kel\u00e9s gyakorlat: Szenzor adatok jellemz\u0151bb form\u00e1tumai: sensor_msgs/PointCloud2, sensor_msgs/Image, geometry_msgs/Pose, stb. Bag .mcap f\u00e1jlok kezel\u00e9se, lej\u00e1tsz\u00e1sa. Egyszer\u0171 pacakge k\u00e9sz\u00edt\u00e9se, amely poz\u00edci\u00f3 adatokra iratkozik fel. 4 Verzi\u00f3kezel\u00e9s, Git, Copilot, vs code, ROS 2 launch: Copilot haszn\u00e1lata ROS 2 fejleszt\u00e9shez, Template repo ismertet\u00e9se, haszn\u00e1lata, launch f\u00e1jlok \u00edr\u00e1sa python nyelven 5 Transzform\u00e1ci\u00f3k gyakorlat: Node l\u00e9trehoz\u00e1sa, amely transzform\u00e1ci\u00f3kat hirdet. Markerek megjelen\u00edt\u00e9se, launch \u00f6n\u00e1ll\u00f3 feladat. 6 \u00c9szlel\u00e9s gyakorlat: egyszer\u0171 LIDAR sz\u0171r\u00e9s, X, Y \u00e9s Z koordin\u00e1t\u00e1k szerint. 7 Szimul\u00e1ci\u00f3 bevezet\u00e9s: Gazebo Fortress \u00e9s ROS 2, szimul\u00e1ci\u00f3 gyakorlat: saj\u00e1t robotszimul\u00e1ci\u00f3 l\u00e9trehoz\u00e1sa. 8 Tervez\u00e9s gyakorlat: Polinom alap\u00fa lok\u00e1lis tervez\u0151 megval\u00f3s\u00edt\u00e1s\u00e1s. Nav2 haszn\u00e1lata szimul\u00e1torral. 9 Szab\u00e1lyoz\u00e1s gyakorlat: PID hangol\u00e1s. Trajekt\u00f3riak\u00f6vet\u00e9s Gazebo szimul\u00e1torral. Saj\u00e1t fejleszt\u00e9s\u0171 szab\u00e1lyz\u00f3 \u00e9s j\u00e1rm\u0171 modell. 10 Mesters\u00e9ges intelligencia gyakorlat: Neur\u00e1lis h\u00e1l\u00f3zatok gyakorlat."},{"location":"#erdemjegy","title":"\u00c9rdemjegy","text":"
  • Al\u00e1\u00edr\u00e1s: Kis beadand\u00f3 teljes\u00edt\u00e9se (egyszer\u0171 otthoni programoz\u00e1si feladat)
  • 1 (el\u00e9gtelen): \\(0\\% \\leq ZH_{\u00e1tlag} < 60\\%\\)
  • 2 (el\u00e9gs\u00e9ges): \\(60\\% \\leq ZH_{\u00e1tlag} < 85\\%\\)
  • 3 (k\u00f6zepes): \\(85\\% \\leq ZH_{\u00e1tlag} \\leq 100\\%\\)
  • 4 (j\u00f3): Nagy f\u00e9l\u00e9ves beadand\u00f3 a megadott ir\u00e1nyelvek ment\u00e9n, nagyobb hib\u00e1kkal teljes\u00edtve
  • 5 (jeles): Nagy f\u00e9l\u00e9ves beadand\u00f3 a megadott ir\u00e1nyelvek ment\u00e9n, csak n\u00e9h\u00e1ny kisebb hib\u00e1val teljes\u00edtve
"},{"location":"#konvenciok","title":"Konvenci\u00f3k","text":"
  • gyakorlati tananyag
  • elm\u00e9leti tananyag
  • kieg\u00e9sz\u00edt\u0151 tananyag, a teljes k\u00e9p meg\u00e9rt\u00e9s\u00e9hez sz\u00fcks\u00e9ges lehet
"},{"location":"#erintett-temakorok-nem-a-feldolgozas-szerinti-sorrendben","title":"\u00c9rintett t\u00e9mak\u00f6r\u00f6k (nem a feldolgoz\u00e1s szerinti sorrendben)","text":"
  • Bevezet\u00e9s: \u00d6nvezet\u0151 / auton\u00f3m j\u00e1rm\u0171vek bevezet\u00e9se: az aktu\u00e1lis helyzet, m\u00falt \u00e9s j\u00f6v\u0151. Szenzorok, aktu\u00e1torok kommunik\u00e1ci\u00f3s technol\u00f3gi\u00e1k. (LIDAR, radar, akt\u00edv \u00e9s passz\u00edv kamera, GPS, odometria, IMU, CAN) Foxglove studio \u00e9s saj\u00e1t m\u00e9r\u00e9sek szeml\u00e9tet\u00e9sk\u00e9pp
  • Szoftverrendszer: \u00d6nvezet\u0151 / auton\u00f3m j\u00e1rm\u0171vek szoftverei: \u00e9rz\u00e9kel\u00e9s, \u00e9szlel\u00e9s, tervez\u00e9s, k\u00f6vet\u00e9s. Szimul\u00e1ci\u00f3s technol\u00f3gi\u00e1k, felhaszn\u00e1l\u00f3i fel\u00fcletek. Keretrendszerek: ROS/ROS2/MATLAB/LabVIEW szererepe, val\u00f3s idej\u0171 rendszerek (FPGA, real-time oper\u00e1ci\u00f3s rendszerek).
  • \u00c9rz\u00e9kel\u00e9s: SLAM, objektumdetekci\u00f3, objektumk\u00f6vet\u00e9s \u00e9s el\u0151rejelz\u00e9s. Padkadetekci\u00f3, s\u00e1vdetekci\u00f3, \u00fathibadetekci\u00f3, j\u00e1rm\u0171 \u00e9s gyalogosdetekci\u00f3/k\u00f6vet\u00e9s stb. Mesters\u00e9ges intelligencia (k\u00fcl\u00f6n\u00f6sen neur\u00e1lis h\u00e1l\u00f3zatok) \u00e9s hagyom\u00e1nyos (pl C++ nyelven k\u00e9sz\u00fclt) algoritmusok el\u0151nyei h\u00e1tr\u00e1nyai, f\u00fazi\u00f3ja.
  • Technol\u00f3giai ismeretek: Linux, Git: Linux ismeretek: Terminal kezel\u00e9se, Git kezel\u00e9se, VS code, ROS telep\u00edt\u00e9se
  • Technol\u00f3giai ismeretek: ROS 2 alapok: topicok \u00e9s \u00fczenetek, MCAP (Rosbag) visszaj\u00e1tsz\u00e1sa, Topicok kezel\u00e9se, Topic tartalm\u00e1nak el\u00e9r\u00e9se pythonb\u00f3l, rviz, rqt_plot, MCAP (Rosbag) k\u00e9sz\u00edt\u00e9s. ROS 2 \u00f6kosziszt\u00e9ma \u00e9s fejleszt\u00e9s ROS 2 node-ok k\u00e9sz\u00edt\u00e9se pythonban \u00e9s C++-ban: ROS 2 node-ok, rqt_graph, Publisher / Subscriber node pythonban, Publisher / Subscriber node C++-ban. Els\u0151 egyeztet\u00e9s az egy\u00e9ni projektfeladatr\u00f3l.
  • ROS 2 programoz\u00e1s:ROS szenzoradatok feldolgoz\u00e1sa C++ node-al: ROS node-ok \u00edr\u00e1sa, visualization_msgs, LIDAR szenzoradatok: sensor_msgs/PointCloud2, sensor_msgs/LaserScan, stb.
  • Szimul\u00e1ci\u00f3 \u00e9s szab\u00e1lyz\u00e1s: Szimul\u00e1ci\u00f3: ROS node-ok haszn\u00e1lata szimul\u00e1ci\u00f3hoz (gazebo) F1/10, rviz, egy\u00e9ni projektfeladatok v\u00e9gleges\u00edt\u00e9se. Tervez\u00e9s blokk: trajekt\u00f3ria tervez\u0151k t\u00edpusai, kinematikai kih\u00edv\u00e1sok, Szab\u00e1lyz\u00e1s blokk: j\u00e1rm\u0171modellez\u00e9s, szab\u00e1lyz\u00f3k bemutat\u00e1sa, j\u00e1rm\u0171- \u00e9s aktu\u00e1torszint\u0171 szab\u00e1lyz\u00e1s, a mozg\u00e1s megval\u00f3s\u00edt\u00e1sa (f\u00e9krendszerek, korm\u00e1nyrendszerek\u2026stb)
  • Kitekint\u00e9s, doktori kutat\u00e1sok, egyetemi hallgat\u00f3i csapatok: Nissan Leaf, Lexus \u00e9s Szenergy \u00f6nvezet\u0151 projektek, bemutat\u00e1sa, kiragadott k\u00f3dr\u00e9szletekkel \u00c9rz\u00e9kel\u00e9s: pontfelh\u0151 kezel\u00e9s vagy objektum detekt\u00e1l\u00e1s kamera alapon \u00c9szlel\u00e9s / tervez\u00e9s: \u00fatvonalmeghat\u00e1roz\u00e1s, szabad ter\u00fclet meghat\u00e1roz\u00e1s, trajekt\u00f3ria tervez\u00e9s Szab\u00e1lyz\u00e1s: z\u00e1rthurk\u00fa modellezett j\u00e1rm\u0171, szab\u00e1lyz\u00f3 \u00e9p\u00edt\u00e9se (pl PID vagy pure pursuit)
  • Mesters\u00e9ges intelligencia: \u00d6nvezet\u0151 / auton\u00f3m j\u00e1rm\u0171vek szoftverei, \u00f6sszefoglal\u00e1s, kitekint\u00e9s neur\u00e1lis h\u00e1l\u00f3zatok (mesters\u00e9ges intelligencia, AI)
  • Technol\u00f3giai ismeretek: ROS 2 haszn\u00e1lata, \u00fajdons\u00e1gai ROS-hez k\u00e9pest
  • Projektmunka: Egy\u00e9ni projektfeladat bemutat\u00e1sa

sze-info.github.io/ajr

"},{"location":"bevezetes/","title":"Bevezet\u00e9s","text":"

Rendszerszinten az \u00f6nvezet\u00e9s a k\u00f6vetkez\u0151 alfunkci\u00f3k \u00f6sszegek\u00e9nt \u00edrhat\u00f3 le:

Irodalom: [TU M\u00fcnchen], [Autoware], [University of Texas at Dallas], [ApolloAuto]

  1. \u00c9rz\u00e9kel\u00e9s: egyszer\u0171 driver-program szint\u0171 nyers adatok el\u0151\u00e1ll\u00edt\u00e1s\u00e1val foglakozik, p\u00e9ld\u00e1ul egy kamera szenzorb\u00f3l a k\u00e9p el\u0151\u00e1ll\u00edt\u00e1sa a rendszer sz\u00e1m\u00e1ra.
  2. \u00c9szlel\u00e9s: ez m\u00e1r \u00f6sszetettebb folyamat, a bemeneti adatokb\u00f3l kinyerni a rendszer sz\u00e1m\u00e1ra fontos inform\u00e1ci\u00f3kat, p\u00e9ld\u00e1ul gyalogos felismer\u00e9se kamerak\u00e9p alapj\u00e1n.
  3. Tervez\u00e9s: a j\u00e1rm\u0171 \u00fatj\u00e1t, vagy trajekt\u00f3ri\u00e1j\u00e1t tervezi meg glob\u00e1lis szinten (a szenzorok \u00e9rz\u00e9kel\u00e9si tartom\u00e1ny\u00e1n t\u00fal), illetve lok\u00e1lis szinten (a szenzorok \u00e9rz\u00e9kel\u00e9s tartom\u00e1ny\u00e1n bel\u00fcl).
  4. Szab\u00e1lyoz\u00e1s: a tervez\u0151 \u00e1ltal el\u0151\u00e1ll\u00edtott \u00fatvonal, vagy tarjekt\u00f3ria lek\u00f6vet\u00e9se, p\u00e9ld\u00e1ul Pure-Pursuit szab\u00e1lyz\u00f3, Modell Predikt\u00edv Szab\u00e1lyz\u00f3 (Model Predictive Control, MPC) stb. seg\u00edts\u00e9g\u00e9vel.
  5. Aktu\u00e1l\u00e1s: a rendszer \u00e1ltal el\u0151\u00e1ll\u00edtott referenciajelek (korm\u00e1nysz\u00f6g, g\u00e1z \u00e9s f\u00e9kped\u00e1l) kiad\u00e1sa (pl. CAN bus rendszeren).

A fenti beoszt\u00e1s megfigyelhet\u0151 nagyobb rendszerek, p\u00e9ld\u00e1ul az Autoware \u00f6sszefoglal\u00f3 rendszer\u00e1br\u00e1j\u00e1n is. Robotik\u00e1ban ismeretes m\u00e9g a sense-think-act paradigma is. Itt a gondolkod\u00e1s (think) foglalja \u00f6ssze az \u00e9szlel\u00e9st, a tervez\u00e9st \u00e9s valamennyire a szab\u00e1lyoz\u00e1st is.

N\u00e9zz\u00fcnk minden r\u00e9szfeladatra egy szeml\u00e9ltet\u00e9st, az egyetem\u00fcnk egyik \u00f6nvezet\u0151 funkci\u00f3kkal rendelkez\u0151 aut\u00f3j\u00e1n, a zalaegerszegi tesztp\u00e1ly\u00e1n:

"},{"location":"bevezetes/#onvezetes-vs-vezetestamogatas","title":"\u00d6nvezet\u00e9s vs. vezet\u00e9st\u00e1mogat\u00e1s","text":""},{"location":"bevezetes/#sae-szintek","title":"SAE szintek","text":"

A SAE J3016 szabv\u00e1ny defini\u00e1lja a sof\u0151r \u00e9s a j\u00e1rm\u0171 rendszere k\u00f6z\u00f6tti munkamegoszt\u00e1st.

  • 0. szint: L0 - No Driving Automation, azaz a vezet\u00e9sautomatiz\u00e1ci\u00f3 teljes hi\u00e1nya.
  • 1. szint: L1 - Driver Assistance, itt bizonyos vezet\u00e9st\u00e1mogat\u00f3 funkci\u00f3k m\u00e1r belesz\u00f3lhatnak a j\u00e1rm\u0171 mozg\u00e1s\u00e1ba.
  • 2. szint: L2 - Partial Driving Automation, azaz mindk\u00e9t ir\u00e1nyba t\u00f6rt\u00e9n\u0151 man\u0151vert v\u00e9gez az aut\u00f3, a fel\u00fcgyelet az ember\u00e9.
  • 3. szint: L3 - Conditional Driving Automation, itt ha a j\u00e1rm\u0171 k\u00e9ri, a sof\u0151rnek vissza kell vennie az ir\u00e1ny\u00edt\u00e1st.
  • 4. szint: L4 - High Driving Automation, itt m\u00e1r minden felel\u0151ss\u00e9g a j\u00e1rm\u0171v\u00e9, de hagyom\u00e1nyos \u00fczemm\u00f3dban is haszn\u00e1lhat\u00f3 m\u00e9g.
  • 5. szint: L5 - Full Driving Automation, Autonomous, itt is a j\u00e1rm\u0171\u00e9 a fele\u0151ss\u00e9g, s\u0151t, nem is lehet hagyom\u00e1nyos korm\u00e1nnyal haszn\u00e1lni.

A szabv\u00e1ny azonban nem \u00edjra le, hogy milyen \"scope\" / ter\u00fclet a j\u00e1rm\u0171 korl\u00e1tja. P\u00e9ld\u00e1ul egy \u00f6nvezet\u0151 rept\u00e9ri busz nem l\u00e9phet ki a rept\u00e9r ter\u00fclet\u00e9r\u0151l. Ugyan\u00edgy a Waymo, Cruise vagy a Zoox robotaxija jellemz\u0151en kisebb r\u00e9gi\u00f3ban, magyar hasonlatk\u00e9nt nagyj\u00e1b\u00f3l 1-2 v\u00e1rmegy\u00e9nyi ter\u00fcleten m\u0171k\u00f6dik csak. Ezt nevezz\u00fck \"geofencing\"-nek is.

"},{"location":"bevezetes/#peldak","title":"P\u00e9ld\u00e1k","text":"

Ahogy l\u00e1thattuk, \u00f6nvezet\u0151 (autonomous) j\u00e1rm\u0171vekhez (L5) hasonl\u00f3 technol\u00f3gi\u00e1k tal\u00e1lhat\u00f3k a vezet\u00e9st\u00e1mogat\u00f3 (automated) szinteken (L2/L3) is. Azonban a feladat komplexit\u00e1sban teljesen m\u00e1s szintet jelent.

Szint: L2/L3 L5 Elnevez\u00e9s: Automatiz\u00e1lt, vezet\u00e9st\u00e1mogat\u00f3 Auton\u00f3m, \u00f6nvezet\u0151 Jellemz\u0151 szenzorok: Kamera, radar Kamera, radar, LIDAR, GPS P\u00e9ld\u00e1k: Tesla, Audi, BMW Waymo, Zoox, Cruise"},{"location":"bevezetes/#onvezeto-jarmuvek-es-robotok","title":"\u00d6nvezet\u0151 j\u00e1rm\u0171vek \u00e9s robotok","text":"Robotok Robotaxik Nuro, Segway, Turtlebot, Clearpath, Starship Zoox, Cruise, Waymo, Navya, Sensible4

N\u00e9zz\u00fcnk egy p\u00e9ld\u00e1t, ami a Zoox \u00f6nvezet\u0151 robotaxit mutaja be m\u0171k\u00f6d\u00e9s k\u00f6zben:

"},{"location":"bevezetes/#kodsorok","title":"K\u00f3dsorok","text":"

Az al\u00e1bbi \u00e1br\u00e1b\u00f3l l\u00e1tszik, hogy egy mai \u00e1tlagos (vezet\u00e9st\u00e1mogat\u00e1ssal rendelkez\u0151) szem\u00e9lyaut\u00f3 igen komplex szoftverm\u00e9rn\u00f6ki munka eredm\u00e9nye, azonban az is vil\u00e1gos, hogy a j\u00f6v\u0151ben az \u00f6nvezet\u0151 j\u00e1rm\u0171vek m\u00e9g enn\u00e9l is \u00f6sszetettebb megold\u00e1sokat fognak ig\u00e9nyelni.

---\nconfig:\n    themeVariables:\n        xyChart:\n            backgroundColor: transparent\n            titleColor: \"#AAAAAA\"\n            xAxisLabelColor: \"#43AEC5\"\n            yAxisLabelColor: \"#43AEC5\"\n            xAxisLineColor: \"#AAAAAA\"\n            yAxisLineColor: \"#AAAAAA\"\n            plotColorPalette: \"#43AEC5\"\n---\nxychart-beta\n\n    title \"Millions of Lines of code (LOC) in 2024\"\n    x-axis [\"Avg. iPhone app\",\"World of warcraft\", \"Linux kernel\", Facebook, \"Avg. new vehicle\"]\n    y-axis \"Average number of lines of codes (million)\" 0 --> 210\n    bar [0.04, 5.5, 30, 62, 200]\n
Forr\u00e1s: statista, informationisbeautiful

"},{"location":"bevezetes/#egyetemi-jarmuvek","title":"Egyetemi j\u00e1rm\u0171vek","text":"

A Sz\u00e9chenyi Istv\u00e1n Egyetem szerencs\u00e9re relat\u00edv sok \u00e1talak\u00edtott szem\u00e9lyg\u00e9pj\u00e1rm\u0171vel, illetve robottal rendelkezik. Ezek a k\u00f6vetkez\u0151ek:

"},{"location":"bevezetes/#lexus-rx450h-my2016-auto","title":"Lexus RX450h MY2016+ (aut\u00f3)","text":"

Szenzorai: Ouster OS2-64 LIDAR, 2x OS1-32 LIDAR, Stereolabs Zed2i m\u00e9lys\u00e9gkamera. Tov\u00e1bbi inform\u00e1ci\u00f3 itt.

Lexus"},{"location":"bevezetes/#nissan-leaf-auto","title":"Nissan Leaf (aut\u00f3)","text":"

Szenzorai: 2x Ouster OS1-64 LIDAR, 2x Velodyne VLP16 LIDAR, SICK LMS111 LIDAR, Stereolabs Zed / Zed2 m\u00e9lys\u00e9gkamera. Tov\u00e1bbi inform\u00e1ci\u00f3 itt.

Nissan Leaf"},{"location":"bevezetes/#szenergy-auto","title":"Szenergy (aut\u00f3)","text":"

Szenzorai: Ouster OS1-128 LIDAR, SICK LMS111 LIDAR, Stereolabs Zed2i m\u00e9lys\u00e9gkamera. Tov\u00e1bbi inform\u00e1ci\u00f3 itt.

Szenergy

A Szenergy csapata eur\u00f3pa legnagyobb \u00f6nvezet\u0151 verseny\u00e9n, a Shell Eco-marathon Autonomous Urban Concept (AUC) versenyen 2023-ban els\u0151, el\u0151tte pedig m\u00e1sodik helyez\u00e9st \u00e9rt el. A doboog\u00f3s helyez\u00e9sek ezekben az \u00e9vek ben \u00edgy alakultak:

\ud83c\udfc6 2022 2023 2024 1. DTU Road Runners, Technical University of Denmark (Denmark) SZEnergy Team, Sz\u00e9chenyi Istv\u00e1n University (Hungary) SZEnergy Team, Sz\u00e9chenyi Istv\u00e1n University (Hungary) 2. SZEnergy Team, Sz\u00e9chenyi Istv\u00e1n University (Hungary) Team EVA, Hogeschool Van Amsterdam University (Netherlands) H2politO,Molecole Urbane Politecnico Di Torino University (Italy) 3. DNV Fuel Fighter, Norwegian University of Science And Technology (Norway) H2politO,Molecole Urbane Politecnico Di Torino University (Italy) Team EVA, Hogeschool Van Amsterdam University (Netherlands)

Forr\u00e1s: shellecomarathon.com

"},{"location":"bevezetes/#f110-ackermann-robot-roboworks-rosbot-mini-ackermann","title":"F1/10 (Ackermann robot) / Roboworks Rosbot mini Ackermann","text":"

Az F1/10 verseny egy auton\u00f3m j\u00e1rm\u0171vekkel kapcsolatos verseny, ahol a r\u00e9sztvev\u0151k 1/10-es m\u00e9retar\u00e1ny\u00fa Formula 1-es aut\u00f3modelleket \u00e9p\u00edtenek \u00e9s programoznak, hogy azok \u00f6n\u00e1ll\u00f3an navig\u00e1ljanak egy versenyp\u00e1ly\u00e1n. A c\u00e9l az, hogy a j\u00e1rm\u0171vek a lehet\u0151 leggyorsabban \u00e9s legbiztons\u00e1gosabban teljes\u00edts\u00e9k a p\u00e1ly\u00e1t, mik\u00f6zben elker\u00fclik az akad\u00e1lyokat \u00e9s a t\u00f6bbi aut\u00f3t. A verseny sor\u00e1n a r\u00e9sztvev\u0151k tesztelhetik robotikai, mesters\u00e9ges intelligencia \u00e9s g\u00e9pi tanul\u00e1si ismereteiket. A Roboworks robotja az F1/10 j\u00e1rm\u0171 m\u00e9re\u00e9hez \u00e9s szenzorozotts\u00e1g\u00e1hoz nagyon hasonl\u00f3. F1tenth j\u00e1rm\u0171 le\u00edr\u00e1s itt.

"},{"location":"bevezetes/#segway-loomo-robot","title":"Segway Loomo (robot)","text":"

Le\u00edr\u00e1s itt.

"},{"location":"bevezetes/#husarion-rosbot-2-pro-robot","title":"Husarion ROSbot 2 Pro (robot)","text":"

Le\u00edr\u00e1s itt.

"},{"location":"bevezetes/#robotis-ros-turtlebot-3-robot","title":"Robotis ROS TurtleBot 3 (robot)","text":"

Le\u00edr\u00e1s itt.

"},{"location":"bevezetes/#dji-matrice-600-pro-drone-robot","title":"DJI Matrice 600 Pro drone (robot)","text":"

Szenzorai: Ouster OS1-64 LIDAR. Tov\u00e1bbi inform\u00e1ci\u00f3 itt.

"},{"location":"bevezetes/copilot/","title":"Coplilot","text":"

A GitHub Copilot egy programoz\u00e1st seg\u00edt\u0151 eszk\u00f6z: github.com/features/copilot. AI technol\u00f3gi\u00e1kon alapul, hasonl\u00f3an a ChatGPT-hez. Kifejezetten hasznos kezd\u0151 programoz\u00f3knak, de tapsztalt fejleszt\u0151knek is nagy seg\u00edts\u00e9g lehet. A GitHub Copilot seg\u00edts\u00e9get ny\u00fajt a fejleszt\u0151knek a k\u00f3d \u00edr\u00e1s\u00e1ban, kieg\u00e9sz\u00edt\u00e9s\u00e9ben \u00e9s jav\u00edt\u00e1s\u00e1ban, javaslatokat tesz a k\u00f3dol\u00e1si mint\u00e1kra \u00e9s strukt\u00far\u00e1kra, \u00e9s gyorsabban hozz\u00e1seg\u00edthet a fejleszt\u0151ket a probl\u00e9m\u00e1k megold\u00e1s\u00e1hoz.

A GitHub Copilot t\u00f6bbf\u00e9le programoz\u00e1si nyelvet t\u00e1mogat, \u00edgy seg\u00edthet k\u00fcl\u00f6nf\u00e9le fejleszt\u00e9si feladatokban, p\u00e9ld\u00e1ul robotikai fejleszt\u00e9sben, adatb\u00e1ziskezel\u00e9sben, mobilalkalmaz\u00e1s-fejleszt\u00e9sben \u00e9s sok m\u00e1s ter\u00fcleten.

Az eszk\u00f6z be\u00e9p\u00fcl a fejleszt\u0151i k\u00f6rnyezetekbe, p\u00e9ld\u00e1ul a Visual Studio Code-ba, \u00e9s k\u00f6zvetlen\u00fcl az alkalmaz\u00e1son bel\u00fcl lehet haszn\u00e1lni.

Haszn\u00e1lata alap\u00e9rtelmezetten fizet\u0151s, de hallgat\u00f3 hozz\u00e1f\u00e9r\u00e9ssel ingyenes: education.github.com/benefits.

N\u00e9zz\u00fck meg m\u0171k\u00f6d\u00e9s k\u00f6zben a copilot-ot:

"},{"location":"bevezetes/copilot/#github-copilot-beszerzese-sze-hallgatoknak","title":"GitHub Copilot beszerz\u00e9se SZE hallgat\u00f3knak","text":"

A tant\u00e1rgy teljes\u00edt\u00e9s\u00e9hez szinte elengedhetetlen a GitHub Copilot haszn\u00e1lata. A GitHub Student Developer Pack keret\u00e9ben a hallgat\u00f3k sz\u00e1m\u00e1ra ingyenesen el\u00e9rhet\u0151 a GitHub Copilot. A Developer Pack r\u00e9szletei \u00e9s a regisztr\u00e1ci\u00f3 itt \u00e9rhet\u0151 el: education.github.com/pack. Hallgat\u00f3k\u00e9nt a k\u00f6vetkez\u0151 l\u00e9p\u00e9sekkel a legegyszer\u0171bb a GitHub Copilot beszerz\u00e9se:

  • Regisztr\u00e1ci\u00f3 Hallgat\u00f3i Office 365 ig\u00e9nyl\u00e9sre, @hallgato.sze.hu email, 5GB OneDrive t\u00e1rhely, Office Online \u00e9s Office 365 ProPlus deskop allalmaz\u00e1sok j\u00e1rnak hozz\u00e1: office365.sze.hu
  • Github regisztr\u00e1ci\u00f3 illetve, amint \u00e9l @hallgato.sze.hu email, m\u00e1sodik vagy els\u0151dleges email c\u00edmk\u00e9nt be\u00e1ll\u00edtani a GitHub fi\u00f3kban.
  • Regisztr\u00e1ci\u00f3 a GitHub Student Developer Pack-ra: education.github.com/pack
  • P\u00e1r nap m\u00falva a GitHub Copilot el\u00e9rhet\u0151v\u00e9 v\u00e1lik a Visual Studio Code-ban. Az extension-\u00f6k k\u00f6z\u00f6tt kereshet\u0151 a Copilot, a Copilot chat, csak be kell jelentkezni a VS code GitHub fi\u00f3kba.
"},{"location":"bevezetes/gepterem/","title":"G\u00e9ptermi ismeretek (C100)","text":""},{"location":"bevezetes/gepterem/#kozos-meghajto-k","title":"K\u00f6z\u00f6s meghajt\u00f3 (K:\\)","text":"

A k\u00f6z\u00f6s meghajt\u00f3 a K:\\ meghajt\u00f3k\u00e9nt tal\u00e1lhat\u00f3 meg Winodws F\u00e1jlkezel\u0151ben (File Explorer). Ha esetleg nem l\u00e1tszana, akkor szint\u00e9n a F\u00e1jlkezel\u0151ben el\u00e9rhet\u0151:

\\\\fs-kab.eik.sze.hu\\C100\\kozos\n

A tant\u00e1rgyhoz kapcsol\u00f3d\u00f3 f\u00e1jlok pontosan a \\\\fs-kab.eik.sze.hu\\C100\\kozos\\GKNB_AUTM078_Auton\u00f3m_robotok_\u00e9s_j\u00e1rm\u0171vek_programoz\u00e1sa c\u00edmen \u00e9rhet\u0151ek el.

"},{"location":"bevezetes/gepterem/#wsl-es-kozos-meghajto","title":"WSL \u00e9s k\u00f6z\u00f6s meghajt\u00f3","text":"

WSL al\u00f3l szint\u00e9n el kellene tudni \u00e9rni a k\u00f6z\u00f6s meghajt\u00f3t m\u00e9gpedig az /mnt/kozos mount ponton. Tesztelj\u00fck az el\u00e9r\u00e9st a cd /mnt/kozos paranccsal. Ha a -bash: cd: /mnt/kozos: No such file or directory \u00fczenetet kaptuk, akkor hozzuk l\u00e9tre mkdir seg\u00edts\u00e9g\u00e9vel. Ha az ls /mnt/kozos nem list\u00e1z f\u00e1jlokat, akkor pedig nincs felmountolva.

Ha esetleg nem m\u0171k\u00f6dne a k\u00f6z\u00f6s meghajt\u00f3, akkor ezek a parancsok seg\u00edthetnek:

sudo mkdir /mnt/kozos\necho \"\\\\\\\\\\\\\\\\fs-kab.eik.sze.hu\\C100\\kozos\\GKNB_AUTM078_Auton\u00f3m_robotok_\u00e9s_j\u00e1rm\u0171vek_programoz\u00e1sa    /mnt/kozos    drvfs defaults,uid=1000,gid=1000    0    0\" | sudo tee -a /etc/fstab\n
Majd wsl --shutdown windows cmd-b\u0151l.

"},{"location":"bevezetes/gepterem/#wsl-a-fajlkezeloben","title":"WSL a F\u00e1jlkezel\u0151ben","text":"

Az Ubuntu 22.04 f\u00e1jljai szint\u00e9n el\u00e9rhet\u0151ek a Windows F\u00e1jlkezel\u0151b\u0151l. Bal oldlalt l\u00e1szik egy WSL vagy Linux felirat. A ~ a /home/<g\u00e9pn\u00e9v> mapp\u00e1n bel\u00fcl \u00e9rhet\u0151 el, \u00edgy a ros2_ws is.

"},{"location":"bevezetes/gepterem/#vs-code","title":"VS code","text":""},{"location":"bevezetes/gepterem/#vs-code-wsl-eleres","title":"VS code WSL el\u00e9r\u00e9s","text":""},{"location":"bevezetes/gepterem/#vs-code-hasznos-extension-ok","title":"VS code hasznos extension-\u00f6k","text":""},{"location":"bevezetes/gepterem/#windows-terminal","title":"Windows terminal","text":"

A k\u00f6z\u00f6s meghajt\u00f3n tal\u00e1lhat\u00f3 egy portable verzi\u00f3. Ezt a C:\\temp-be m\u00e1solva haszn\u00e1lhat\u00f3 a program.

A k\u00f6vetkez\u0151 \u00e1bra egy c\u00e9lszer\u0171 (nem k\u00f6telez\u0151) g\u00e9ptermi elrendez\u00e9st mutat, bal oldalt a terminal, jobb oldalt a b\u00f6ng\u00e9sz\u0151:

"},{"location":"bevezetes/gepterem/#foxglove","title":"Foxglove","text":"

Telep\u00edtve van, az asztalon tal\u00e1lhat\u00f3 ikonnal ind\u00edthat\u00f3. Ha m\u00e9gse lenne telep\u00edtve, a k\u00f6z\u00f6s meghajt\u00f3n l\u00e9v\u0151 portable verzi\u00f3t kell a C:\\temp-be m\u00e1solni.

"},{"location":"bevezetes/gepterem/#geptermi-beallitasok-gyors-ellenorzese","title":"G\u00e9ptermi be\u00e1ll\u00edt\u00e1sok gyors ellen\u0151rz\u00e9se","text":"

Ellen\u0151rz\u00e9s

A k\u00f6vetkez\u0151 parancsokat futtasd le a g\u00e9ptermi termin\u00e1lban:

cd /mnt/kozos/script/\n./check_all.sh\n

"},{"location":"bevezetes/linux/","title":"Linux, git","text":"

A le\u00edr\u00e1sban alapvet\u0151 Linux ismeretek tal\u00e1lhat\u00f3k.

Linuxban (ebben a le\u00edr\u00e1sban \u00e9rtsd Ubuntu, Raspbian) a legt\u00f6bb munkamenetet lehets\u00e9ges, vagy \u00e9pp c\u00e9lszer\u0171 termin\u00e1lb\u00f3l v\u00e9grehajtani. Ez a tutorial seg\u00edt a linux termin\u00e1l alapjainak megismertet\u00e9s\u00e9ben.

Danger

Fontos, hogy a megszokott ctrl+v, ctrl+c helyett itt a ctrl+shift+v, ctrl+shift+c m\u0171k\u00f6dik. A ctr+c(megszak\u00edt\u00e1s billenty\u0171zetr\u0151l) pl. egy ROS node (program) befejez\u00e9s\u00e9re haszn\u00e1lhat\u00f3 itt.

"},{"location":"bevezetes/linux/#ajanlott-terminalprogramok","title":"Aj\u00e1nlott termin\u00e1lprogramok","text":"

Sz\u00e1mos program v\u00e1laszthat\u00f3 a sz\u00f6veges parancssor el\u00e9r\u00e9s\u00e9re. ROS/ROS2 eset\u00e9n tal\u00e1n a k\u00f6vetkez\u0151k a legjobb v\u00e1laszt\u00e1sok.

"},{"location":"bevezetes/linux/#windows-terminal","title":"Windows Terminal","text":"

Ahogy a neve is mutatja, ez a megold\u00e1s WSL eset\u00e9n, Windows-on relev\u00e1ns. El\u0151nye, hogy egy helyen haszn\u00e1lhatunk t\u00f6bb Linux disztrib\u00faci\u00f3t ak\u00e1r Windows parancssorral is. Ctrl-Shift-P billenty\u0171 kombin\u00e1ci\u00f3kkal, majd a Split down, Split left parancsokkal oszhatjuk sz\u00e9t hasonl\u00f3 m\u00f3don a termin\u00e1lt:

A Windows Terminal release oldalon let\u00f6lthet\u0151 telep\u00edt\u0151k\u00e9nt vagy zip form\u00e1tumban portable verzi\u00f3ban. A portable haszn\u00e1lathoz kit\u00f6m\u00f6r\u00edt\u00e9s ut\u00e1n egy \u00fcres .portable f\u00e1jlt kell elhelyezn\u00fcnk. \u00cdgy ak\u00e1r USB pendriveon is a megszokott be\u00e1ll\u00edt\u00e1sokkal haszn\u00e1lhatjuk. Egy ilyen portable verzi\u00f3 tal\u00e1lhat\u00f3 a g\u00e9ptermekben a K:\\ meghajt\u00f3n is (\\\\fs-kab.eik.sze.hu\\C100\\kozos\\GKNB_AUTM078_Auton\u00f3m_robotok_\u00e9s_j\u00e1rm\u0171vek_programoz\u00e1sa)

"},{"location":"bevezetes/linux/#terminator","title":"Terminator","text":"

Linuxon \u00e9rtelmezett termin\u00e1l, de telep\u00edteni kell.

sudo apt update\nsudo apt install terminator\n

Terminator-ban Ctrl-Shift-O, Ctrl-Shift-E billenty\u0171 kombin\u00e1ci\u00f3kkal oszthatjuk tov\u00e1bb az adott ablakot. Ctrl-Shift-W bez\u00e1rja az akt\u00edv ablakot.

"},{"location":"bevezetes/linux/#vs-code-terminal","title":"VS code terminal","text":"

A fejleszt\u0151k\u00f6rnyezet be\u00e9p\u00edtett termin\u00e1lja, mind Windowson, mind Linuxon m\u0171k\u00f6dik.

"},{"location":"bevezetes/linux/#fontosabb-terminal-parancsok","title":"Fontosabb terminal parancsok","text":""},{"location":"bevezetes/linux/#korabbi-parancsok","title":"Kor\u00e1bbi parancsok","text":"
  • Fel ny\u00edl\ud83d\udd3c vagy Le ny\u00edl\ud83d\udd3d - A k\u00f6zvetlen\u00fcl ezel\u0151tti parancsokat \u00e9rhetj\u00fck el \u00edgy.
  • Ctrl+R billenyt\u0171kombin\u00e1ci\u00f3val kor\u00e1bbi parancsok h\u00edvhat\u00f3k el\u0151, id\u0151renben egyre kor\u00e1bbiak
  • Ctrl+Shift+R billenyt\u0171kombin\u00e1ci\u00f3val kor\u00e1bbi parancsok h\u00edvhat\u00f3ak el\u0151, de id\u0151renben el\u0151re haladva

A megszokott ctrl+v, ctrl+c helyett itt a ctrl+shift+v, ctrl+shift+c m\u0171k\u00f6dik. A ctr+c pl. egy ROS node (program) befejez\u00e9s\u00e9re haszn\u00e1lhat\u00f3 itt.

"},{"location":"bevezetes/linux/#automatikus-kiegeszites","title":"Automatikus kieg\u00e9sz\u00edt\u00e9s","text":"
  • Tab billenyt\u0171vel az elkezdett parancsok eg\u00e9sz\u00edthet\u0151ek ki
  • Tab Tab billenyt\u0171kombin\u00e1ci\u00f3val az \u00f6sszes lehets\u00e9ges parancsot fogja kilist\u00e1zni
"},{"location":"bevezetes/linux/#keprnyotorles","title":"K\u00e9prny\u0151t\u00f6rl\u00e9s","text":"
  • Ctrl+L billenyt\u0171vel t\u00f6r\u00f6lhet\u0151ek a kor\u00e1bbi sz\u00f6vegek, \u00edgy jobban \u00e1tl\u00e1that\u00f3 lesz a terminal
"},{"location":"bevezetes/linux/#konyvtarak-kozotti-navigacio","title":"K\u00f6nyvt\u00e1rak k\u00f6z\u00f6tti navig\u00e1ci\u00f3","text":"
  • cd: adott k\u00f6nyvt\u00e1rba / mapp\u00e1ba t\u00f6rt\u00e9n\u0151 bel\u00e9p\u00e9s
  • pl cd ~/ros2_ws/src, cd ../..
  • ls: list\u00e1z\u00e1s: k\u00f6nyvt\u00e1rak, f\u00e1jlok
  • mkdir: k\u00f6nyvt\u00e1r k\u00e9sz\u00edt\u00e9se
  • pwd: aktu\u00e1lis munkak\u00f6nyvt\u00e1r ki\u00edrat\u00e1sa (print working directory)
  • cp: Ezzel a paranccsal tudunk m\u00e1solni (cp /file/helye /ahova/m\u00e1solni/akarod/, cp -r /a/k\u00f6nyvt\u00e1r/helye /ahova m\u00e1solni/akarod)
  • mv: Ezzel adott f\u00e1jlt vagy k\u00f6nyvt\u00e1rat tudunk mozgatni (\u00e1thelyezni) vagy \u00e1tnevezni (mv /a/f\u00e1jl/helye *f\u00e1jl \u00faj neve, mv /a/f\u00e1jl/helye /a/f\u00e1jl/\u00faj/helye)
  • rm: F\u00e1jlok t\u00f6rl\u00e9se (rm /a/f\u00e1jl/helye, rm -r /a/f\u00e1jlok/\u00e9s/mapp\u00e1k/helye) Az rm -r parancsn\u00e1l minden t\u00f6rl\u0151dni fog a meghat\u00e1rozott helyen.
  • rmdir: Egy \u00fcres k\u00f6nyvt\u00e1r t\u00f6rl\u00e9se
  • chmod: (change mode) Arra alkalmas, hogy megv\u00e1ltoztassuk a f\u00e1jlok / mapp\u00e1k hozz\u00e1f\u00e9r\u00e9si jogait. Tehetj\u00fck ezt p\u00e9ld\u00e1ul karakteres kapcsol\u00f3kkal (r, w, stb.), vagy okt\u00e1lisan (sz\u00e1mjegyekkel).
  • pl chmod +x my_python_node.py: v\u00e9grehajt\u00e1si (execute) jog hozz\u00e1ad\u00e1sa
  • pl chmod 777 everything.py: minden jog hozz\u00e1ad\u00e1sa
"},{"location":"bevezetes/linux/#chmod","title":"chmod","text":"N Sum rwx Permission 7 4(r)+ 2(w) + 1(x) rwx read, write and execute 6 4(r)+ 2(w) rw- read and write 5 4(r)+ 1(x) r-x read and execute 4 4(r) r-- read only 3 2(w)+ 1(x) -wx write and execute 2 2(w) -w- write only 1 1(x) --x execute only 0 0 --- none"},{"location":"bevezetes/linux/#konyvtarak","title":"K\u00f6nyvt\u00e1rak","text":"Hely Magyar\u00e1zat / A k\u00f6nyvt\u00e1rfa kiindul\u00f3pontja, gy\u00f6k\u00e9r /boot Rendszerind\u00edt\u00e1s, bootloader /bin A futtathat\u00f3 parancsok, binaries /sbin A rendszergazda parancsai, superuser/system bin /lib Az indul\u00e1shoz sz\u00fcks\u00e9ges osztott rendszerk\u00f6nyvt\u00e1rak -libraries- illetve, modulok, meghajt\u00f3programok /dev Eszk\u00f6z\u00f6k, mint p\u00e9ld\u00e1ul USB (ttyUSB0) - devices /etc Be\u00e1ll\u00edt\u00f3f\u00e1jlok, helyi ind\u00edt\u00f3 parancsok, jelszavak, h\u00e1l\u00f3zati be\u00e1ll\u00edt\u00f3k stb. helye. /home Itt tal\u00e1lhat\u00f3 minden felhaszn\u00e1l\u00f3 saj\u00e1t k\u00f6nyvt\u00e1rat. P\u00e9ld\u00e1ul ha a sanyi felhaszn\u00e1l\u00f3val vagyunk bel\u00e9pve, /home/sanyi tartalmazza a f\u00e1jljainkat. A /home/sanyi/Desktop, vagy r\u00f6viden ~/Desktop az asztalunk tartalma. /mnt A felcsatolt (mountolt) perif\u00e9ri\u00e1k, f\u00e1jlrendszerek helye, mount. /proc Process information /root A root user k\u00f6nyvt\u00e1ra /tmp Temp /usr Universal system resources, alkalmaz\u00e1sok, rendszereszk\u00f6z\u00f6k /var V\u00e1ltoz\u00f3 adatok, p\u00e9ld\u00e1ul nyomtat\u00e1si munk\u00e1k, email-ek"},{"location":"bevezetes/linux/#verziokezeles","title":"Verzi\u00f3kezel\u00e9s","text":"
  • git clone: git repo kl\u00f3noz\u00e1sa
  • git config --global user.name \"Sanyika\": felhszn\u00e1l\u00f3n\u00e9v be\u00e1ll\u00edt\u00e1sa
  • git config --global user.email \"sanyika@gggmail.com: email be\u00e1ll\u00edt\u00e1sa
  • git init: lok\u00e1lis rep\u00f3 inicializ\u00e1l\u00e1sa
  • git add <file>: f\u00e1jl hozz\u00e1ad\u00e1sa
  • git status: aktu\u00e1lis st\u00e1tusz lek\u00e9rdez\u00e9se
  • git commit -m \"My beautiful commit\": commit, \u00fczenettel
  • git push: push
  • git pull: pull
  • git branch <new_branch_name>: branch k\u00e9sz\u00edt\u00e9se
  • git checkout <branch_name>: \u00faj branch
  • git checkout -- .: Minden nem staged (unstaged) v\u00e1ltoz\u00e1s elvet\u00e9se lok\u00e1lisan. VS code-ban kb ez a \"discard all changes\" parancs. (\u00dajabb git verzi\u00f3kban a git restore . is hasonl\u00f3 m\u00f3don m\u0171k\u00f6dik.)
  • git merge <branch_name>: a jelenlegi branch-be mergeli a branch-t

Tip

A legt\u00f6bb m\u0171velet VS code-dal elv\u00e9gezhet\u0151 termin\u00e1l n\u00e9lk\u00fcl is. Err\u0151l b\u0151vebben itt lehet olvasni.

Forr\u00e1s: link

"},{"location":"bevezetes/linux/#szoveges-fajlok","title":"Sz\u00f6veges f\u00e1jlok","text":"
  • wget: webes tartalmak let\u00f6lt\u00e9se terminalb\u00f3l
  • cat: f\u00e1jl tartalm\u00e1nak ki\u00edrat\u00e1sa
  • touch: sz\u00f6veges f\u00e1jl l\u00e9trehoz\u00e1sa
  • pl. touch hello.txt
  • echo: ki\u00edrat\u00e1s, vagy f\u00e1jlba \u00edr\u00e1s (>> oper\u00e1tor). Amennyiben nem l\u00e9tezik a f\u00e1jl, l\u00e9trehozza (touch)
  • pl. echo \"hello\" >> hello.txt
  • pl. echo \"n = 5; print('\\n'.join(':D ' * i for i in range(1, n + 1)))\" >> hello.py
  • pl. ros2 topic list >> hello.txt
  • pl. ros2 topic echo --once /scan >> hello.txt
  • find: f\u00e1jl keres\u00e9se, pl a find ~/ros2_ws/src/ -name *.txt minden txt f\u00e1jlt megkeres a ~/ros2_ws/src k\u00f6nyvt\u00e1rban.
  • nano: sz\u00f6vegszerkeszt\u0151: egyszer\u0171, termin\u00e1l-alap\u00fa
  • code: sz\u00f6vegszerkeszt\u0151: GUI, VS code
  • pl. code . megnyintja az aktu\u00e1lis mappa tartalm\u00e1t
  • pl. code ~/.bashrc megnyintja a ~/.bashrc tartalm\u00e1t szerkeszt\u00e9sre
  • colcon: wrapper a cmake \u00e9s make parancsok egyszer\u0171bb haszn\u00e1lat\u00e1hoz, err\u0151l b\u0151vebben k\u00e9s\u0151bb
"},{"location":"bevezetes/linux/#telepites","title":"Telep\u00edt\u00e9s","text":"
  • sudo apt install vagy sudo apt-get install: szoftver csomagkezel\u0151vel t\u00f6rt\u00e9n\u0151 telep\u00edt\u00e9s, Advanced Packaging Tool (APT).
  • pl. sudo apt install tree mc - tree \u00e9s mc programok telep\u00edt\u00e9se
  • sudo: (Superuser do) Lehet\u0151v\u00e9 teszi, hogy rendszergazdak\u00e9nt vagy m\u00e1s felhaszn\u00e1l\u00f3 nev\u00e9ben hajtsunk v\u00e9gre parancsokat.
  • sudo apt update: csomagindex friss\u00edt\u00e9se, ha \u00faj verzi\u00f3k j\u00f6nnek ki k\u00fcl\u00f6nb\u00f6z\u0151 szoftverekb\u0151l, ezt a paracsot a telep\u00edt\u00e9s (apt install) el\u0151tt c\u00e9lszer\u0171 kiadni.
  • sudo apt update: m\u00e1r telep\u00edtett csomagok friss\u00edt\u00e9se
  • apt list: list\u00e1zza asz \u00f6sszes telep\u00edtett csomagot
  • pl. apt list | grep ros: lesz\u0171ri csak az ROS-hez kapcsol\u00f3d\u00f3 csomagokat
"},{"location":"bevezetes/linux/#tovabbi-hasznos-eszkozok","title":"Tov\u00e1bbi hasznos eszk\u00f6z\u00f6k","text":""},{"location":"bevezetes/linux/#navigacio","title":"Navig\u00e1ci\u00f3","text":"
  • Ctrl + a vagy home: A sor elej\u00e9re dob
  • Ctrl + e vagy end: A sor v\u00e9g\u00e9re dob
  • Ctrl + \u25c0 / Ctrl + \u25b6: Az el\u0151z\u0151 / k\u00f6vetkez\u0151 sz\u00f3ra ugrik
"},{"location":"bevezetes/linux/#grep","title":"grep","text":"
  • grep: (Global \\ Regular Expression \\ Print) f\u00e1jlokban illetve parancsok kimenet\u00e9ben keres
  • pl. grep 'ROS' ~/.bashrc: list\u00e1zza a bashrc f\u00e1jlban az ROS sz\u00f6veget tartalmaz\u00f3 sorokat
  • pl. ros2 topic list | grep pose: list\u00e1zza az \u00f6sszes topicot, amiben van pose string
"},{"location":"bevezetes/linux/#ssh","title":"ssh","text":"
  • ssh: (Secure Shell Protocol) linux g\u00e9pektbe t\u00e1voli terminal bejelentkez\u00e9st tesz lehet\u0151v\u00e9
  • pl. ssh nvidia@192.168.1.5: bel\u00e9p\u00e9s az adott user adott IP c\u00edmen l\u00e9v\u0151 g\u00e9p\u00e9be
  • pl. ssh user01@computer4 -X: bel\u00e9p\u00e9s -X X window haszn\u00e1lat\u00e1val, \u00edgy az esetleges ablakok a mi g\u00e9p\u00fcnk\u00f6n jelennek meg, de a t\u00e1voli g\u00e9p hostolja \u0151ket
  • pl. ssh laptop@192.168.0.2 touch hello.txt: l\u00e9trehoz az adott g\u00e9pen egy f\u00e1jlt, nyilv\u00e1n m\u00e1s parancsokkal is m\u0171k\u00f6dik
"},{"location":"bevezetes/linux/#gyakran-hasznalt-parancsok","title":"Gyakran haszn\u00e1lt parancsok","text":"
  • Fut\u00f3 folyamatokr\u00f3l a ps ad t\u00e1j\u00e9koztat\u00e1st pl: ps -A | grep ros vagy ps -eo pid,cmd | grep ros2
  • A f\u00e1jlrendszer \u00e1llapot\u00e1r\u00f3l a df -h (disk filesystem, human readable) parancs ad t\u00e1j\u00e9koztat\u00e1st

Az ssh alapvet\u0151en jelsz\u00f3t is k\u00e9r, de ha megb\u00edzunk egy adott g\u00e9pben, elmenthetj\u00fck a priv\u00e1t-publikus kulcsp\u00e1rt, \u00e9s akkor erre nincs sz\u00fcks\u00e9g, p\u00e9ld\u00e1ul \u00edgy.

"},{"location":"bevezetes/linux/#rsync-halozati-masolas","title":"rsync h\u00e1l\u00f3zati m\u00e1sol\u00e1s","text":"

H\u00e1l\u00f3zatba k\u00f6t\u00f6tt g\u00e9pek k\u00f6z\u00f6tti m\u00e1sol\u00e1s (remote sync), pl. egy Nvidia Jetson be\u00e1gyazott sz\u00e1m\u00edt\u00f3g\u00e9pr\u0151l a saj\u00e1t g\u00e9p\u00fcnk /mnt/c/bag/ mapp\u00e1j\u00e1ba t\u00f6rt\u00e9n\u0151 m\u00e1sol\u00e1s progress-barral \u00edgy n\u00e9z ki:

rsync -avzh --progress /mnt/kozos/measurement_files/lexus-2023-07-18-campus.mcap  /mnt/c/temp/\n
rsync -avzh --progress nvidia@192.168.1.5:/mnt/storage_1tb/2023-07-02/ /mnt/c/bag/2023-07-02/\n

"},{"location":"bevezetes/linux/#scp-halozati-masolas","title":"scp h\u00e1l\u00f3zati m\u00e1sol\u00e1s","text":"

H\u00e1l\u00f3zatba k\u00f6t\u00f6tt g\u00e9pek k\u00f6z\u00f6tti m\u00e1sol\u00e1s (az rsync alternat\u00edv\u00e1ja). A progress-bar sajnos nem minden rendszeren jelenik meg:

scp /mnt/kozos/measurement_files/lexus3sample02.mcap  /mnt/c/temp/\n
"},{"location":"bevezetes/linux/#screen","title":"screen","text":"

Virtu\u00e1lis termin\u00e1lokat ind\u00edt, kezel, p\u00e9ld\u00e1ul:

screen -m -d -S roscore bash -c roscore\nscreen -m -d -S campfly bash -c 'roslaunch drone_bringup campus_fly.launch'\nscreen -m -d -S rviz1 bash -c 'rosrun rviz rviz'\n

  • list screen: screen -ls
  • restore screen: screen -r roscore / screen -r campfly / screen -r rviz1
  • detach: Ctrl-a + Ctrl-d
  • kill: killall -9 screen and screen -wipe
"},{"location":"bevezetes/linux/#mc-fajlkezelo","title":"mc f\u00e1jlkezel\u0151","text":"

GNU Midnight Commander (mc), a Norton Commander inspir\u00e1lta f\u00e1jlkezel\u0151:

"},{"location":"bevezetes/linux/#nmtui","title":"nmtui","text":"

Az nmtui (Network Manager Text User Interface) terminal-alap\u00fa Wifi / Ethernet / H\u00e1l\u00f3zat konfigur\u00e1tor.

"},{"location":"bevezetes/linux/#nano-szovegszerkeszto","title":"nano sz\u00f6vegszerkeszt\u0151","text":"

Terminal alap\u00fa sz\u00f6vegszerkeszt\u0151. Szerkeszt\u00e9s ut\u00e1n Ctrl+X a kil\u00e9p\u00e9s, ut\u00e1na Y-t \u00fctve menti a f\u00e1jlt.

"},{"location":"bevezetes/linux/#htop-top","title":"htop / top","text":"

Az htop egy interakt\u00edv folyamatfigyel\u0151 parancs (nagyj\u00e1b\u00f3l a windows task manager funkcionalit\u00e1sa), amely megjelen\u00edti \u00e9s fel\u00fcgyeli a fut\u00f3 folyamatokat a rendszeren. Mem\u00f3ria- \u00e9s CPU-haszn\u00e1lat folymatonk\u00e9nt r\u00e9szletezve is kilvashat\u00f3, tov\u00e1bb\u00e1 van lehet\u0151s\u00e9g a kill haszn\u00e1lat\u00e1ra is.

"},{"location":"bevezetes/linux/#bashrc-fajl","title":"~/.bashrc f\u00e1jl","text":"

A bashrc f\u00e1jl (a ~ jelent\u00e9se, hogy user1 felhaszn\u00e1l\u00f3 eset\u00e9n a /home/user1/ mapp\u00e1ban tal\u00e1lhat\u00f3, a . jelent\u00e9se pedig, hogy rejtett f\u00e1jl) minden terminal indt\u00e1skor lefut\u00f3 f\u00e1jl. Teh\u00e1t, ha pl egy parancsot \u00edrunk bele, ami echo \"hello\" akkor minden terminal ind\u00edt\u00e1skor ki\u00edr egy hello \u00fczenetet. Szerkeszt\u00e9se nano/VS code sz\u00f6vegszerkeszt\u0151b\u0151l:

nano ~/.bashrc\ncode ~/.bashrc\n

Sz\u00e1munkra fontos k\u00f6rnyezeti v\u00e1ltoz\u00f3k pl:

export ROS_DOMAIN_ID=4\nexport ROS_LOCALHOST_ONLY=1\nexport GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models\nexport TURTLEBOT3_MODEL=waffle\nsource /opt/ros/humble/setup.bash\nsource ~/ros2_ws/install/setup.bash\n

A bashrc f\u00e1jl m\u00f3dos\u00edt\u00e1sa ut\u00e1n nem kell \u00faj termin\u00e1lt nyitni, ha kiadjuk a k\u00f6vetkez\u0151 parancsot:

source ~/.bashrc\n
"},{"location":"bevezetes/linux/#ros-1","title":"ROS 1","text":"

Tip

A fejezetben a r\u00e9gi ROS 1-es k\u00f6nyzeteti v\u00e1ltoz\u00f3kr\u00f3l van sz\u00f3, az \u00faj ROS 2-est a k\u00f6vetkez\u0151 fejezet tartalmazza.

Ki\u00edrathatjuk a k\u00f6rnyezeti v\u00e1ltoz\u00f3kat (environment variables) echo-val / printenv-vel pl:

echo $ROS_MASTER_URI\nprintenv ROS_MASTER_URI\n\nhttp://192.168.1.5:11311\n
echo $ROS_IP\nprintenv ROS_IP\n\n192.168.1.10\n

"},{"location":"bevezetes/linux/#ros-2","title":"ROS 2","text":"

ROS 2 fejezet

Ez az \u00faj, ROS 2-est tartalmaz\u00f3 fejezet.

Ki\u00edrathatjuk a k\u00f6rnyezeti v\u00e1ltoz\u00f3kat (environment variables) echo-val / printenv-vel pl:

echo $ROS_DISTRO\nprintenv ROS_DISTRO\n\nhumble\n
echo $AMENT_PREFIX_PATH\nprintenv AMENT_PREFIX_PATH\n\n/opt/ros/humble\n

printenv | grep -i ROS\n\nROS_VERSION=2\nROS_PYTHON_VERSION=3\nROS_DISTRO=humble\n
"},{"location":"bevezetes/linux/#gazebo-es-wsl","title":"Gazebo \u00e9s WSL","text":"

Gazebo szimul\u00e1tort \u00e9s WSL-t haszn\u00e1lva el\u0151fordulhat egy issue, ami egy egyszer\u0171 k\u00f6rnyezeti v\u00e1ltoz\u00f3 be\u00e1ll\u00edt\u00e1s\u00e1val jav\u00edthat\u00f3. A ~/.bashrc f\u00e1jlban a k\u00f6vetkez\u0151t kell be\u00e1ll\u00edtani.

export LIBGL_ALWAYS_SOFTWARE=1 ### GAZEBO IGNITION \n

\u00daj termin\u00e1l vagy source ut\u00e1n a echo $LIBGL_ALWAYS_SOFTWARE parancsra 1-et fog ki\u00edni.

"},{"location":"bevezetes/linux/#branch-megjelenitese-linux-bash-ben","title":"Branch megjelen\u00edt\u00e9se Linux bash-ben","text":"

Opcion\u00e1lis, de hasznos lehet: Keress\u00fck meg \u00e9s m\u00f3dos\u00edtsuk a ~/.bashrc f\u00e1jlban a k\u00f6vetkez\u0151 r\u00e9szt.

(VS code haszn\u00e1lat\u00e1val a k\u00f6vetkez\u0151 parancs: code ~/.bashrc)

if [ \"$color_prompt\" = yes ]; then\n    PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[00m\\]\\$ '\nelse\n    PS1='${debian_chroot:+($debian_chroot)}\\u@\\h:\\w\\$ '\nfi\nunset color_prompt force_color_prompt\n

Miut\u00e1n megvan, cser\u00e9lj\u00fck a k\u00f6vetkez\u0151 r\u00e9szre:

parse_git_branch() {\n git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/(\\1)/'\n}\nif [ \"$color_prompt\" = yes ]; then\n PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[01;31m\\]$(parse_git_branch)\\[\\033[00m\\]\\n\\$ '\nelse\n PS1='${debian_chroot:+($debian_chroot)}\\u@\\h:\\w$(parse_git_branch)\\\\n$ '\nfi\n
vagy ugyanez \u00faj sorban kezd\u00e9s n\u00e9lk\u00fcl:
parse_git_branch() {\n git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/(\\1)/'\n}\nif [ \"$color_prompt\" = yes ]; then\n PS1='${debian_chroot:+($debian_chroot)}\\[\\033[01;32m\\]\\u@\\h\\[\\033[00m\\]:\\[\\033[01;34m\\]\\w\\[\\033[01;31m\\]$(parse_git_branch)\\[\\033[00m\\]\\$ '\nelse\n PS1='${debian_chroot:+($debian_chroot)}\\u@\\h:\\w$(parse_git_branch)\\$ '\nfi\n

Ments\u00fcnk, majd a source ~/.bashrc, illetve minden \u00faj termin\u00e1lnyit\u00e1s hat\u00e1s\u00e1ra git repository-t tartalmaz\u00f3 k\u00f6nyvt\u00e1rban a k\u00f6vetkez\u0151h\u00f6z hasonl\u00f3 bash fogad majd minket:

Forr\u00e1s: Ubuntu magyar dokument\u00e1ci\u00f3s projekt CC by-sa 2.5, \u00d3buda University CC BY-NC-SA 4.0

"},{"location":"bevezetes/practice/","title":"Bevezet\u00e9s gyakorlat","text":"

A gyakorlat sor\u00e1n meg fogunk ismerkedni az \u00f6nvezet\u0151 j\u00e1rm\u0171vek jellemz\u0151 tulajdons\u00e1gaival \u00e9s a r\u00f6gz\u00edtett adatok jellegzetess\u00e9geivel.

"},{"location":"bevezetes/practice/#foxglove-studio","title":"Foxglove Studio","text":"

Bevezet\u00e9sk\u00e9ppen n\u00e9zz\u00fck egy \u00f6nvezet\u0151 j\u00e1rm\u0171 jellemz\u0151 adatait. P\u00e9ldak\u00e9pp c\u00e9lszer\u0171 az egyetem\u00fcnk egyik ilyen j\u00e1rm\u0171v\u00e9vel k\u00e9sz\u00fclt adatokat vizsg\u00e1lni. Foxglove Studio-t fogunk haszn\u00e1lni, hiszen telep\u00edt\u00e9s n\u00e9lk\u00fcl, vagy ~150MB m\u00e9ret\u0171 telep\u00edthet\u0151 \u00e1llom\u00e1nyk\u00e9nt is hozz\u00e1f\u00e9rhet\u0151, valamint k\u00e9pes vizualiz\u00e1lni a sz\u00e1munkra fontos adatokat. A vizsg\u00e1lt adatok hasonl\u00f3 k\u00e9pet fognak mutatni:

\u00d3r\u00e1n a K:\\ meghajt\u00f3r\u00f3l (\\\\fs-kab.eik.sze.hu\\C100\\kozos\\GKNB_AUTM078_Auton\u00f3m_robotok_\u00e9s_j\u00e1rm\u0171vek_programoz\u00e1sa), otthon a z\u00f6ld gombot haszn\u00e1lva t\u00f6lts\u00fck le a fent vizualiz\u00e1lt rosbag .bag / .mcap f\u00e1jlt \u00e9s a Foxglove Studio layout-ot:

MCAP let\u00f6lt\u00e9se 553 MB Layout let\u00f6lt\u00e9se

cd /mnt/c/temp\nmkdir /mnt/c/temp # ha nem l\u00e9tezne\nrsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap /mnt/c/temp/\nrsync -avzh --progress /mnt/kozos/measurement_files/lexus01foxglove.json   /mnt/c/temp/\n

Tip

A https://jkk-research.github.io/dataset oldalr\u00f3l tov\u00e1bbi p\u00e9lda adatokat lehet let\u00f6lteni.

"},{"location":"bevezetes/practice/#a-foxglove-bemutatasa","title":"A Foxglove bemutat\u00e1sa","text":"

Am\u00edg az .mcap t\u00f6lt\u0151dik, r\u00f6viden bemutatjuk a Foxglove Studio programot. A Foxglove Studio egy ny\u00edlt forr\u00e1sk\u00f3d\u00fa, robotikai adatokat vizualiz\u00e1l\u00f3 \u00e9s hibakeres\u0151 eszk\u00f6z. Eg\u00e9sz pontosan a v1.87.0-ig bez\u00e1r\u00f3lag ny\u00edlt forr\u00e1sk\u00f3du volt, a v2.0.0-t\u00f3l pedig ingyenesen haszn\u00e1lhat\u00f3, de z\u00e1rt forr\u00e1sk\u00f3d\u00fa. El\u00e9rhet\u0151 sz\u00e1mos m\u00f3don:

  • \u00f6n\u00e1ll\u00f3 asztali alkalmaz\u00e1sk\u00e9nt futtathat\u00f3
  • b\u00f6ng\u00e9sz\u0151ben hozz\u00e1f\u00e9rhet\u0151
  • saj\u00e1t domainen, \u00f6n\u00e1ll\u00f3an hostolhat\u00f3

A nat\u00edv robotikai eszk\u00f6z\u00f6k (mint p\u00e9ld\u00e1ul az ROS \u00f6kosziszt\u00e9ma r\u00e9szei) \u00e1ltal\u00e1ban csak Linux rendszeren t\u00e1mogatottak, de a Studio asztali alkalmaz\u00e1s Linuxon, Windows-on \u00e9s macOS-en is m\u0171k\u00f6dik. Ak\u00e1r az ROS stack m\u00e1s oper\u00e1ci\u00f3s rendszeren fut, a Studio k\u00e9pes kommunik\u00e1lni a robottal z\u00f6kken\u0151mentesen.

A Studio gazdag vizu\u00e1lis elemeket \u00e9s hibakeres\u0151 panelokat k\u00edn\u00e1l - interakt\u00edv diagramokt\u00f3l, 3D vizu\u00e1lis elemekig, kamerak\u00e9pekt\u0151l, \u00e9s diagnosztikai adatfolyamokig. Legyen sz\u00f3 val\u00f3s idej\u0171 robotk\u00f6vet\u00e9sr\u0151l, vagy .bag / .mcap f\u00e1jlban t\u00f6rt\u00e9n\u0151 hibakeres\u00e9sr\u0151l, ezek a panelok seg\u00edtenek a k\u00fcl\u00f6nb\u00f6z\u0151, \u00e1ltal\u00e1nos robotikai feladatok megold\u00e1s\u00e1ban.

Ezek a panelok ezut\u00e1n egyedi elrendez\u00e9sekben konfigur\u00e1lhat\u00f3k \u00e9s \u00f6ssze\u00e1ll\u00edthat\u00f3k a projekt egyedi ig\u00e9nyeinek \u00e9s munkafolyamatainak megfelel\u0151en.

"},{"location":"bevezetes/practice/#az-egytemi-nissan-meresadatainak-leirasa","title":"Az egytemi Nissan m\u00e9r\u00e9sadatainak le\u00edr\u00e1sa","text":"

ROS rendszerben (de m\u00e1s hasonl\u00f3 robotikai megold\u00e1sokban is) az egyes adatok topic-okba szervez\u0151dve vannak publik\u00e1lva. Egy topic lehet p\u00e9ld\u00e1ul egy szenzor kimenete, egy szab\u00e1lyz\u00f3 bemenete, vizualiz\u00e1ci\u00f3s marker stb. A topicoknak t\u00edpusuk van, rengeteg el\u0151re defini\u00e1lt t\u00edpus l\u00e9tezik, de l\u00e9trehozhatunk saj\u00e1tot is, ha ezek nem lenn\u00e9nek elegek. P\u00e9ldak\u00e9pp p\u00e1r el\u0151re defini\u00e1lt t\u00edpus:

  • sensor_msgs/Image - T\u00f6m\u00f6r\u00edt\u00e9s n\u00e9lk\u00fcli k\u00e9pi inform\u00e1ci\u00f3, jellemz\u0151en a kamer\u00e1t\u00f3l j\u00f6n, de lehet feldolgozott adat, amin p\u00e9ld\u00e1ul jel\u00f6lve vannak a gyalogosok is.
  • sensor_msgs/CompressedImage - T\u00f6m\u00f6r\u00edtett k\u00e9pi inform\u00e1ci\u00f3.
  • std_msgs/String - Egyszer\u0171 sz\u00f6veges \u00fczenett\u00edpus.
  • std_msgs/Bool - Egyszer\u0171 bin\u00e1ris \u00fczenett\u00edpus.
  • geometry_msgs/Point - XYZ 3D pont.
  • geometry_msgs/Pose - 3D pont \u00e9s a hozz\u00e1 tartoz\u00f3 orient\u00e1ci\u00f3.

Ahogy l\u00e1tszik, a t\u00edpusok k\u00fcl\u00f6nb\u00f6z\u0151 kateg\u00f3ri\u00e1kba esnek, \u00fagy mint: std_msgs, diagnostic_msgs, geometry_msgs, nav_msgs, sensor_msgs stb. N\u00e9zz\u00fck, milyen t\u00edpus\u00fa \u00fczenetek tal\u00e1lhat\u00f3k a let\u00f6lt\u00f6tt f\u00e1jlban:

Topic T\u00edpus Hz Szenzor /gps/duro/current_pose geometry_msgs/PoseStamped 10 Duro GPS (UTM) /gps/duro/imu sensor_msgs/Imu 200 Duro GPS /gps/duro/mag sensor_msgs/MagneticField 25 Duro GPS /gps/nova/current_pose geometry_msgs/PoseStamped 20 Novatel GPS (UTM) /gps/nova/imu sensor_msgs/Imu 200 Novatel GPS /left_os1/os1_cloud_node/imu sensor_msgs/Imu 100 Ouster LIDAR /left_os1/os1_cloud_node/points sensor_msgs/PointCloud2 20 Ouster LIDAR /right_os1/os1_cloud_node/imu sensor_msgs/Imu 100 Ouster LIDAR /right_os1/os1_cloud_node/points sensor_msgs/PointCloud2 20 Ouster LIDAR /velodyne_left/velodyne_points sensor_msgs/PointCloud2 20 Velodyne LIDAR /velodyne_right/velodyne_points sensor_msgs/PointCloud2 20 Velodyne LIDAR /cloud sensor_msgs/PointCloud2 25 SICK LIDAR /scan sensor_msgs/LaserScan 25 SICK LIDAR /zed_node/left/camera_info sensor_msgs/CameraInfo 30 ZED kamera /zed_node/left/image_rect_color/compressed sensor_msgs/Image 20 ZED kamera /vehicle_status autoware_msgs/VehicleStatus 100 CAN adatok /ctrl_cmd autoware_msgs/ControlCommandStamped 20 Referencia sebess\u00e9g \u00e9s kormy\u00e1nsz\u00f6g /current_pose geometry_msgs/PoseStamped 20 Aktu\u00e1lis GPS /tf tf2_msgs/TFMessage 500+ Transform"},{"location":"bevezetes/practice/#hazi-feladat","title":"H\u00e1zi feladat","text":"

H\u00e1zi feladat

Otthon reproduk\u00e1ljuk a gyakorlatot, \u00e9s vizsg\u00e1ljuk meg a let\u00f6lt\u00f6tt adatokat a Foxglove Studio seg\u00edts\u00e9g\u00e9vel. A vizsg\u00e1lat sor\u00e1n a k\u00f6vetkez\u0151 k\u00e9rd\u00e9sekre keress\u00fck a v\u00e1laszt:

  • M\u00e9terben kifejezve milyen t\u00e1vols\u00e1gokra tal\u00e1lhat\u00f3ak az objektumok a j\u00e1rm\u0171t\u0151l?
  • Milyen sebess\u00e9ggel halad a j\u00e1rm\u0171?
  • Milyen ir\u00e1nyban halad a j\u00e1rm\u0171?
"},{"location":"bevezetes/ros2/","title":"ROS 2 alapfoglamak","text":"

ROS verzi\u00f3k \u00e9s telep\u00edt\u00e9s

Az ROS 2, a ROS leg\u00fajabb kiad\u00e1sa, olyan szoftverk\u00f6nyvt\u00e1rak \u00e9s eszk\u00f6z\u00f6k k\u00e9szlete (middleware), amelyek seg\u00edtenek robotalkalmaz\u00e1sok fejleszt\u00e9s\u00e9ben. Defin\u00edci\u00f3 szerint a middleware egy szoftver komponenseket \u00f6sszek\u00f6t\u0151 szoftver. Ez egy olyan r\u00e9teg, amely az oper\u00e1ci\u00f3s rendszer \u00e9s az alkalmaz\u00e1sok k\u00f6z\u00f6tt helyezkedik el az elosztott sz\u00e1m\u00edt\u00f3g\u00e9pes h\u00e1l\u00f3zat mindk\u00e9t oldal\u00e1n. Az ROS 2 megenged\u0151, ny\u00edlt forr\u00e1sk\u00f3d\u00fa, Apache 2.0 licenszel\u00e9st haszn\u00e1l.

ROS 2 \u00e1ttekint\u00e9s

A ROS 2007-es kiad\u00e1sa \u00f3ta inkrement\u00e1lis friss\u00edt\u00e9seken esett \u00e1t, teh\u00e1t fundament\u00e1lis v\u00e1ltoz\u00e1sok nem, nagyobb fejleszt\u00e9sek viszont folyamatosan t\u00f6rt\u00e9ntek. 2017-ben j\u00f6tt r\u00e1 a robotikai k\u00f6z\u00f6ss\u00e9g, hogy olyan alapvet\u0151 limit\u00e1ci\u00f3i vannak az eredeti 2007-es elk\u00e9pzel\u00e9snek, amit ilyen inkrement\u00e1lis m\u00f3don sajnos nem lehet jav\u00edtani. \u00cdgy v\u00e9g\u00fcl a Noetic Ninjemis (2025-ig t\u00e1mogatva) az ROS 1 utols\u00f3 kiad\u00e1sa, helyette p\u00e1rhuzamosan elkezdt\u00e9k fejleszteni az ROS 2-t. Ez egyben azt is jelenteti, hogy a kor\u00e1bbi forr\u00e1sk\u00f3dokat nehezebben lehet portolni az \u00faj verzi\u00f3ra, cser\u00e9be rengeteg \u00fajdons\u00e1got, jav\u00edt\u00e1st, t\u00e1mogat\u00e1st kaphatunk a fejlesztend\u0151 robotok, j\u00e1rm\u0171vek sz\u00e1m\u00e1ra.

A fentiek hat\u00e1s\u00e1ra teh\u00e1t az ROS 2 \u00e1tl\u00e9pett az akad\u00e9miai kutat\u00e1sok vil\u00e1g\u00e1b\u00f3l az ipari fehaszn\u00e1l\u00e1sra. \u00c9rdekess\u00e9g, hogy a NASA VIPER nev\u0171 holdj\u00e1r\u00f3ja is ROS 2-t futtat. Emellett olyan aut\u00f3ipari \u00f3ri\u00e1sok is haszn\u00e1lj\u00e1k, mint a Bosch, a BMW vagy a Volvo. Robotikai c\u00e9gek k\u00f6z\u00fcl pedig sz\u00e1mos tov\u00e1bbi p\u00e9ld\u00e1t lehetne hozni. Linkek: www.nasa.gov/viper/lunar-operations, rosindustrial.org/ric/current-members, www.bosch.com/stories/bringing-robotics-middleware-onto-tiny-microcontrollers. ROS felhaszn\u00e1l\u00f3k a vil\u00e1gban: metrorobots.com/rosmap.html.

K\u00e9p forr\u00e1sa: Robot Operating System 2: Design, Architecture, and Uses In The Wild: Steve Macenski et al.

"},{"location":"bevezetes/ros2/#miert-hasznaljak-framework-ot-robotikai-projektemhez","title":"Mi\u00e9rt haszn\u00e1ljak framework-\u00f6t robotikai projektemhez?","text":"

Els\u0151 robotikai projekt\u00fcnkn\u00e9l v\u00e1laszthatjuk azt az utat, hogy framework n\u00e9lk\u00fcl teljesen saj\u00e1t megold\u00e1sk\u00e9nt feljeszt\u00fcnk. Nyilv\u00e1n ennek is vannak el\u0151nyei (tanul\u00e1s, fut\u00e1si gyorsas\u00e1g, stb.). De hamarosan kelleni fog olyan algoritmus, amit ak\u00e1r m\u00e1sok implement\u00e1ltak is, csak nem kompatibilis az eredeti elk\u00e9pzel\u00e9ssel. Itt m\u00e1r c\u00e9lszer\u0171 meggondolni egy framework (pl a ROS 2) haszn\u00e1lat\u00e1t. Megjegyz\u00e9s, hogy nem a ROS 2 az egyetlen lehet\u0151s\u00e9g sz\u00e1mos hasonl\u00f3, kisebb framework l\u00e9tezik: Player, YARP, Orocos, CARMEN, Orca, MOOS, and Microsoft Robotics Studio. Niylv\u00e1n mindegyiknek van el\u0151nye, ebben a t\u00e1rgyban a t\u00e1mogatotts\u00e1g miatt m\u00e9gis az ROS 2-re szor\u00edthozunk.

K\u00e9p forr\u00e1sa: ros.org/blog/ecosystem

  • Plumbing: A ROS alapvet\u0151en egy \u00fczenetk\u00fcld\u0151 rendszert biztos\u00edt, amelyet gyakran \"middleware\"-nek vagy \"plumbing\"-nek neveznek. A kommunik\u00e1ci\u00f3 az egyik els\u0151 ig\u00e9ny, amely felmer\u00fcl egy \u00faj robotikai alkalmaz\u00e1s vagy b\u00e1rmilyen olyan szoftverrendszer implement\u00e1l\u00e1sakor, amelyhez hardverrel is csatlakozik. A ROS be\u00e9p\u00edtett \u00e9s j\u00f3l tesztelt \u00fczenetk\u00fcld\u0151 rendszere id\u0151t takar\u00edthat meg, hiszen kezeli a kommunik\u00e1ci\u00f3 r\u00e9szleteit a decentraliz\u00e1lt csom\u00f3pontok k\u00f6z\u00f6tt, ezt nem kell k\u00fcl\u00f6n implement\u00e1lni. S\u0151t lehet\u0151s\u00e9g van egy g\u00e9pen Intra-process kommunik\u00e1ci\u00f3 seg\u00edts\u00e9g\u00e9vel direkt mem\u00f3ria el\u00e9r\u00e9sre is.
  • Eszk\u00f6z\u00f6k: A hat\u00e9kony alkalmaz\u00e1sok fejleszt\u00e9s\u00e9hez j\u00f3 fejleszt\u0151i eszk\u00f6z\u00f6kre van sz\u00fcks\u00e9g. A ROS rendelkezik ilyen az eszk\u00f6z\u00f6kkel, bele\u00e9rtve: a hibakeres\u00e9st (rqt_console), a vizualiz\u00e1ci\u00f3t (Rviz2, Foxglove Studio), a diagramokat (rqt_plot, Foxglove Studio), a logol\u00e1st (mcap) \u00e9s a visszaj\u00e1tsz\u00e1st.
  • K\u00e9pess\u00e9gek: Legyen sz\u00f3 GPS-eszk\u00f6z-illeszt\u0151programr\u00f3l, n\u00e9gyl\u00e1b\u00fa robothoz val\u00f3 j\u00e1r\u00e1s- \u00e9s egyens\u00falyszab\u00e1lyoz\u00f3r\u00f3l, vagy mobil robothoz val\u00f3 t\u00e9rk\u00e9pez\u0151rendszerr\u0151l, a ROS-nak vannak megold\u00e1sai a probl\u00e9m\u00e1ra. A driverekt\u0151l az algoritmusokig, a felhaszn\u00e1l\u00f3i fel\u00fcletekig a ROS biztos\u00edtja azokat az \u00e9p\u00edt\u0151elemeket, amelyek lehet\u0151v\u00e9 teszik, hogy a saj\u00e1t alkalmaz\u00e1s\u00e1ra koncentr\u00e1ljon.
  • K\u00f6z\u00f6ss\u00e9g: A ROS m\u00f6g\u00f6tt egy nagy, glob\u00e1lis \u00e9s v\u00e1ltozatos k\u00f6z\u00f6ss\u00e9g \u00e1ll. Di\u00e1kokt\u00f3l \u00e9s hobbib\u00f3l \u0171z\u0151kt\u0151l kezdve multinacion\u00e1lis v\u00e1llalatokig \u00e9s korm\u00e1nyzati \u00fcgyn\u00f6ks\u00e9gekig, az emberek \u00e9s szervezetek minden szegmense m\u0171k\u00f6dteti az ROS 2 projektet. Ez az\u00e9rt is fontos, mert a fejleszt\u00e9s sor\u00e1n rengeteg k\u00e9rd\u00e9s fog felmer\u00fclni. Ezek nagy r\u00e9sz\u00e9t m\u00e1r meg is v\u00e1laszolta ak\u00f6z\u00f6ss\u00e9g, az \u00faj k\u00e9rd\u00e9sekre pedig sz\u00edvesen v\u00e1laszolnak.

A k\u00f6vetkez\u0151 \u00e1bra egy egyszer\u0171 vonalk\u00f6vet\u0151 robot node-jait (programjait) \u00e9s topic-jait (~kommunk\u00e1ci\u00f3) szeml\u00e9ltei:

graph TD;\n\n    camd([/cam_driver]):::red --> im1[ /image1<br/>sensor_msgs/Image]:::light\n    im1 --> li1([ /line_detect_node]):::red\n    im1 --> st1([ /stop_detect_node]):::red\n    li1 --> li2[ /line<br/>example_msgs/Line]:::light\n    st1 --> st2[ /stop<br/>example_msgs/Stop]:::light\n    li2 --> nav([ /line_detect_node]):::red\n    st2 --> nav\n    nav --> cmd[ /cmd_vel<br/>geometry_msgs/Twist]:::light\n    cmd --> control([ /robot_control]):::red\n    n1([ /node]):::white -- publishes --> t[ /topic<br/>msg_type]:::white\n    t -- subscribes --> n2([ /node]):::white\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff

Forr\u00e1s: Bestmann, Marc & Fakult\u00e4t, Min & Zhang, Jianwei & Hendrich, N.. (2017). Towards Using ROS in the RoboCup Humanoid Soccer League. Masterthesis

N\u00e9zz\u00fcnk egy m\u00e1sik p\u00e9ld\u00e1t, ami sebess\u00e9gadatokb\u00f3l, IMU-b\u00f3l, t\u00e1vols\u00e1gadatokb\u00f3l k\u00e9sz\u00edt t\u00e9rk\u00e9peket.

graph LR;\n\n    odom[ /odom<br/>nav_msgs/Odometry]:::light --> slam([ /slam_node]):::red\n    speed[ /speed<br/>geometry_msgs/Twist]:::light --> slam\n    imu[ /imu<br/>sensor_msgs/Imu]:::light --> slam\n    scan[ /scan<br/>sensor_msgs/PointCloud2]:::light --> slam\n    n1([ /node]):::white -- publishes --> t[ /topic<br/>msg_type]:::white\n    slam --> pose[ /global_pose<br/>geometry_msgs/Pose]:::light\n    slam --> map_g[ /map_grid<br/>nav_msgs/OccupancyGrid]:::light\n    slam --> map_p[ /map_points<br/>sensor_msgs/PointCloud2]:::light\n    t -- subscribes --> n2([ /node]):::white\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
"},{"location":"bevezetes/ros2/#ros-2-mappaszerkezet","title":"ROS 2 mappaszerkezet","text":"
~/ros2_ws$ ls\n\nbuild  install  log  src\n
graph TD;\n\n    W1{{ Workspace</br>pl. ros2_ws }}:::light --> S1{{ Source space</br>src }}:::white\n    W1 --> B1{{ Build space</br>build }}:::white\n    W1 --> I1{{ Install space</br>install }}:::white\n    W1 --> L1{{ Log space</br>log }}:::white\n    S1 --> P1{{ package1 }}:::white\n    S1 --> P2{{ package2 }}:::white\n    S1 --> P3{{ bundle_packages }}:::white\n    P1 --> LA1{{ launch }}:::white\n    P1 --> SR1{{ src }}:::white\n    P2 --> LA2{{ launch }}:::white\n    P2 --> SR2{{ src }}:::white\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
graph TD;\n\n    W2{{ other_ws }}:::light --> S2{{ src }}:::white\n    W2 --> B2{{ build }}:::white\n    W2 --> I2{{ install }}:::white\n    W2 --> L2{{ log }}:::white\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
~/ros2_ws/\n\u251c\u2500\u2500build  \n\u251c\u2500\u2500install  \n\u251c\u2500\u2500log\n\u2514\u2500\u2500src/\n    \u251c\u2500\u2500 bundle_packages \n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 cone_detection_lidar\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 launch\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 src\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 my_vehicle_bringup\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 launch\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 other bundle package1\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 other bundle package2\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 img\n    \u2514\u2500\u2500 wayp_plan_tools\n        \u251c\u2500\u2500 csv\n        \u251c\u2500\u2500 launch\n        \u2514\u2500\u2500 src\n
"},{"location":"bevezetes/ros2/#kulonbsegek-az-ros-1-es-ros-2-kozott","title":"K\u00fcl\u00f6nbs\u00e9gek az ROS 1 \u00e9s ROS 2 k\u00f6z\u00f6tt","text":"
  • V\u00e1ltoz\u00e1sok a Middleware-ben A ROS 1 a Master-Slave architekt\u00far\u00e1t \u00e9s az XML-RPC middleware-t haszn\u00e1lja. A ROS 2 ezzel szemben a Data Distribution Service (DDS) haszn\u00e1l, amely nagyobb hat\u00e9konys\u00e1got \u00e9s megb\u00edzhat\u00f3s\u00e1got, alacsony k\u00e9sleltet\u00e9st \u00e9s sk\u00e1l\u00e1zhat\u00f3s\u00e1got, valamint konfigur\u00e1lhat\u00f3 szolg\u00e1ltat\u00e1smin\u0151s\u00e9gi (QoS) param\u00e9tereket biztos\u00edt. T\u00f6bbek k\u00f6z\u00f6tt \u00edgy nem kell roscore-t ind\u00edtani. Az XML-RPC jobb az egyszer\u0171 t\u00e1voli elj\u00e1r\u00e1sh\u00edv\u00e1sokhoz, m\u00edg a DDS hozz\u00e1adott komplexit\u00e1sa lehet\u0151v\u00e9 teszi, hogy jobban t\u00e1mogassa a val\u00f3s idej\u0171 rendszereket.
  • V\u00e1ltoz\u00e1sok a ROS API-ban A ROS 1 k\u00e9t k\u00fcl\u00f6n\u00e1ll\u00f3 k\u00f6nyvt\u00e1rral rendelkezik: a C++ nyelvhez k\u00e9sz\u00fclt roscpp \u00e9s a Pythonhoz k\u00e9sz\u00fclt rospy. Ezek nem teljesen azonosak egym\u00e1ssal a funkci\u00f3k tekintet\u00e9ben. Ezzel szemben a ROS 2 egy C nyelven \u00edrt alapk\u00f6nyvt\u00e1rral - rcl (ROS kliensk\u00f6nyvt\u00e1r) - rendelkezik, amelyre k\u00f6nyvt\u00e1rak \u00e9p\u00fclnek. Ez biztos\u00edtja, hogy az alapvet\u0151 funkci\u00f3k hamarabb el\u00e9rhet\u0151k legyenek a k\u00fcl\u00f6nb\u00f6z\u0151 API-kban. Ez az egyik f\u0151 oka annak, hogy a ROS 2 a kor\u00e1bbi Pythonon \u00e9s a C++-on k\u00edv\u00fcl t\u00f6bb nyelvi t\u00e1mogat\u00e1st is k\u00e9pes ny\u00fajtani: p\u00e9ld\u00e1ul rclada Ada, rclcpp C++, rclgo Go, rclpy Python, rcljava Java, rclnodejs Node.js, rclobjc Objective C (iOS), rclc C, ros2_rust Rust, ros2_dotnet .NET, ros2cs ros2_dotnet alternat\u00edva C# nyelven.

  • V\u00e1ltoz\u00e1sok az adatform\u00e1tumban A ROS 2 az MCAP form\u00e1tumot haszn\u00e1lja, ami nem dedik\u00e1ltan az ROS saj\u00e1t form\u00e1tuma, hanem egy ny\u00edlt forr\u00e1sk\u00f3d\u00fa kont\u00e9nerf\u00e1jl-form\u00e1tum multimod\u00e1lis log-adatokhoz. T\u00e1mogatja az id\u0151b\u00e9lyegz\u0151vel ell\u00e1tott, el\u0151re sorba rendezett adatokat, \u00e9s ide\u00e1lis a pub/sub vagy robotikai alkalmaz\u00e1sokban val\u00f3 haszn\u00e1latra. B\u0151vebben: mcap.dev

"},{"location":"bevezetes/ros2/#par-hasznos-ujitas","title":"P\u00e1r hasznos \u00faj\u00edt\u00e1s","text":"
  • Val\u00f3s idej\u0171 feldolgoz\u00e1s A fenti funkci\u00f3k \u00f6sszegz\u00e9se, valamint a DDS haszn\u00e1lata lehet\u0151v\u00e9 teszi, hogy a ROS 2 kiv\u00e1l\u00f3an alkalmas legyen a val\u00f3s idej\u0171 (real time) feldolgoz\u00e1sra, k\u00fcl\u00f6n\u00f6sen akkor, ha determinisztikus, alacsony k\u00e9sleltet\u00e9s\u0171 kommunik\u00e1ci\u00f3ra van sz\u00fcks\u00e9g.
  • QoS: Quality of Service A ROS 2 lehet\u0151v\u00e9 teszi az adat\u00e1raml\u00e1s konfigur\u00e1l\u00e1s\u00e1t, ami befoly\u00e1solja az adatok k\u00fcld\u00e9s\u00e9nek \u00e9s fogad\u00e1s\u00e1nak m\u00f3dj\u00e1t. Ez mag\u00e1ban foglalja az \u00fczenetek megb\u00edzhat\u00f3s\u00e1g\u00e1ra, hat\u00e1ridej\u00e9re \u00e9s priorit\u00e1s\u00e1ra vonatkoz\u00f3 be\u00e1ll\u00edt\u00e1sokat, amelyek biztos\u00edthatj\u00e1k, hogy a kritikus \u00fczenetek id\u0151ben k\u00e9zbes\u00edt\u00e9sre ker\u00fcljenek.
  • T\u00f6bbsz\u00e1l\u00fa v\u00e9grehajt\u00e1s A ROS 2 t\u00e1mogatja a t\u00f6bb csom\u00f3pont val\u00f3ban p\u00e1rhuzamos futtat\u00e1s\u00e1t, \u00edgy a modern t\u00f6bbmagos processzorok sokkal jobban kihaszn\u00e1lhat\u00f3k, mint a ROS 1 eset\u00e9ben.

Forr\u00e1s: husarnet.com/blog/ros2-docker

"},{"location":"bevezetes/ros2/#egyeb-valtozasok","title":"Egy\u00e9b v\u00e1ltoz\u00e1sok","text":"
  • A Catkin elt\u0171nt, hely\u00e9re az Ament (Colcon) l\u00e9pett, mint build rendszer. Az overlay-ek lehet\u0151v\u00e9 teszik egy m\u00e1sodlagos munkater\u00fclet l\u00e9trehoz\u00e1s\u00e1t, amely nem befoly\u00e1solja az els\u0151dleges munkater\u00fcletet - ez akkor hasznos, ha \u00faj csomagokkal kell k\u00eds\u00e9rletezni, de \u00fagy, hogy ez ne befoly\u00e1solja az alapkonfigur\u00e1ci\u00f3t (ezt \"underlay\"-nek h\u00edvj\u00e1k).
  • A ROS 2 visszafel\u00e9 nem kompatibilis a ROS 1-gyel. K\u00f6vetkez\u00e9sk\u00e9ppen a ROS 1 csomagok val\u00f3sz\u00edn\u0171leg nem fognak m\u0171k\u00f6dni a ROS 2-vel, \u00e9s \u00e1tdolgoz\u00e1st ig\u00e9nyeln\u00e9nek, \u00e9s m\u00e1s szoftverek, amelyeket a ROS 1-gyel szokt\u00e1l haszn\u00e1lni, m\u00e1r nem fognak m\u0171k\u00f6dni.
  • A ROS 1 els\u0151sorban az Ubuntu sz\u00e1m\u00e1ra k\u00e9sz\u00fclt. A ROS 2 fut MacOS, Windows, Ubuntu \u00e9s m\u00e1s (ak\u00e1r Real-Time) oper\u00e1ci\u00f3s rendszereken is.
"},{"location":"bevezetes/ros2/#verziok","title":"Verzi\u00f3k","text":"

ROS verzi\u00f3k \u00e9s telep\u00edt\u00e9s

\n\ngantt\n    dateFormat  YY-MM\n    title       ROS 2 Distros\n    excludes    weekends\n    tickInterval 365days\n    %% (`excludes` accepts specific dates in YYYY-MM-DD format, days of the week (\"sunday\") or \"weekends\", but not the word \"weekdays\".)\n    axisFormat %y\n\n    section ROS 2\n    Jazzy   :active, r012, 2024-05-23, 5y\n    .       :active, r011, 2021-01-01, 0d %% placeholder\n    Iron    :active, r010, 2023-11-01, 188d\n    .       :active, r011, 2021-01-01, 0d %% placeholder\n    Humble  :active, r009, 2022-05-23, 5y\n    .       :active, r011, 2021-01-01, 0d %% placeholder\n    Galactic:active, r008, 2021-05-23, 1y

Distrok sz\u00e1zal\u00e9kos megoszl\u00e1sa az id\u0151ben: metrics.ros.org/rosdistro_rosdistro.html

A Humble Hawksbill vagy r\u00f6viden Humble egy long term support (LTS) release, 5 \u00e9vig t\u00e1mogatott (2022 m\u00e1jus\u00e1t\u00f3l 2027 m\u00e1jus\u00e1ig)

Tov\u00e1bbi release-ek: docs.ros.org/en/humble/Releases.html

Koncepci\u00f3k\u00b6"},{"location":"bevezetes/ros2/#nodes","title":"Nodes","text":"

A node legegyszer\u0171bben fogalmazva ROS programot (magyaros\u00edtva csom\u00f3pont) jelent. \u00c1br\u00e1n kerek \ud83d\udd34 jel\u00f6l\u00e9ssel felt\u00fcnteve. Jellemz\u0151ik:

  • \"V\u00e9grehajthat\u00f3ak\" (c++ / py).
  • Minden node egy folyamat
  • ROS kezeli a sz\u00e1lakat (threading).
  • Egy node belsej\u00e9ben t\u00f6bb sz\u00e1l is lehet.
  • publish/subscribe topic-okra.
  • T\u00f6bb node is \"k\u00f6zz\u00e9tehet\" egy topicra, \u00e9s egy node t\u00f6bb topicot is \"meghallgathat\".
"},{"location":"bevezetes/ros2/#topics","title":"Topics","text":"

A topic-ok felfoghat\u00f3ak egy neves\u00edtett \"portnak\", ahol a node-ok kommunk\u00e1lni tudnak. \u00c1br\u00e1n sz\u00f6gletes \ud83d\udfe6 jel\u00f6l\u00e9ssel felt\u00fcnteve. Jellemz\u0151ik:

  • A node-ok k\u00f6z\u00f6tti inform\u00e1ci\u00f3 \u00e1raml\u00e1s\u00e9rt felel.
  • Minden topic t\u00edpus\u00e1t az \"\u00fczenet\" hat\u00e1rozza meg
  • A node-ok k\u00f6z\u00f6tt megengedett a \"many-to-many\" kommunik\u00e1ci\u00f3
"},{"location":"bevezetes/ros2/#messages","title":"Messages","text":"
  • Egy topic tartalm\u00e1t \u00e9s szerkezet\u00e9t az \u00fczenet hat\u00e1rozza meg
  • Alkalmaz\u00e1sprogramoz\u00e1si interf\u00e9sz (API) a Node-ok sz\u00e1m\u00e1ra .msg kiterjeszt\u00e9s\u0171 f\u00e1jlokban vannak defini\u00e1lva
"},{"location":"bevezetes/ros2/#uzenetek-tipusai","title":"\u00dczenetek t\u00edpusai","text":"
  • Primitive built-in types (std_msgs)
  • bool, string, float32, int32, \u2026
  • Higher-level built in types:
  • geometry_msgs: Point, Polygon, Vector, Pose, PoseWithCovariance, \u2026
  • nav_msgs: OccupancyGrid, Odometry, Path, \u2026
  • sensors_msgs: Joy, Imu, NavSatFix, PointCloud, LaserScan, \u2026
  • T\u00e1mogatottak tov\u00e1bb\u00e1:
  • Konstansok
  • Felsorol\u00e1sok
  • Be\u00e1gyazott defin\u00edci\u00f3k

P\u00e9lda:

$ ros2 interface show geometry_msgs/msg/Point\nfloat64 x\nfloat64 y\nfloat64 z\n
$ ros2 interface show std_msgs/msg/Header\nuint32 seq\ntime stamp\nstring frame_id\n

A Header \u00e9s aPoint a t\u00edpusb\u00f3l \u00e9p\u00fcl fel a PoseStamped t\u00edpus strukt\u00far\u00e1ja:

$ ros2 interface show geometry_msgs/msg/PoseStamped\nstd_msgs/Header header\n  uint32 seq\n  time stamp\n  string frame_id\ngeometry_msgs/Pose pose\n  geometry_msgs/Point position # (1) \n    float64 x\n    float64 y\n    float64 z\n  geometry_msgs/Quaternion orientation # (2)\n    float64 x\n    float64 y\n    float64 z\n    float64 w\n

  1. Ez m\u00e1r ismer\u0151s lehet: a geometry_msgs/msg/Point-r\u0151l m\u00e1r besz\u00e9lt\u00fcnk.
  2. geometry_msgs/Quaternion egyfajta 3D orient\u00e1ci\u00f3 reprezent\u00e1ci\u00f3, err\u0151l k\u00e9s\u0151bb r\u00e9szletesen.
"},{"location":"bevezetes/ros2/#publishing-subscribing","title":"Publishing / Subscribing","text":"

A k\u00f6vetkez\u0151kben az urban_road_filt nev\u0171 node a points adatokra iratkozik fel, ami PointCloud2 t\u00edpus\u00fa, \u00e9s hirdet PointCloud2, MarkerArray t\u00edpus\u00fa \u00fczeneteket:

flowchart LR\n\nP[points]:::light -->|sensor_msgs/PointCloud2| U([urban_road_filt]):::red\nU --> |sensor_msgs/PointCloud2| A[curb]:::light\nU --> |sensor_msgs/PointCloud2| B[road]:::light \nU --> |sensor_msgs/PointCloud2| C[road_probably]:::light\nU --> |sensor_msgs/PointCloud2| D[roi]:::light\nU --> |visualization_msgs/MarkerArray| E[road_marker]:::light\n\nn1([ /node]):::white -- publishes</br>topic_type --> t[ /topic]:::white\nt -- subscribes</br>topic_type --> n2([ /node]):::white\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"bevezetes/ros2/#parameters","title":"Parameters","text":"
  • Publish/Subscribe seg\u00edts\u00e9g\u00e9vel nem \u00edrhat\u00f3 le minden
  • A Node-oknak n\u00e9ha sz\u00fcks\u00e9g\u00fck lehet param\u00e9terez\u00e9sre
  • Param\u00e9terek lehetnek:
  • Vez\u00e9rl\u0151 t\u00edpusa
  • Sz\u00edn k\u00fcsz\u00f6b\u00e9rt\u00e9kek;
  • Kamera felbont\u00e1s, stb
"},{"location":"bevezetes/ros2/#launch-fajlok","title":"Launch f\u00e1jlok","text":"

T\u00f6bb node (ROS program) k\u00f6tegelt v\u00e9gehajt\u00e1sa. Megtartva az ROS 1konvenci\u00f3kat lehet XML form\u00e1tum\u00fa f\u00e1jl, amely az ROS szinte minden aspektus\u00e1t / m\u0171velet\u00e9t meghat\u00e1rozhatja. \u00dajabban viszont ezek python f\u00e1jlok is lehetnek, \u00edgy sokkkal nagyobb szabads\u00e1gunk van. Node ind\u00edt\u00e1s, param\u00e9terek be\u00e1ll\u00edt\u00e1sa / bet\u00f6lt\u00e9se, topic lek\u00e9pez\u00e9se, parancssori argumentumok \u00e1tad\u00e1sa.

Err\u0151l egy r\u00f6vid vide\u00f3:

"},{"location":"bevezetes/ros2/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble
  • ros.org/blog/ecosystem
  • husarnet.com/blog/ros2-docker
  • design.ros2.org/articles/intraprocess_communications.html
  • Towards Using ROS in the RoboCup Humanoid Soccer League - Masterthesis
"},{"location":"bevezetes/ros2gyak/","title":"ROS 2 bevezet\u00e9s \u00e9s gyakorlat","text":""},{"location":"bevezetes/ros2gyak/#emlekezteto","title":"Eml\u00e9keztet\u0151","text":"

P\u00e1r alapfogalom az el\u0151z\u0151 alkalomr\u00f3l:

  • Node: Gyakorlatilag ROS programot jelent. (pl. turtlesim_node, cmd_gen_node, foxglove_bridge)
  • Topic (topik): Nevekkel ell\u00e1tott kommunik\u00e1ci\u00f3s csatorna. (pl. /turtle1/cmd_vel, /turtle1/pose, /raw_cmd)
  • Message (\u00fczenet): (pl. std_msgs/msg/Bool, geometry_msgs/msg/Twist, turtlesim/msg/Pose)
  • Package (csomag): ROS programok (node-ok) gy\u0171jtem\u00e9nye (pl. turtlesim, arj_intro_cpp, arj_transforms_cpp)
  • Launch f\u00e1jlok: T\u00f6bb node param\u00e9terezett elind\u00edt\u00e1s\u00e1ra alkalmas (pl. multisim.launch.py, foxglove_bridge.launch.xml, foxglove_bridge.launch.py)
  • Publish / subscribe: \u00dczenetekre t\u00f6rt\u00e9n\u0151 publik\u00e1l\u00e1s \u00e9s feliratkoz\u00e1s.
  • Build: A package forr\u00e1sk\u00f3dj\u00e1b\u00f3l futtathat\u00f3 \u00e1llom\u00e1nyok k\u00e9sz\u00edt\u00e9s\u00e9nek folyamata. ROS2-ben a colcon az alap\u00e9rtelmezett build eszk\u00f6z.
"},{"location":"bevezetes/ros2gyak/#1-feladat-node-es-publish","title":"1. feladat - Node \u00e9s publish","text":"

Nyissunk k\u00e9t termin\u00e1lt. Az els\u0151 termin\u00e1lb\u00f3l ind\u00edtsuk a be\u00e9p\u00edtett turtlesim_node szimul\u00e1tort, ami a turtlesim package-ben tal\u00e1lhat\u00f3.

ros2 run turtlesim turtlesim_node\n

Megjegyz\u00e9s: ha esetleg valami\u00e9rt hi\u00e1nyozna, telep\u00edthet\u0151 a sudo apt install ros-humble-turtlesim paranccsal.

A m\u00e1sodik ablakb\u00f3l publik\u00e1ljunk egy parancsot, melynek hat\u00e1s\u00e1ra k\u00f6rbe fordul:

ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist '{linear: {x: 0.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.2}}'\n
Turtlesim anim\u00e1ci\u00f3

A h\u00e1tt\u00e9rben a turtlesim_node node (kerek jel\u00f6l\u00e9s) feliratkozik a /turtle1/cmd_vel topicra (sz\u00f6gletes jel\u00f6l\u00e9s), ennek hat\u00e1s\u00e1ra indul a mozg\u00e1s.

flowchart LR\n\nC[ /turtle1/cmd_vel]:::light -->|geometry_msgs/msg/Twist| S([turtlesim_node]):::red\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n

Ahogy a flowcharton is l\u00e1tszik, a /turtle1/cmd_vel t\u00edpusa geometry_msgs/msg/Twist. Ezt a k\u00f6vetkez\u0151 parancsb\u00f3l tudhatjuk meg:

ros2 topic type /turtle1/cmd_vel\n

A geometry_msgs/msg/Twist a \u00fczenet strut\u00far\u00e1j\u00e1t pedig ez a parancs adja:

ros2 interface show geometry_msgs/msg/Twist\n

Vector3  linear\n        float64 x\n        float64 y\n        float64 z\nVector3  angular\n        float64 x\n        float64 y\n        float64 z\n
Az \u00f6sszes topic-ot \u00edgy lehet list\u00e1zni:

ros2 topic list\n

Az adott topic tartalm\u00e1t, k\u00fcl\u00f6nb\u00f6z\u0151 form\u00e1tumban, sz\u0171r\u00e9sekkel a k\u00f6vetkez\u0151k\u00e9pp lehet ki\u00edratni vagy f\u00e1jlba iratni:

ros2 topic echo /turtle1/pose\nros2 topic echo /turtle1/pose --csv\nros2 topic echo /turtle1/pose --csv > turtle_data_01.csv\nros2 topic echo /turtle1/pose --once\nros2 topic echo /turtle1/pose --once | grep velocity\nros2 topic echo /turtle1/pose --field x\nros2 topic echo /turtle1/pose --field linear_velocity\nros2 topic echo /turtle1/cmd_vel --field linear.x\n

P\u00e9lda kimenet:

x: 6.2\ny: 4.0\ntheta: 0.0\nlinear_velocity: 0.0\nangular_velocity: 0.0\n

Tip

A ros2 topic echo --help parancsot kiadva tov\u00e1bbi haszn\u00e1latra vonatkoz\u00f3 le\u00edr\u00e1st kapunk. A --help kapcsol\u00f3 term\u00e9szetesen a t\u00f6bbi ros2 parancsn\u00e1l is haszn\u00e1lhat\u00f3.

"},{"location":"bevezetes/ros2gyak/#workspace-es-build-tudnivalok","title":"Workspace \u00e9s build tudnival\u00f3k","text":"

Els\u0151 l\u00e9p\u00e9sk\u00e9nt az ls ~ | grep ros2 parancs seg\u00edts\u00e9g\u00e9vel ellen\u0151rizz\u00fck, hogy l\u00e9tezik-e a workspace a home directoryban(~). A tant\u00e1rgyban a workspace-t ros2_ws-nek nevezz\u00fck. A n\u00e9v igaz\u00e1b\u00f3l nem sz\u00e1m\u00edt, de a legt\u00f6bb tutorial is ezt a nevet haszn\u00e1lja, \u00edgy mi is k\u00f6vetj\u00fck ezt a hagyom\u00e1nyt. T\u00f6bb workspace is haszn\u00e1lhat\u00f3 egyidej\u00fcleg, k\u00fcl\u00f6n source-olhat\u00f3, nagyobb rendszerekn\u00e9l ez k\u00e9nyelmes megold\u00e1s lehet. Mi egyel\u0151re maradunk az egytelen ros2_ws-n\u00e9l. Ha nem l\u00e9tezne a mkdir -p ros2_ws/src parancs seg\u00edts\u00e9g\u00e9vel k\u00e9sz\u00edthetj\u00fck el a workspace \u00e9s a source mapp\u00e1kat.

"},{"location":"bevezetes/ros2gyak/#colcon","title":"Colcon","text":"

A legfontosabb parancs tal\u00e1n a colcon build. Eml\u00edt\u00e9sre m\u00e9lt\u00f3 m\u00e9g a colcon list \u00e9s a colcon graph. El\u0151bbi list\u00e1zza az el\u00e9rhet\u0151 packageket, ut\u00f3bbi pedig a f\u00fcgg\u0151s\u00e9gekr\u0151l ad gyors n\u00e9zetet.

A colcon build sz\u00e1mos hasznos kapcsol\u00f3val \u00e9rkezik:

  • --packages-select: Tal\u00e1n az egyik leggyakrabban haszn\u00e1lt kapcsol\u00f3, ut\u00e1na meggadhatunk t\u00f6bb package-t, amit buildelni szeretn\u00e9nk. Ha nincs megadva, akkor az alap\u00e9rtelmezett, hogy a teljes workspace-t buildeli. A gyakorlatban lesz is egy colcon build --packages-select arj_intro_cpp arj_transforms_cpp parancs, ez a k\u00e9t arj package-t buildeli.
  • --symlink-install: A f\u00e1jlok forr\u00e1sb\u00f3l val\u00f3 m\u00e1sol\u00e1sa helyett haszn\u00e1ljon szimbolikus hivatkoz\u00e1sokat. \u00cdgy elker\u00fclhet\u0151, hogy pl. minden egyes launch f\u00e1jl m\u00f3dos\u00edt\u00e1s eset\u00e9n \u00fajra kelljen buildelni a package-t.
  • --parallel-workers 2: A p\u00e1rhuzamosan feldolgozhat\u00f3 feladatok maxim\u00e1lis sz\u00e1ma, ebben az esetben 2. Ha nincs megadva, akkor az alap\u00e9rtelmezett \u00e9rt\u00e9k a logikai CPU magok sz\u00e1ma. Akkor \u00e9rdemes korl\u00e1tozni, ha a build nem fut v\u00e9gig er\u0151forr\u00e1s hi\u00e1ny miatt.
  • --continue-on-error: Nagyobb build eset\u00e9n, ne \u00e1lljon meg az els\u0151 hib\u00e1s package ut\u00e1n. \u00cdgy ha 100 packageb\u0151l 1 nem m\u0171k\u00f6dne, akkor is 99 buildel\u0151dik. Ha ez nincs megadva, akkor 0 \u00e9s 99 k\u00f6z\u00f6tti package buildel\u0151dik, a f\u00fcgg\u0151s\u00e9gek \u00e9s egy\u00e9b sorrendis\u00e9gek alapj\u00e1n.
"},{"location":"bevezetes/ros2gyak/#source","title":"Source","text":"

Ahhoz hogy az ROS2 futtathat\u00f3 f\u00e1jlainkat val\u00f3ban el tudjuk ind\u00edtani, be kell \u00e1ll\u00edani a be a k\u00f6rnyezetet (\u00fagynevezett source-ol\u00e1s), teh\u00e1t meg kell adni a bash sz\u00e1m\u00e1ra, hogy hol keresse az adott futtathat\u00f3 f\u00e1jlokat, azoknak milyen f\u00fcgg\u0151s\u00e9gei vannak stb. Ez egyszer\u0171bb, mint hangzik, csak egy source <\u00fatvonal>/<n\u00e9v>.bash parancsot kell kiadni. Kor\u00e1bban \u00edrtuk, hogy a worksapce neve nem sz\u00e1m\u00edt, \u00e9s val\u00f3ban, a source megad\u00e1sa ut\u00e1n mindegy, hogy fizikailag hol tal\u00e1lhat\u00f3 a futtathat\u00f3 \u00e1llom\u00e1ny, k\u00e9nyelmesen elind\u00edthat\u00f3 egy paranccsal b\u00e1rmelyik mapp\u00e1b\u00f3l. Mivel a packagek k\u00fcl\u00f6nb\u00f6z\u0151 workspace-eken bel\u00fcl egym\u00e1sra is \u00e9p\u00fclhetnek, az ROS2 bevezette az overlay / underlay elvet. Ez azt jelenti, hogy egyik workspace buildel\u00e9sekor egy m\u00e1sik workspace m\u00e1r be volt source-olva, annak valamely package-e f\u00fcgg a az el\u0151z\u0151leg lebuildelt package-t\u0151l. Teh\u00e1t annak funkcionalit\u00e1sa, k\u00f3dja sz\u00fcks\u00e9ges a r\u00e1\u00e9p\u00fcl\u0151 package-nek. Ennek megfele\u0151en a source-ol\u00e1s is k\u00e9tf\u00e9le lehet: - A local_setup.bash script csak a jelenlegi workspace-ben \u00e1ll\u00edtja be a k\u00f6rnyezetet (source-ol). Teh\u00e1t nem source-ol sz\u00fcl\u0151 (f\u00fcgg\u0151) workspace-t. - A setup.bash szkript viszont a local_setup.bash parancsf\u00e1jlt adja az \u00f6sszes olyan workspace-hez, amely a munkater\u00fclet l\u00e9trehoz\u00e1sakor f\u00fcgg\u0151s\u00e9g volt.

Note

A tant\u00e1rgyban nem kell ilyen \u00f6sszetett rendszereket haszn\u00e1lni, legt\u00f6bbsz\u00f6r egy ros2_ws is el\u00e9g.

"},{"location":"bevezetes/ros2gyak/#2-feladat-package-build-es-hasznalat","title":"2. feladat - Package build \u00e9s haszn\u00e1lat","text":"Eml\u00e9keztet\u0151\u00fcl a mapparendszer.
~/ros2_ws/\n\u251c\u2500\u2500build  \n\u251c\u2500\u2500install  \n\u251c\u2500\u2500log\n\u2514\u2500\u2500src/\n    \u251c\u2500\u2500 bundle_packages \n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 cone_detection_lidar\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 launch\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 src\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 my_vehicle_bringup\n    \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 launch\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 other bundle package1\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 other bundle package2\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 img\n    \u2514\u2500\u2500 wayp_plan_tools\n        \u251c\u2500\u2500 csv\n        \u251c\u2500\u2500 launch\n        \u2514\u2500\u2500 src\n

docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html

Nyissunk n\u00e9gy termin\u00e1lt. Az els\u0151 termin\u00e1lb\u00f3l most is ind\u00edtsuk a be\u00e9p\u00edtett turtlesim_node szimul\u00e1tort, ami a turtlesim package-ben tal\u00e1lhat\u00f3.

ros2 run turtlesim turtlesim_node\n

Success

A m\u00e1sodik termin\u00e1lban ellen\u0151rizz\u00fck a ros2_ws/src tartalm\u00e1t, \u00e9s ha sz\u00fcks\u00e9ges kl\u00f3nozzuk, majd buildelj\u00fck a p\u00e9lda package-t.

ls ~/ros2_ws/src | grep arj_\n
vagy

cd ~ && test -d \"ros2_ws/src/arj_packages\" && echo Letezik || echo Nem letezik\n
  • A. opci\u00f3: Ha nincs package (az el\u0151z\u0151 ls nem ad vissza tal\u00e1latot), akkor git clone \u00e9s colcon build.
  • B. opci\u00f3: Ha van package, de nem a legfrissebb, akkor git pull \u00e9s colcon build.
  • C. opci\u00f3: Ha van package \u00e9s friss is, akkor nincs k\u00fcl\u00f6n teend\u0151nk.

A. opci\u00f3:

cd ~/ros2_ws/src\n
git clone https://github.com/sze-info/arj_packages\n
cd ~/ros2_ws\n
colcon build --packages-select arj_intro_cpp\n

B. opci\u00f3:

cd ~/ros2_ws/src/arj_packages\n
git checkout -- .\n
git pull\n
cd ~/ros2_ws\n

colcon build --packages-select arj_intro_cpp\n

A git checkout -- . az \u00f6sszes esetleges lok\u00e1lis v\u00e1ltoz\u00e1s visszavon\u00e1s\u00e1ra j\u00f3.

A harmadik termin\u00e1lban futtassuk a cmd_gen_node ROS node-ot.

El\u0151sz\u00f6r source-olnunk kell, ha saj\u00e1t package-ket haszn\u00e1lunk:

source ~/ros2_ws/install/setup.bash\n

Ezut\u00e1n m\u00e1r futtathat\u00f3 a node:

ros2 run arj_intro_cpp cmd_gen_node\n

A k\u00f6vetkez\u0151k\u00e9pp mozog most a tekn\u0151s:

Turtle

Forr\u00e1sk\u00f3dja el\u00e9rhet\u0151 a github.com/sze-info/arj_packages repon.A l\u00e9nyeg, hogy a loop f\u00fcggv\u00e9ny 5 Hz (200 ms) frekvenci\u00e1n fut le, \u00e9s

void loop()\n{\n  // Publish transforms\n  auto cmd_msg = geometry_msgs::msg::Twist();\n  if (loop_count_ < 20)\n  {\n    cmd_msg.linear.x = 1.0;\n    cmd_msg.angular.z = 0.0;\n  }\n  else\n  {\n    cmd_msg.linear.x = -1.0;\n    cmd_msg.angular.z = 1.0;\n  }\n  cmd_pub_->publish(cmd_msg);\n  loop_count_++;\n  if (loop_count_ > 40)\n  {\n    loop_count_ = 0;\n  }\n}\n

Python megfelel\u0151je

A C++ k\u00f3d python verzi\u00f3ja szint\u00e9n el\u00e9rhet\u0151 a github.com/sze-info/arj_packages c\u00edmen. \u00c9rdemes \u00f6sszehasonl\u00edtani a C++ \u00e9s a python k\u00f3dokat.

N\u00e9zz\u00fck meg az utols\u00f3 termin\u00e1lban a Foxglove seg\u00edts\u00e9g\u00e9vel az \u00e9l\u0151 adatokat (itt se felejts\u00fck a source-t):

ros2 launch arj_intro_cpp foxglove_bridge.launch.py\n

Vizsg\u00e1ljuk meg Foxglove Studio-val is WebSocketen kereszt\u00fcl (Open connection ws://localhost:8765):

Megjegyz\u00e9s: g\u00e9pteremben fel van t\u00e9ve a foxglove_bridge, otthon sudo apt install ros-humble-foxglove-bridge paranccsal (el\u0151tte update) telep\u00edthet\u0151.

flowchart LR\n\nC[ /turtle1/cmd_vel]:::light --> S([turtlesim_node]):::red\nC[ /turtle1/cmd_vel] --> F([foxglove_bridge]):::red\nG([cmd_gen_node]):::red--> C\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
Mindeh\u00e1rom node-ot egyben a k\u00f6vetkez\u0151k\u00e9pp ind\u00edthatjuk:

ros2 launch arj_intro_cpp turtle.launch.py\n

Vizsg\u00e1ljuk meg a package tartalm\u00e1t r\u00f6viden a code ~/ros2_ws/src/arj_packages/arj_intro_cpp parancs ut\u00e1n.

"},{"location":"bevezetes/ros2gyak/#3-feladat-sajat-package-keszitese","title":"3. feladat - Saj\u00e1t package k\u00e9sz\u00edt\u00e9se","text":"

A feladat a hivatalos ROS2 dokument\u00e1ci\u00f3n alapul: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html. K\u00e9sz\u00edts\u00fck el a my_package nev\u0171 ROS 2 package-t.

Python megfelel\u0151je

Jelenleg C++ package-t k\u00e9sz\u00edt\u00fcnk, de az eredeti tutorial is taralmazza a CMake(c++) package Python megfelel\u0151it.

Els\u0151 l\u00e9p\u00e9s, hogy a a workspace src mapp\u00e1j\u00e1ba l\u00e9pj\u00fcnk:

cd ~/ros2_ws/src\n

K\u00e9sz\u00edts\u00fcnk egy my_package nev\u0171 package-t \u00e9s egy my_node nev\u0171 node-ot.

ros2 pkg create --build-type ament_cmake --node-name my_node my_package\n

Buildelj\u00fck a szok\u00e1sos m\u00f3don:

cd ~/ros2_ws\n
colcon build --packages-select my_package\n

Majd source:

source ~/ros2_ws/install/setup.bash\n

\u00c9s m\u00e1r futtathat\u00f3 is:

ros2 run my_package my_node\n
# output:\n\nhello world my_package package\n

Vizsg\u00e1ljuk meg a my_package tartalm\u00e1t!

ls -R ~/ros2_ws/src/my_package\n
# output:\n/home/he/ros2_ws/src/my_package:\n  CMakeLists.txt  include  package.xml  src\n/home/he/ros2_ws/src/my_package/include:\n  my_package\n/home/he/ros2_ws/src/my_package/include/my_package:\n  [empty]\n/home/he/ros2_ws/src/my_package/src:\n  my_node.cpp\n

tree ~/ros2_ws/src/my_package\n
# output:\nmy_package\n\u251c\u2500\u2500 CMakeLists.txt\n\u251c\u2500\u2500 include\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 my_package\n\u251c\u2500\u2500 package.xml\n\u2514\u2500\u2500 src\n    \u2514\u2500\u2500 my_node.cpp\n

cat ~/ros2_ws/src/my_package/src/my_node.cpp\n
#include <cstdio>\n\nint main(int argc, char ** argv)\n{\n  (void) argc;\n  (void) argv;\n\n  printf(\"hello world my_package package\\n\");\n  return 0;\n}\n
\u00c9rdemes megfigyelni, hogy a cpp f\u00e1jl m\u00e9g semmilyen ros2 headert nem haszn\u00e1l.

Futtat\u00e1sa:

source ~/ros2_ws/install/setup.bash\n
ros2 run my_package my_node\n

Alternat\u00edvak\u00e9nt VS code-b\u00f3l is megnyinthatjuk a teljes mapp\u00e1t.

code ~/ros2_ws/src/my_package\n

Tip

A code parancs ut\u00e1n f\u00e1jlt megadva a f\u00e1jl niyt\u00f3dik meg, m\u00edg mapp\u00e1t (k\u00f6nyvt\u00e1rat) megadva az adott mappa tartalma ny\u00edlik meg. Gyakran forul el\u0151, hogy p\u00e9ld\u00e1ul egy adott package-ben vagyunk \u00e9s szeretn\u00e9nk az aktu\u00e1lis mapp\u00e1t megnyitni. Ezt megtehetj\u00fck a code . paranccsal, amikoris az aktu\u00e1lis mappa nyit\u00f3dik meg, hiszen a . karakter az aktu\u00e1lis mapp\u00e1t jelenti linuxban.

"},{"location":"bevezetes/ros2gyak/#4-feladat-c-publisher-subscriber","title":"4. feladat - C++ publisher / subscriber","text":"

H\u00e1zi feladat

Otthon k\u00e9sz\u00edts\u00fck el a cpp_pubsub / py_pubsub package-t, ami egy egyszer\u0171 publish/subscribe p\u00e9ld\u00e1t val\u00f3s\u00edt meg.

A gyakorlat a hivatalos ROS 2 tutorialokon alapszik: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html

  • C++ publisher
  • C++ subscriber
"},{"location":"bevezetes/ros2gyak/#hozzuk-letre-a-cpp_pubsub-package-t","title":"Hozzuk l\u00e9tre a cpp_pubsub package-t","text":"

Nyissunk egy \u00faj termin\u00e1lt, \u00e9s source-oljunk a telep\u00edt\u00e9st, hogy a ros2 parancsok m\u0171k\u00f6djenek.

Navig\u00e1ljunk az m\u00e1r l\u00e9trehozott ros2_ws k\u00f6nyvt\u00e1rba.

Fontos, hogy a csomagokat az src' k\u00f6nyvt\u00e1rban kell l\u00e9trehozni, nem a munkater\u00fclet gy\u00f6ker\u00e9ben. Teh\u00e1t navig\u00e1ljunk aros2_ws/src` f\u00e1jlba, \u00e9s futtassuk a package l\u00e9trehoz\u00f3 parancsot:

ros2 pkg create --build-type ament_cmake cpp_pubsub\n

A termin\u00e1l egy \u00fczenetet k\u00fcld vissza, amely meger\u0151s\u00edti a cpp_pubsub csomag \u00e9s az \u00f6sszes sz\u00fcks\u00e9ges f\u00e1jl \u00e9s mappa l\u00e9trehoz\u00e1s\u00e1t.

"},{"location":"bevezetes/ros2gyak/#irjuk-meg-a-publisher-node-ot","title":"\u00cdrjuk meg a publisher node-ot","text":"

L\u00e9pj\u00fcnk a ros2_ws/src/cpp_pubsub/src mapp\u00e1ba. Ez az a k\u00f6nyvt\u00e1r minden CMake package-ben, ahov\u00e1 a forr\u00e1sf\u00e1jlok tartoznak (pl .cpp kiterjeszt\u00e9ssel).

T\u00f6lts\u00fck le a p\u00e9lda talker k\u00f3dj\u00e1t:

wget -O publisher_member_function.cpp https://raw.githubusercontent.com/ros2/examples/humble/rclcpp/topics/minimal_publisher/member_function.cpp\n

Ez a parancs l\u00e9trehozza a publisher_member_function.cpp f\u00e1jlt. Nyissuk meg pl VS code seg\u00edts\u00e9g\u00e9vel a mapp\u00e1t (code .)

#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\n#include \"rclcpp/rclcpp.hpp\"\n#include \"std_msgs/msg/string.hpp\"\n\nusing namespace std::chrono_literals;\n\n/* This example creates a subclass of Node and uses std::bind() to register a\n* member function as a callback from the timer. */\n\nclass MinimalPublisher : public rclcpp::Node\n{\n    public:\n    MinimalPublisher()\n    : Node(\"minimal_publisher\"), count_(0)\n    {\n        publisher_ = this->create_publisher<std_msgs::msg::String>(\"topic\", 10);\n        timer_ = this->create_wall_timer(\n        500ms, std::bind(&MinimalPublisher::timer_callback, this));\n    }\n\n    private:\n    void timer_callback()\n    {\n        auto message = std_msgs::msg::String();\n        message.data = \"Hello, world! \" + std::to_string(count_++);\n        RCLCPP_INFO(this->get_logger(), \"Publishing: '%s'\", message.data.c_str());\n        publisher_->publish(message);\n    }\n    rclcpp::TimerBase::SharedPtr timer_;\n    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;\n    size_t count_;\n};\n\nint main(int argc, char * argv[])\n{\n    rclcpp::init(argc, argv);\n    rclcpp::spin(std::make_shared<MinimalPublisher>());\n    rclcpp::shutdown();\n    return 0;\n}\n
"},{"location":"bevezetes/ros2gyak/#fuggosegek-hozzaadasa","title":"F\u00fcgg\u0151s\u00e9gek hozz\u00e1ad\u00e1sa","text":"

L\u00e9pj\u00fcnk vissza egy szinttel a ros2_ws/src/cpp_pubsub k\u00f6nyvt\u00e1rba, ahol a CMakeLists.txt \u00e9s a package.xml f\u00e1jlok m\u00e1r l\u00e9trej\u00f6ttek.

Nyissuk meg a package.xml f\u00e1jlt a sz\u00f6vegszerkeszt\u0151vel (pl. vs code). Tipp: a teljes k\u00f6nyvt\u00e1rat is meg lehet, nyitni, ami k\u00e9s\u0151bb p\u00e1r dolgot egyszer\u0171s\u00edt:

code ~/ros2_ws/src/cpp_pubsub/\n

Mindig \u00e9rdemes kit\u00f6lteni a <description>, <maintainer> \u00e9s <license> tag-eket:

<description>Examples of minimal publisher/subscriber using rclcpp</description>\n<maintainer email=\"you@email.com\">Your Name</maintainer>\n<license>Apache License 2.0</license>\n

Adjunk hozz\u00e1 egy \u00faj sort az ament_cmake buildtool f\u00fcgg\u0151s\u00e9ge ut\u00e1n, \u00e9s illessze be a k\u00f6vetkez\u0151 f\u00fcgg\u0151s\u00e9geket a node include utas\u00edt\u00e1sainak megfelel\u0151en:

<depend>rclcpp</depend>\n<depend>std_msgs</depend>\n

Ez deklar\u00e1lja, hogy a pacakge-nek sz\u00fcks\u00e9ges az rclcpp \u00e9s a std_msgs ford\u00edt\u00e1skor \u00e9s futtat\u00e1skor.

"},{"location":"bevezetes/ros2gyak/#cmakeliststxt","title":"CMakeLists.txt","text":"

Most nyissuk meg a CMakeLists.txt f\u00e1jlt. A megl\u00e9v\u0151 find_package(ament_cmake REQUIRED) f\u00fcgg\u0151s\u00e9g al\u00e1 adjuk hozz\u00e1 a k\u00f6vetkez\u0151 sorokat:

find_package(rclcpp REQUIRED)\nfind_package(std_msgs REQUIRED)\n

Ezut\u00e1n adjuk hozz\u00e1 a v\u00e9grehajthat\u00f3 f\u00e1jlt, \u00e9s nevezz\u00fck el talker-nak, hogy a ros2 run haszn\u00e1lat\u00e1val futtassa a node-ot:

add_executable(talker src/publisher_member_function.cpp)\nament_target_dependencies(talker rclcpp std_msgs)\n

V\u00e9g\u00fcl az install(TARGETS...) r\u00e9szt adjuk hozz\u00e1, hogy az ros 2 megtal\u00e1lja a futtathat\u00f3 \u00e1llom\u00e1nyt, amit leford\u00edtottunk

install(TARGETS\ntalker\nDESTINATION lib/${PROJECT_NAME})\n

A CMakeLists.txt megtiszt\u00edthat\u00f3 n\u00e9h\u00e1ny felesleges szakasz \u00e9s megjegyz\u00e9s elt\u00e1vol\u00edt\u00e1s\u00e1val, \u00edgy a k\u00f6vetkez\u0151k\u00e9ppen n\u00e9z ki:

cmake_minimum_required(VERSION 3.5)\nproject(cpp_pubsub)\n\n# Default to C++14\nif(NOT CMAKE_CXX_STANDARD)\nset(CMAKE_CXX_STANDARD 14)\nendif()\n\nif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\nadd_compile_options(-Wall -Wextra -Wpedantic)\nendif()\n\nfind_package(ament_cmake REQUIRED)\nfind_package(rclcpp REQUIRED)\nfind_package(std_msgs REQUIRED)\n\nadd_executable(talker src/publisher_member_function.cpp)\nament_target_dependencies(talker rclcpp std_msgs)\n\ninstall(TARGETS\ntalker\nDESTINATION lib/${PROJECT_NAME})\n\nament_package()\n

M\u00e1r buildelhet\u0151 a package, adjuk hozz\u00e1 a feliratkoz\u00f3 (subscriber) node-ot is, hogy l\u00e1thassuk a teljes rendszert m\u0171k\u00f6d\u00e9s k\u00f6zben.

cd ~/ros2_ws/\n
colcon build --packages-select cpp_pubsub\n

"},{"location":"bevezetes/ros2gyak/#irjuk-meg-a-subscriber-node-ot","title":"\u00cdrjuk meg a subscriber node-ot","text":"

A subscriber node elk\u00e9sz\u00edt\u00e9s\u00e9t a k\u00f6vetkez\u0151 tutorial 3-a pontja is le\u00edrja: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html

L\u00e9pj\u00fcnk vissza a ros2_ws/src/cpp_pubsub/src mapp\u00e1ba \u00e9s t\u00f6lts\u00fck le a sunbscriber node-ot is:

wget -O subscriber_member_function.cpp https://raw.githubusercontent.com/ros2/examples/humble/rclcpp/topics/minimal_subscriber/member_function.cpp\n

Ha most ls-el list\u00e1zunk, a k\u00f6vetkez\u0151t kell l\u00e1ssuk:

publisher_member_function.cpp  subscriber_member_function.cpp\n

A CMakeList.txt-hez adjuk hozz\u00e1 a subscribe node-ot is:

add_executable(listener src/subscriber_member_function.cpp)\nament_target_dependencies(listener rclcpp std_msgs)\n\ninstall(TARGETS\n  talker\n  listener\n  DESTINATION lib/${PROJECT_NAME})\n
"},{"location":"bevezetes/ros2gyak/#forditsuk-a-package-t","title":"Ford\u00edtsuk a package-t","text":"

cd ~/ros2_ws/\n
colcon build --packages-select cpp_pubsub\n

Futtat\u00e1s:

source ~/ros2_ws/install/setup.bash\n
ros2 run cpp_pubsub talker\n

[INFO] [minimal_publisher]: Publishing: \"Hello World: 0\"\n[INFO] [minimal_publisher]: Publishing: \"Hello World: 1\"\n[INFO] [minimal_publisher]: Publishing: \"Hello World: 2\"\n[INFO] [minimal_publisher]: Publishing: \"Hello World: 3\"\n[INFO] [minimal_publisher]: Publishing: \"Hello World: 4\"\n

Egy \u00fajabb terminalba:

source ~/ros2_ws/install/setup.bash\n
ros2 run cpp_pubsub listener\n

[INFO] [minimal_subscriber]: I heard: \"Hello World: 10\"\n[INFO] [minimal_subscriber]: I heard: \"Hello World: 11\"\n[INFO] [minimal_subscriber]: I heard: \"Hello World: 12\"\n[INFO] [minimal_subscriber]: I heard: \"Hello World: 13\"\n[INFO] [minimal_subscriber]: I heard: \"Hello World: 14\"\n
"},{"location":"bevezetes/ros2gyak/#5-feladat-python-publisher-subscriber","title":"5. feladat - Python publisher / subscriber","text":"

A gyakorlat a hivatalos ROS 2 tutorialokon alapszik: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html

PythonC++
import rclpy      ## ROS2 Python API \nfrom std_msgs.msg import String ## ROS2 Standard String\nfrom rclpy.node import Node \n\n\n\n\n## MinimalPublisher oszt\u00e1ly\nclass MinimalPublisher(Node):\n\n    def __init__(self):\n        super().__init__('minimal_publisher')\n        self.publisher_ = self.create_publisher(String, 'topic', 10)\n        timer_period = 0.5  # seconds\n        self.timer = self.create_timer(timer_period, self.timer_callback)\n        self.i = 0\n\n    def timer_callback(self):\n        msg = String()\n        msg.data = 'Hello World: %d' % self.i\n        self.publisher_.publish(msg)\n        self.get_logger().info('Publishing: \"%s\"' % msg.data)\n        self.i += 1\n\n\n\n\n\ndef main(args=None):\n    rclpy.init(args=args)\n    minimal_publisher = MinimalPublisher()\n    rclpy.spin(minimal_publisher)\n    minimal_publisher.destroy_node()\n    rclpy.shutdown()\n\n\nif __name__ == '__main__':\n    main()\n
#include \"rclcpp/rclcpp.hpp\" // ROS2 C++ API \n#include \"std_msgs/msg/string.hpp\" // ROS2 standard String\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\nusing namespace std::chrono_literals;\n// MinimalPublisher oszt\u00e1ly\nclass MinimalPublisher : public rclcpp::Node\n{\n    public: MinimalPublisher() : Node(\"minimal_publisher\"), count_(0) {\n        publisher_ = this->create_publisher<std_msgs::msg::String>(\"topic\", 10);\n        timer_ = this->create_wall_timer(\n        500ms, std::bind(&MinimalPublisher::timer_callback, this));\n    }\n\n    private:\n    void timer_callback(){\n        auto message = std_msgs::msg::String();\n        message.data = \"Hello, world! \" + std::to_string(count_++);\n        RCLCPP_INFO(this->get_logger(), \"Publishing: '%s'\", message.data.c_str());\n        publisher_->publish(message);\n    }\n    rclcpp::TimerBase::SharedPtr timer_;\n    rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;\n    size_t count_;\n};\n\nint main(int argc, char * argv[]){\n    rclcpp::init(argc, argv);\n    rclcpp::spin(std::make_shared<MinimalPublisher>());\n    rclcpp::shutdown();\n    return 0;\n}\n
  • Python publisher
  • Python subscriber
"},{"location":"bevezetes/ros2gyak/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Introducing-Turtlesim/Introducing-Turtlesim.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
"},{"location":"bevezetes/vscodegit/","title":"VS code \u00e9s Git","text":"

A VS code Linux, Windows \u00e9s Mac rendszerekre k\u00e9sz\u00fclt egyszer\u0171 k\u00f3d \u00e9s sz\u00f6vegszerkezst\u0151, amely k\u00fcl\u00f6nb\u00f6z\u0151 kieg\u00e9sz\u00edt\u00e9sekkel egy teljes \u00e9rt\u00e9k\u0171 IDE (integr\u00e1lt fejleszt\u0151k\u00f6rnyezet) lehet. Neve a Visual Studio Code r\u00f6vid\u00edt\u00e9se, ingyenes, ny\u00edlt forr\u00e1sk\u00f3d\u00fa, a Microsoft fejleszti. N\u00e9pszer\u0171 fejleszt\u0151k\u00f6rnyezet (pl. 2021-ben a Stack Overflow Developer Survey alapj\u00e1n 82000 v\u00e1laszad\u00f3b\u00f3l 70% haszn\u00e1lta, \u00edgy az egyik legn\u00e9pszer\u0171bb IDE).

"},{"location":"bevezetes/vscodegit/#navigacio-a-fejlesztokornyezetben","title":"Navig\u00e1ci\u00f3 a fejleszt\u0151k\u00f6rnyezetben","text":"

A k\u00f6vetkez\u0151kben a fontosabb fele\u00fcleteket mutatjuk be.

Tal\u00e1n az egyik legfontosabb billenty\u0171kombin\u00e1ci\u00f3 a Ctrl-Shift-P, mellyel a Command Palette j\u00f6n el\u0151, ahol be\u00e1ll\u00edt\u00e1sok, f\u00e1jlok, parancsok k\u00f6z\u00f6tt b\u00f6ng\u00e9szhet\u00fcnk.

"},{"location":"bevezetes/vscodegit/#source-control-forraskezeles-attetintese","title":"Source control (forr\u00e1skezel\u00e9s) \u00e1ttetint\u00e9se","text":"

A forr\u00e1skezel\u0151 szoftvereket, mint p\u00e9ld\u00e1ul a Git, a k\u00f6vetkez\u0151 okok miatt haszn\u00e1ljuk a modern szoftverfejleszt\u00e9sben:

  • V\u00e1ltoz\u00e1sk\u00f6vet\u00e9s: Lehet\u0151v\u00e9 teszik a forr\u00e1sk\u00f3d minden m\u00f3dos\u00edt\u00e1s\u00e1nak nyomon k\u00f6vet\u00e9s\u00e9t, \u00edgy k\u00f6nnyen vissza lehet t\u00e9rni kor\u00e1bbi verzi\u00f3khoz, ha hib\u00e1t fedeznek fel, vagy ha egy \u00faj funkci\u00f3 nem m\u0171k\u00f6dik megfelel\u0151en.
  • Egy\u00fcttm\u0171k\u00f6d\u00e9s: T\u00f6bb fejleszt\u0151 egyidej\u0171leg dolgozhat ugyanazon a projekten. A forr\u00e1skezel\u0151 szoftverek seg\u00edtenek kezelni a k\u00fcl\u00f6nb\u00f6z\u0151 v\u00e1ltoztat\u00e1sokat \u00e9s megoldani az esetleges \u00fctk\u00f6z\u00e9seket.
  • Biztons\u00e1gi ment\u00e9s: A projekt minden verzi\u00f3j\u00e1t t\u00e1rolja, \u00edgy ha valami elromlik vagy elveszik, k\u00f6nnyen vissza lehet \u00e1ll\u00edtani az el\u0151z\u0151 \u00e1llapotot.
  • \"K\u00eds\u00e9rletez\u00e9s\": Lehet\u0151v\u00e9 teszi a fejleszt\u0151k sz\u00e1m\u00e1ra, hogy k\u00fcl\u00f6nb\u00f6z\u0151 verzi\u00f3kat vagy \u00e1gakat (branch) hozzanak l\u00e9tre, \u00e9s \u00faj funkci\u00f3kat vagy jav\u00edt\u00e1sokat pr\u00f3b\u00e1ljanak ki an\u00e9lk\u00fcl, hogy befoly\u00e1soln\u00e1k a f\u0151 projektk\u00f3dot.
  • Dokument\u00e1l\u00e1s: A forr\u00e1skezel\u0151 rendszerekben lehet\u0151s\u00e9g van a m\u00f3dos\u00edt\u00e1sokhoz kapcsol\u00f3d\u00f3 \u00fczenetek (commit message) r\u00f6gz\u00edt\u00e9s\u00e9re, ami seg\u00edti a v\u00e1ltoztat\u00e1sok okainak \u00e9s c\u00e9ljainak dokument\u00e1l\u00e1s\u00e1t.
  • Integr\u00e1ci\u00f3 \u00e9s folyamatos fejleszt\u00e9s: Seg\u00edtik az automatikus tesztel\u00e9st \u00e9s a folyamatos integr\u00e1ci\u00f3s folyamatokat (CI/CD), mivel biztos\u00edtj\u00e1k, hogy minden v\u00e1ltoztat\u00e1s k\u00f6nnyen kezelhet\u0151 \u00e9s nyomon k\u00f6vethet\u0151 legyen.

"},{"location":"bevezetes/vscodegit/#git-source-control-forraskezeles-hasznalata-a-vs-code-ban","title":"Git source control (forr\u00e1skezel\u00e9s) haszn\u00e1lata a VS Code-ban","text":"

A Visual Studio Code integr\u00e1lt forr\u00e1skezel\u00e9ssel (SCM) rendelkezik, \u00e9s tartalmazza a Git t\u00e1mogat\u00e1st. Sok m\u00e1s forr\u00e1skezel\u0151 szolg\u00e1ltat\u00f3 \u00e9rhet\u0151 el a extensions oldalon a VS Code Marketplace-en.

"},{"location":"bevezetes/vscodegit/#git-repository","title":"Git repository","text":"

Gy\u0151z\u0151dj\u00f6n meg arr\u00f3l, hogy a Git telep\u00edtve van. A VS Code a sz\u00e1m\u00edt\u00f3g\u00e9pe Git-telep\u00edt\u00e9s\u00e9t fogja haszn\u00e1lni (legal\u00e1bb 2.0.0 verzi\u00f3 sz\u00fcks\u00e9ges), ez\u00e9rt telep\u00edtenie kell a Git-et, miel\u0151tt ezeket a szolg\u00e1ltat\u00e1sokat ig\u00e9nybe vehetn\u00e9.

A bal oldali tev\u00e9kenys\u00e9gs\u00e1vban tal\u00e1lhat\u00f3 Source control ikon mindig \u00e1ttekint\u00e9st ad arr\u00f3l, hogy h\u00e1ny v\u00e1ltoz\u00e1s van jelenleg a t\u00e1rhelyen (repo). Az ikon kiv\u00e1laszt\u00e1s\u00e1val megjelennek az aktu\u00e1lis adatt\u00e1r-m\u00f3dos\u00edt\u00e1sok r\u00e9szletei: CHANGES, STAGED CHANGES \u00e9s MERGE CHANGES.

Az egyes elemekre kattintva r\u00e9szletesen megtekintheti az egyes f\u00e1jlokon bel\u00fcli sz\u00f6veges v\u00e1ltoz\u00e1sokat. Vegye figyelembe, hogy a nem szakaszos m\u00f3dos\u00edt\u00e1sok eset\u00e9n a jobb oldali szerkeszt\u0151 tov\u00e1bbra is lehet\u0151v\u00e9 teszi a f\u00e1jl szerkeszt\u00e9s\u00e9t.

A repo st\u00e1tusz\u00e1ra vonatkoz\u00f3 indik\u00e1torokat is megtal\u00e1lhat\u00f3k a VS Code bal als\u00f3 sark\u00e1ban: az aktu\u00e1lis branch (current branch), dirty indicators, valamint a bej\u00f6v\u0151 \u00e9s kimen\u0151 commitok sz\u00e1ma. az aktu\u00e1lis \u00e1gb\u00f3l. A t\u00e1rhely b\u00e1rmely \u00e1g\u00e1t checkout-olhatja, ha r\u00e1kattint az \u00e1llapotjelz\u0151re, \u00e9s kiv\u00e1lasztja a Git hivatkoz\u00e1st a list\u00e1b\u00f3l.

Tip

A VS Code-ot megnyithatjuk egy Git-repo k\u00f6nyvt\u00e1r\u00e1ban. Ehhez a parancs a k\u00f6nyt\u00e1rban \u00e1llva: code . illetve pl: code ~/ros2_ws/src/arj_packages/, ha a tant\u00e1rgy arj_packages repoj\u00e1t szeret\u00e9nk megnyitni. A VS Code Git szolg\u00e1ltat\u00e1sai tov\u00e1bbra is a szok\u00e1sos m\u00f3don m\u0171k\u00f6dnek, \u00e9s minden v\u00e1ltoz\u00e1st megjelen\u00edtenek a t\u00e1rol\u00f3n bel\u00fcl, de a hat\u00f3k\u00f6r\u0171 k\u00f6nyvt\u00e1ron k\u00edv\u00fcli f\u00e1jlm\u00f3dos\u00edt\u00e1sok egy eszk\u00f6ztippel vannak \u00e1rny\u00e9kolva, jelezve, hogy az aktu\u00e1lis munkater\u00fcleten k\u00edv\u00fcl helyezkednek el.

"},{"location":"bevezetes/vscodegit/#commit","title":"Commit","text":"

Az staging (git add) \u00e9s unstaging (git reset) v\u00e9grehajthat\u00f3 a f\u00e1jlok kontextus szerinti m\u0171veleteivel vagy h\u00faz\u00e1ssal.

Konfigur\u00e1lja a Git-felhaszn\u00e1l\u00f3nev\u00e9t \u00e9s e-mail-c\u00edm\u00e9t. Commitol\u00e1skor, figyelni kell, hogy ha a felhaszn\u00e1l\u00f3n\u00e9v \u00e9s/vagy e-mail-c\u00edm be legyen \u00e1ll\u00edtva a Git-konfigur\u00e1ci\u00f3ban. R\u00e9szletek: [Git commit information] (https://git-scm.com/docs/git-commit#_commit_information).

Be\u00edrhat\u00f3 egy commit \u00fczenetet a v\u00e1ltoztat\u00e1sok jelz\u00e9s\u00e9re, ezut\u00e1n kbstyle(Ctrl+Enter) (macOS: kbstyle(\u2318+Enter)) billenty\u0171t kell \u00fctni a v\u00e9gleges\u00edt\u00e9shez. Ha vannak v\u00e1ltoztat\u00e1sok(staged chnages), csak azokat a v\u00e1ltoztat\u00e1sokat hajtj\u00e1k v\u00e9gre. Ellenkez\u0151 esetben a rendszer k\u00e9ri, hogy v\u00e1lassza ki, milyen v\u00e1ltoztat\u00e1sokat szeretne v\u00e9grehajtani.

P\u00e9ld\u00e1ul a kor\u00e1bbi k\u00e9perny\u0151k\u00e9pen csak az \"overview.png\" szakaszos m\u00f3dos\u00edt\u00e1sai szerepelnek a v\u00e9gleges\u00edt\u00e9sben. A k\u00e9s\u0151bbi szakaszol\u00e1si \u00e9s v\u00e9gleges\u00edt\u00e9si m\u0171veletek k\u00fcl\u00f6n v\u00e9gleges\u00edt\u00e9sk\u00e9nt tartalmazhatj\u00e1k a \"versioncontrol.md\" \u00e9s a m\u00e1sik k\u00e9t \".png\" k\u00e9p m\u00f3dos\u00edt\u00e1sait.

A pontosabb Commit m\u0171veletek a forr\u00e1skezel\u00e9s n\u00e9zet tetej\u00e9n tal\u00e1lhat\u00f3 Views and More Actions ... men\u00fcben tal\u00e1lhat\u00f3k.

Tipp: Ha rossz \u00e1gon (branch) hajtja v\u00e9gre a m\u00f3dos\u00edt\u00e1st, vonja vissza a v\u00e9gleges\u00edt\u00e9st a Command Palette Git: Undo Last Commit (Utols\u00f3 commit visszavon\u00e1sa) paranccsal (Ctrl+Shift+P).

"},{"location":"bevezetes/vscodegit/#repo-klonozasa","title":"Repo kl\u00f3noz\u00e1sa","text":"

Ha m\u00e9g nincs kl\u00f3nozva repository, akkor a Forr\u00e1skezel\u00e9s n\u00e9zetben a Open Folder a helyi g\u00e9pr\u0151l vagy a Clone Repository (t\u00e1voli g\u00e9pr\u0151l) lehet\u0151s\u00e9gek k\u00f6z\u00fcl v\u00e1laszthat.

A Clone Repository lehet\u0151s\u00e9get v\u00e1lasztva, a rendszer meg fogja k\u00e9rni a t\u00e1voli t\u00e1rhely URL-c\u00edm\u00e9t (p\u00e9ld\u00e1ul a GitHubon) \u00e9s azt a k\u00f6nyvt\u00e1rat, amelybe a helyi t\u00e1rat helyezi.

GitHub-t\u00e1rhely eset\u00e9n az URL-t a GitHub K\u00f3d p\u00e1rbesz\u00e9dpanelen tal\u00e1lja meg.

Ezut\u00e1n illessze be ezt az URL-t a Git: Clone promptba.

Megjelenik a Clone from GitHub lehet\u0151s\u00e9g is. Miut\u00e1n hiteles\u00edtette GitHub-fi\u00f3kj\u00e1t a VS Code-ban, kereshet\u0151 v\u00e1lnak a saj\u00e1t (ak\u00e1r priv\u00e1t) rep\u00f3k is, n\u00e9v alapj\u00e1n.

"},{"location":"bevezetes/vscodegit/#beepitett-terminal","title":"Be\u00e9p\u00edtett terminal","text":"

A fejleszt\u0151k\u00f6rnyezet be\u00e9p\u00edtett termin\u00e1lja, mind Windowson, mind Linuxon m\u0171k\u00f6dik.

"},{"location":"bevezetes/vscodegit/#hasznos-tudni","title":"Hasznos tudni","text":"
  • pl code . megnyintja az aktu\u00e1lis mappa tartalm\u00e1t
  • pl code ~/.bashrc megnyintja a ~/.bashrc tartalm\u00e1t szerkeszt\u00e9sre
"},{"location":"bevezetes/vscodegit/#wsl-vs-code-video","title":"WSL VS code vide\u00f3","text":""},{"location":"bevezetes/vscodegit/#ros-2-ajanlott-beallitasok","title":"ROS 2 aj\u00e1nlott be\u00e1ll\u00edt\u00e1sok","text":"

ROS 2 C++ fejleszt\u00e9sn\u00e9l alapvet\u0151en a VS code nem ismeri fel az ROS header f\u00e1jlokat, \u00edgy az pl az IntelliSense se m\u0171k\u00f6dik megfelel\u0151en:

Includepath VS code-ban

Erre egyszer\u0171 megold\u00e1s az includePath settings-re kattintva be\u00e1ll\u00edtani az /opt/ros/humble/** el\u00e9r\u00e9si utat. (Term\u00e9szetesen ugyanez m\u0171k\u00f6dik nem humble verzi\u00f3n\u00e1l is, ott a megfelel\u0151 el\u00e9r\u00e9si utat sz\u00fcks\u00e9ges megadni). Ez a k\u00f6vetkez\u0151k\u00e9pp n\u00e9z ki:

Includepath settings VS code-ban

Amennyiben mentette a VS code, az IntelliSense \u00e9s egy\u00e9b funkci\u00f3k is ennek megfelel\u0151en fognak m\u0171k\u00f6dni.

Forr\u00e1sok: code.visualstudio.com/docs/sourcecontrol/overview

"},{"location":"erzekeles/","title":"\u00c9rz\u00e9kel\u00e9s","text":"

Az \u00e9rz\u00e9kel\u00e9s nyers adatok beolvas\u00e1s\u00e1t jelenti.

\u00c9rz\u00e9kel\u00e9s eset\u00e9ben fontos felh\u00edvi a figyelmet, hogy ez m\u00e9g nem jelent magas szint\u0171 adatfeldolgoz\u00e1st. Szenzorai lehetnek kamer\u00e1k, mikrofonok, LIDAR-ok stb. Ahogy az \u00e1bra is mutatja a tananyagban az \u00e9rz\u00e9kel\u00e9ssel egy\u00fctt t\u00e1rgyaljuk az aktu\u00e1l\u00e1st is.

Note

Magyar nyelven k\u00f6nny\u0171 \u00f6sszekeverni az \u00e9rz\u00e9kel\u00e9s (sensing) \u00e9s az \u00e9szlel\u00e9s (perception) foglamakat. Az \u00e9rz\u00e9kel\u00e9s egyszer\u0171 driver szint\u0171 nyers adatok el\u0151\u00e1ll\u00edt\u00e1s\u00e1val foglakozik.

"},{"location":"erzekeles/#kamera","title":"Kamera","text":"

A kamera az \u00e9rz\u00e9kel\u0151j\u00e9re (pl CCD CMOS szenzor) \u00e9rkez\u0151 f\u00e9nyt elektronikus jell\u00e9 alak\u00edtja, diit\u00e1lisan. Megk\u00fcl\u00f6nb\u00f6ztethet\u00fcnk mono, sztereo vagy m\u00e9lys\u00e9g\u00e9rz\u00e9kel\u00e9sre k\u00e9pes kamer\u00e1kat is.

  • Jellemz\u0151 gy\u00e1rt\u00f3k: Allied Vision, Basler, Stereolabs, Orbbec, Intel
  • Jellemz\u0151 interf\u00e9sz: GigE, USB3
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/Image, sensor_msgs/msg/CameraInfo

M\u00e9lys\u00e9gesztim\u00e1ci\u00f3:

"},{"location":"erzekeles/#lidar","title":"LIDAR","text":"

A LIDAR (Light Detection and Ranging) szenzor egy olyan eszk\u00f6z, amely l\u00e9zerpulzusokkal \u00e9s azok visszaver\u0151d\u00e9si idej\u00e9b\u0151l t\u00e1vols\u00e1gokat k\u00e9pes meg\u00e1llap\u00edtani. Az elve hasnol\u00f3 a l\u00e9zeres t\u00e1vols\u00e1gm\u00e9r\u0151h\u00f6z, \u00e1m a m\u00e9r\u00e9s gyakoris\u00e1ga \u00e9s frekvenci\u00e1ja is sokkal naygobb ann\u00e1l. P\u00e9ldak\u00e9pp vegy\u00fcnk egy forg\u00f3 64 csatorn\u00e1s LIDAR-t. Ez jellemz\u0151en 10 vagy 20 Hz-en m\u00e9r, teh\u00e1t m\u00e1sodpercenk\u00e9nt 10 vagy 20 teljes 360\u00b0-os k\u00f6rbefordul\u00e1st tesz meg. A 64 csatorna azt jelenti, hogy minden pillanatban 64 egym\u00e1s alatti \u00e9rz\u00e9kel\u0151 \u00e9rz\u00e9kel. Egy k\u00f6rbefordul\u00e1st jellemz\u0151en 512 / 1024 / 2048 m\u00e9r\u00e9st jelent csatorn\u00e1nk\u00e9nt. Innen ki is sz\u00e1molhat\u00f3 a m\u00e1sodpercenk\u00e9nti m\u00e9r\u00e9sadat: pl 20*64*1024 = 1 310 720. Teh\u00e1t jellemz\u0151en m\u00e1sodpercenk\u00e9nt, t\u00f6bb mint egymilli\u00f3 3D pontot m\u00e9r az eszk\u00f6z, amihez intenzit\u00e1s, ambient, reflekt\u00edv tulajdons\u00e1gok is t\u00e1rsulnak.

  • Jellemz\u0151 gy\u00e1rt\u00f3k: Velodyne, Ouster, Livox, SICK, Hokuy, Pioneer, Luminar, Hesai, Robosense, Ibeo, Innoviz, Quanenergy, Cepton, Blickfeld, Aeva
  • Jellemz\u0151 interf\u00e9sz: GigE
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/PointCloud2, sensor_msgs/msg/LaserScan

LIDAR gy\u00e1rt\u00f3kat, dataseteket, algoritmusokat tartlamaz\u00f3 gy\u0171jtem\u00e9ny: github.com/szenergy/awesome-lidar.

"},{"location":"erzekeles/#radar","title":"Radar","text":"
  • Jellemz\u0151 gy\u00e1rt\u00f3k: Aptiv, Bosch, Continental, Denso
  • Jellemz\u0151 interf\u00e9sz: CAN bus
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: radar_msgs/msg/RadarTrack

A LIDAR \u00e9s a kamera jellemz\u0151inek \u00f6sszehasonl\u00edt\u00e1sa

"},{"location":"erzekeles/#imu","title":"IMU","text":"

Az IMU kis m\u00e9ret\u0171 elektromechanikus giroszk\u00f3pokat \u00e9s gyorsul\u00e1sm\u00e9r\u0151ket, valamint jelfeldolgoz\u00f3 processzorokat tartalmaz\u00f3 szenzor. Gyakran kombin\u00e1lj\u00e1k tov\u00e1bbi szenzorokkal, pl. barometrikus magass\u00e1gm\u00e9r\u0151vel, magnetom\u00e9terrel, ir\u00e1nyt\u0171vel. N\u00e9mely GPS (GNSS) rendszerben is megtal\u00e1lhat\u00f3k.

  • Jellemz\u0151 gy\u00e1rt\u00f3k: Lord MicroStrain, Bosch, XSens
  • Jellemz\u0151 interf\u00e9sz: Serial, Ethernet, USB, CAN bus
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/Imu, sensor_msgs/msg/MagneticField

"},{"location":"erzekeles/#gnss-gps","title":"GNSS (GPS)","text":"

A GNSS (global navigation satellite system) glob\u00e1lis szatelit-alap\u00fa navig\u00e1ci\u00f3s rendszert jelent, k\u00f6znapi sz\u00f3haszn\u00e1latban ezt szok\u00e1s GPS-nek nevezni. Ha pontosak szeretn\u00e9nk lenni, akkor a GPS csup\u00e1n az els\u0151 ilyen technol\u00f3gia ezen k\u00edv\u00fcl l\u00e9tezik m\u00e9g GLONASS, BeiDou, Galileo \u00e9s QZSS rendszer is, ezek \u00fczemeltet\u00e9se k\u00fcl\u00f6nb\u00f6z\u0151 \u00e1llamokhoz / sz\u00f6vets\u00e9gekhez k\u00f6t\u0151dik.

  • Jellemz\u0151 gy\u00e1rt\u00f3k: SwiftNavigation, VectorNav, Ublox, NovaTel
  • Jellemz\u0151 interf\u00e9sz: GigE, CAN bus
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/NavSatFix, geometry_msgs/msg/PoseStamped

R\u00f6vid, de j\u00f3 le\u00edr\u00e1s a GNSS pontoss\u00e1gr\u00f3l: www.sbg-systems.com/news/mastering-accurac-gnss-and-its-errors-sources/

"},{"location":"erzekeles/#can-bus","title":"CAN bus","text":"

A CAN bus (Controller Area Network) egy jellem\u0151en aut\u00f3ipari szabv\u00e1ny, mely lehet\u0151v\u00e9 teszi a mikrokontrollerek \u00e9s az eszk\u00f6z\u00f6k sz\u00e1m\u00e1ra, hogy k\u00f6zponti egys\u00e9g (host) n\u00e9lk\u00fcl kommunik\u00e1ljanak egym\u00e1ssal. Az ethernet kommunk\u00e1ci\u00f3val \u00f6sszevetve egyszer\u0171bb megval\u00f3s\u00edt\u00e1s, alacsonyabb s\u00e1vsz\u00e9less\u00e9g\u0171, robosztus.

  • Sebess\u00e9g adat lek\u00e9rdez\u00e9se, refencia jel
  • Korm\u00e1nysz\u00f6g adat lek\u00e9rdez\u00e9se, refencia jel
  • Jellemz\u0151 ROS 2 topic t\u00edpusok: can_msgs/msg/Frame, geometry_msgs/msg/Twist

"},{"location":"erzekeles/#ros-2-idokezeles","title":"ROS 2 id\u0151kezel\u00e9s","text":"

Az ROS id\u0151 kezel\u00e9sre a Unix-id\u0151t, vagy a POSIX-id\u0151t haszn\u00e1lja. Ez a UTC (greenwichi id\u0151) szerinti 1970. janu\u00e1r 1. 00:00:00 \u00f3ta eltelt m\u00e1sodpercek \u00e9s nanoszekundumok sz\u00e1m\u00e1t jelenti (int32 sec, int32 nsec). Ez egyr\u00e9szt relat\u00edv kis helyet foglal a mem\u00f3ri\u00e1ban, m\u00e1sr\u00e9szt k\u00f6nnyen sz\u00e1molhat\u00f3 k\u00e9t id\u0151pont k\u00f6z\u00f6tt eltelt id\u0151, m\u00e9gpedig egy egyszer\u0171 kivon\u00e1ssal.

ros2time.ipynb

H\u00e1tr\u00e1nya, hogy nem t\u00fal intuit\u00edv, nem olvashat\u00f3 az ember sz\u00e1m\u00e1ra. Pl. a Foxglove Studio ez\u00e9rt is gyakran \u00e1talak\u00edtja olvashat\u00f3bb form\u00e1tumra.

A m\u00e1sodpercek \u00e9s nanoszekundumok a k\u00f6vetkez\u0151k\u00e9pp k\u00e9pzelhet\u0151k el:

import rclpy\ncurrent_time = node.get_clock().now()\nprint(current_time.to_msg())\n\nOutput: \nsec=1694595162, nanosec=945886859\n

Az id\u0151b\u00e9lyeg t\u00f6bb helyen is szerepet kap:

ros2 topic echo /clock --once\nclock:\n  sec: 1689687476\n  nanosec: 770421827\n
ros2 topic echo --once /lexus3/gps/duro/current_pose\n\nheader:\n  stamp:\n    sec: 1694595162\n    nanosec: 945886859\n  frame_id: map\npose:\n  position:\n    x: 640142.9676535318\n    y: 5193606.439717201\n    z: 1.7999999523162842\n  orientation:\n    x: 0.008532664424537166\n    y: 0.0018914791588597107\n    z: 0.44068499630505714\n    w: 0.8976192678279703\n

Ha szeretn\u00e9nk \u00e1tv\u00e1latni a m\u00e1sodperceket \u00e9s nanoszekundumokat, azt a k\u00f6vetkez\u0151 m\u00f3don tehetj\u00fck meg:

from datetime import datetime\ncurrent_time_float = current_time.to_msg().sec + current_time.to_msg().nanosec / 1e9 # 1e9 is 1,000,000,000: nanosec to sec\nprint(\"As a float:\\t%.5f\" % (current_time_float))\nprint(\"ISO format:\", end=\"\\t\")\nprint(datetime.utcfromtimestamp(current_time_float).isoformat())\n\n\nOutput:\nAs a float: 1694595162.94589\nISO format: 2023-09-13T08:52:42.945887\n
"},{"location":"erzekeles/#forrasok","title":"Forr\u00e1sok","text":"
  • Szenzorok ROS-ben (online google prezent\u00e1ci\u00f3 magyarul)
  • docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Topics/Understanding-ROS2-Topics.html
"},{"location":"erzekeles/practice/","title":"Gyakorlat","text":"

A gyakorlat Ubuntu 22.04 ROS humble, Windows 10/11 WSL humble mellett m\u0171k\u00f6dik. A k\u00fcl\u00f6nb\u00f6z\u0151 verzi\u00f3k telep\u00edt\u00e9s\u00e9nek le\u00edr\u00e1sa itt tal\u00e1lhat\u00f3.

El\u0151zetes ellen\u0151rz\u00e9s

Otthoni g\u00e9pen a gyakorlat el\u0151tt \u00e9rdemes ellen\u0151rizni, hogy a megfelel\u0151 ROS 2 szoftvercsomagok telep\u00edtve vannak-e.

sudo apt install ros-humble-rosbag2 ros-humble-rosbag2-storage-mcap\n

G\u00e9pteremben is ellen\u0151rizz\u00fck a check_all.sh seg\u00edts\u00e9g\u00e9vel:

cd /mnt/kozos/script\n

./check_all.sh\n
./bag_mcap.sh\n
"},{"location":"erzekeles/practice/#elokeszuletek","title":"El\u0151k\u00e9sz\u00fcletek","text":"

Az el\u0151z\u0151 gyakorlaton megismerkedt\u00fcnk a k\u00f6vetkez\u0151 rosbag-gel (ROS 2-ben a form\u00e1tum m\u00e1r .mcap):

El\u0151k\u00e9sz\u00fcletk\u00e9nt n\u00e9zz\u00fck meg, hogy l\u00e9tezik-e a C:\\temp k\u00f6nyvt\u00e1r

test -d \"/mnt/c/temp\" && echo Letezik || echo Nem letezik\n
Vagy egyszer\u0171bben:
ls /mnt/c/temp\n

  • Ha nem l\u00e9tezik (No such file or directory), akkor hozzuk l\u00e9tre: mkdir /mnt/c/temp
  • Ha l\u00e9tezik, akkor nincs teend\u0151nk, l\u00e9pj\u00fcnk a k\u00f6vetkez\u0151 l\u00e9p\u00e9sre, m\u00e1soljuk \u00e1t ide az .mcap f\u00e1jlokat

List\u00e1zzuk a m\u00e9r\u00e9sadatokat a mnt/kozos/measurement_files k\u00f6nyvt\u00e1rban:

ls /mnt/kozos/measurement_files/ -lh\n
Az eredm\u00e9ny valami hasonl\u00f3 lesz:
-rwxrwxrwx 1 he he 4.9K Aug 23  2023 leaf01foxglove.json\n-rwxrwxrwx 1 he he 6.6K Sep  4  2023 lexus01foxglove.json\n-rwxrwxrwx 1 he he 2.7G Jun 10 09:17 lexus-2023-07-18-campus.mcap\n-rwxrwxrwx 1 he he 541M Apr 11 17:01 lexus3-2024-04-05-gyor.mcap\n

Tanteremben a m\u00e1sol\u00e1s a k\u00f6vetkez\u0151 parancs seg\u00edts\u00e9g\u00e9vel:

rsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap  /mnt/c/temp/\n

Figyelem

A f\u00e1jl m\u00e9rete miatt a m\u00e1sol\u00e1s n\u00e9h\u00e1ny percig is eltarthat.

Otthon a k\u00f6vetkez\u0151 linkr\u0151l (z\u00f6ld gomb), vagy parancsk\u00e9nt wget-el lehet let\u00f6lteni:

wget  -O lexus3-2024-04-05-gyor.mcap https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/Eclwzn42FS9GunGay5LPq-EBA6U1dZseBFNDrr6P0MwB2w?download=1\n

MCAP let\u00f6lt\u00e9se 553 MB

List\u00e1zzuk a megfelel\u0151 \u00e1tm\u00e1solt .mcap f\u00e1jl alap inform\u00e1ci\u00f3it, hasonl\u00f3an:

ros2 bag info /mnt/c/temp/lexus3-2024-04-05-gyor.mcap\n

Az eredm\u00e9ny hasnl\u00f3 lesz:

Files:             /mnt/c/temp/lexus3-2024-04-05-gyor.mcap\nBag size:          540.7 MiB\nStorage id:        mcap\nDuration:          12.519s\nStart:             Apr  5 2024 14:51:02.480 (1712321462.480)\nEnd:               Apr  5 2024 14:51:14.999 (1712321474.999)\nMessages:          5930\nTopic information: \n  Topic: /lexus3/gps/duro/status_string | Type: std_msgs/msg/String | Count: 124\n  Topic: /tf_static | Type: tf2_msgs/msg/TFMessage | Count: 24\n  Topic: /tf | Type: tf2_msgs/msg/TFMessage | Count: 2597\n  Topic: /lexus3/os_right/points | Type: sensor_msgs/msg/PointCloud2 | Count: 247\n  Topic: /lexus3/os_left/points | Type: sensor_msgs/msg/PointCloud2 | Count: 249\n  Topic: /lexus3/gps/duro/time_ref | Type: sensor_msgs/msg/TimeReference | Count: 124\n  Topic: /lexus3/gps/duro/status_flag | Type: std_msgs/msg/UInt8 | Count: 124\n  Topic: /lexus3/gps/duro/mag | Type: sensor_msgs/msg/MagneticField | Count: 315\n  Topic: /lexus3/gps/duro/time_diff | Type: std_msgs/msg/Float64 | Count: 124\n  Topic: /lexus3/os_center/points | Type: sensor_msgs/msg/PointCloud2 | Count: 246\n  Topic: /lexus3/gps/duro/navsatfix | Type: sensor_msgs/msg/NavSatFix | Count: 124\n  Topic: /lexus3/gps/duro/imu | Type: sensor_msgs/msg/Imu | Count: 1259\n  Topic: /lexus3/gps/duro/current_pose | Type: geometry_msgs/msg/PoseStamped | Count: 124\n  Topic: /lexus3/zed2i/zed_node/left/image_rect_color/compressed | Type: sensor_msgs/msg/CompressedImage | Count: 249\n
"},{"location":"erzekeles/practice/#jatsszuk-vissza-az-mcap-fajlt","title":"J\u00e1tsszuk vissza az .mcap f\u00e1jlt","text":"

A k\u00f6vetkez\u0151ken a m\u00e9r\u00e9sadatf\u00e1jlt visszaj\u00e1tsszuk \u00e9s ellen\u0151rizz\u00fck, hogy milyen adatok jelennek meg, milyen t\u00edpusban \u00e9s sebess\u00e9ggel. A --loop kapcsol\u00f3 a v\u00e9gtelen ism\u00e9tl\u00e9st, a --clock kapcsol\u00f3 pedig egy /clock topic hirdet\u00e9s\u00e9\u00e9rt felel, ehhez igaz\u00edtja a lej\u00e1tsz\u00e1st.

ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap --clock --loop\n
Ugyanez, csak lassabban visszaj\u00e1tszva pl.:

ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap --clock --loop --rate 0.2\n

A k\u00f6vetkez\u0151 topic-ok jelennek meg:

ros2 topic list\n

Eredm\u00e9nye valami hasonl\u00f3 lesz:

/clock\n/events/read_split\n/lexus3/gps/duro/current_pose\n/lexus3/gps/duro/imu\n/lexus3/gps/duro/mag\n/lexus3/gps/duro/navsatfix\n/lexus3/gps/duro/status_flag\n/lexus3/gps/duro/status_string\n/lexus3/gps/duro/time_diff\n/lexus3/gps/duro/time_ref\n/lexus3/os_center/points\n/lexus3/os_left/points\n/lexus3/os_right/points\n/lexus3/zed2i/zed_node/left/image_rect_color/compressed\n/parameter_events\n/rosout\n/tf\n/tf_static\n

A ros2 topic hz az adott topic frekvenci\u00e1j\u00e1t mutatja. A poz\u00edci\u00f3 ebben az esetben ~10Hz.

ros2 topic hz /lexus3/gps/duro/current_pose\n
Az eredm\u00e9ny valami hasonl\u00f3 lesz:
average rate: 9.994\n        min: 0.003s max: 1.005s std dev: 0.09166s window: 107\n

"},{"location":"erzekeles/practice/#ros-2-idokezeles","title":"ROS 2 id\u0151kezel\u00e9s","text":"

Az ROS id\u0151 kezel\u00e9sre a Unix-id\u0151t, vagy a POSIX-id\u0151t haszn\u00e1lja. Ez a UTC (greenwichi id\u0151) szerinti 1970. janu\u00e1r 1. 00:00:00 \u00f3ta eltelt m\u00e1sodpercek \u00e9s nanoszekundumok sz\u00e1m\u00e1t jelenti (int32 sec, int32 nsec). Ez egyr\u00e9szt relat\u00edv kis helyet foglal a mem\u00f3ri\u00e1ban, m\u00e1sr\u00e9szt k\u00f6nnyen sz\u00e1molhat\u00f3 k\u00e9t id\u0151pont k\u00f6z\u00f6tt eltelt id\u0151, m\u00e9gpedig egy egyszer\u0171 kivon\u00e1ssal.

ros2time.ipynb

H\u00e1tr\u00e1nya, hogy nem t\u00fal intuit\u00edv, nem olvashat\u00f3 az ember sz\u00e1m\u00e1ra. Pl. a Foxglove Studio ez\u00e9rt is gyakran \u00e1talak\u00edtja olvashat\u00f3bb form\u00e1tumra.

A m\u00e1sodpercek \u00e9s nanoszekundumok a k\u00f6vetkez\u0151k\u00e9pp k\u00e9pzelhet\u0151k el:

import rclpy\ncurrent_time = node.get_clock().now()\nprint(current_time.to_msg())\n\nOutput: \nsec=1694595162, nanosec=945886859\n

Az id\u0151b\u00e9lyeg t\u00f6bb helyen is szerepet kap:

ros2 topic echo /clock --once\nclock:\n  sec: 1689687476\n  nanosec: 770421827\n

ros2 topic echo --once /lexus3/gps/duro/current_pose\n
Az eredm\u00e9ny valami hasonl\u00f3 lesz:

header:\n  stamp:\n    sec: 1694595162\n    nanosec: 945886859\n  frame_id: map\npose:\n  position:\n    x: 640142.9676535318\n    y: 5193606.439717201\n    z: 1.7999999523162842\n  orientation:\n    x: 0.008532664424537166\n    y: 0.0018914791588597107\n    z: 0.44068499630505714\n    w: 0.8976192678279703\n

Ha szeretn\u00e9nk \u00e1tv\u00e1latni a m\u00e1sodperceket \u00e9s nanoszekundumokat, azt a k\u00f6vetkez\u0151 m\u00f3don tehetj\u00fck meg:

from datetime import datetime\ncurrent_time_float = current_time.to_msg().sec + current_time.to_msg().nanosec / 1e9 # 1e9 is 1,000,000,000: nanosec to sec\nprint(\"As a float:\\t%.5f\" % (current_time_float))\nprint(\"ISO format:\", end=\"\\t\")\nprint(datetime.utcfromtimestamp(current_time_float).isoformat())\n\n\nOutput:\nAs a float: 1694595162.94589\nISO format: 2023-09-13T08:52:42.945887\n

Eml\u00e9keztet\u0151: a nanoszekundum a m\u00e1sodperc egy milli\u00e1rdodr\u00e9sze (10^-9 s).

"},{"location":"erzekeles/practice/#global-navigation-satellite-system-gnss-global-positioning-system-gps","title":"Global Navigation Satellite System (GNSS) / Global Positioning System (GPS)","text":"

A k\u00f6veztkez\u0151kben \u00e1tn\u00e9z\u00fcnk p\u00e1r jellemz\u0151 szenzort (GPS, kamera, LIDAR) \u00e9s azok topic-jait, node-jait (driver package-ekbe szervezve). Vess\u00fcnk egy pillant\u00e1st a saj\u00e1t fejleszt\u00e9s\u0171 Duro GPS (GNSS) driverre: github.com/szenergy/duro_gps_driver. A GPS-t etherneten a sz\u00e1m\u00edt\u00f3g\u00e9phez csatlakoztatva, az ROS drivert ind\u00edtva a k\u00f6vetkez\u0151 topicokat fogja hirdetni:

Topic Type /gps/duro/current_pose [geometry_msgs/PoseStamped] /gps/duro/fix [sensor_msgs/NavSatFix] /gps/duro/imu [sensor_msgs/Imu] /gps/duro/mag [sensor_msgs/MagneticField] /gps/duro/odom [nav_msgs/Odometry] /gps/duro/rollpitchyaw [geometry_msgs/Vector3] /gps/duro/status_flag [std_msgs/UInt8] /gps/duro/status_string [std_msgs/String] /gps/duro/time_ref [sensor_msgs/TimeReference]"},{"location":"erzekeles/practice/#inertial-measurement-unit-imu","title":"Inertial Measurement Unit (IMU)","text":"

Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/Imu, sensor_msgs/msg/MagneticField

ros2 topic echo --once /lexus3/gps/duro/imu\n
Az eredm\u00e9ny valami hasonl\u00f3 lesz:

header:\n  stamp:\n    sec: 1695039048\n    nanosec: 44466475\n  frame_id: duro\norientation:\n  x: 0.0\n  y: 0.0\n  z: 0.7071067811865475\n  w: 0.7071067811865476\norientation_covariance:\n  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\nangular_velocity:\n  x: 0.01330030487804878\n  y: 0.015893864329268294\n  z: 0.037307355182926834\nangular_velocity_covariance:\n  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\nlinear_acceleration:\n  x: -0.5291185668945312\n  y: 0.031124621582031248\n  z: -9.610325463867188\nlinear_acceleration_covariance:\n  - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]\n
"},{"location":"erzekeles/practice/#kamera","title":"Kamera","text":"

Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/Image, sensor_msgs/msg/CameraInfo, sensor_msgs/msg/CompressedImage

Attz\u00f3l f\u00fcgg\u0151en, hogy a kamera k\u00e9pe t\u00f6m\u00f6r\u00edtett vagy sem, a sensor_msgs/msg/Image vagy a sensor_msgs/msg/CompressedImage t\u00edpus\u00fa \u00fczeneteket fogunk l\u00e1tni. Haszn\u00e1ljuk a megfelel\u0151 topic-ot.

ros2 topic echo --once /lexus3/zed2i/zed_node/right_raw/image_raw_color\n
ros2 topic echo --once /lexus3/zed2i/zed_node/left/image_rect_color/compressed\n

Az eredm\u00e9ny valami hasonl\u00f3 lesz:

header:\n  stamp:\n    sec: 1695039047\n    nanosec: 340698516\n  frame_id: zed2i_right_camera_optical_frame\nheight: 720\nwidth: 1280\nencoding: bgra8 # vagy format: bgra8; jpeg compressed bgr8\nis_bigendian: 0\nstep: 5120\ndata: 21,66,93,255,21,66,94,255,25,69,94,255,14,63,90,255,31,55,80,255,19,49,75,255,26,55,76,255,24,57,80,255,35,51,72,255,30,52,74,255,57,73,88,255,55,74,90,255,64,74,93,255,52,66,86,255,56,61,76,255,25,34,48,255,25,31,52,255,16,24,43,255,14,22,41,255,19,27,46,255,13,20,38,255,23,28,45,255,31,41,65,255,36,37,59,255,23,59,82,255,45,71,91,255,51,84,116,255,70,94,122,255,57,105,141,255,42,84,117,255,42,90,126,255,36,81,116,255,..\n
"},{"location":"erzekeles/practice/#lidar","title":"LIDAR","text":"

Jellemz\u0151 ROS 2 topic t\u00edpusok: sensor_msgs/msg/PointCloud2, sensor_msgs/msg/LaserScan

ros2 topic echo --once /lexus3/os_center/points\n
Az eredm\u00e9ny valami hasonl\u00f3 lesz:

header:\n  stamp:\n    sec: 1695039048\n    nanosec: 390894137\n  frame_id: lexus3/os_center_a_laser_data_frame\nheight: 64\nwidth: 1024\nfields:\n- name: x, y, z, intensity, t, reflectivity, ring, ambient, range\ndata: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,16,65,96,211,241,2,0,0,0,0,12,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,16,65,116,145,242,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,63,0,0,32,65,18,92,243,2,0,0,0,0,253,2,0,0,...,\n
"},{"location":"erzekeles/practice/#vizualizacio","title":"Vizualiz\u00e1ci\u00f3","text":""},{"location":"erzekeles/practice/#rviz2","title":"RVIZ2","text":"
ros2 run rviz2 rviz2\n

Alak\u00edtsunk ki hasonl\u00f3 elrendez\u00e9st:

"},{"location":"erzekeles/practice/#foxglove-studio","title":"Foxglove studio","text":"
ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765\n

Alak\u00edtsunk ki hasonl\u00f3 elrendez\u00e9st:

Forr\u00e1s: foxglove.dev/blog/introducing-foxglove-studios-new-navigation

"},{"location":"erzekeles/practice/#hozzuk-letre-a-simple_sub_cpp-package-t","title":"Hozzuk l\u00e9tre a simple_sub_cpp package-t","text":"

A k\u00f6vetkez\u0151kben egy egyszer\u0171 subscriber node fog feliratkozni geometry_msgs/PoseStamped \u00fczenetekre, majd ki\u00edrni az X \u00e9s az Y koordin\u00e1t\u00e1kat. A gyakorlat a hivatalos ROS 2 tutorialokon alapszik fel\u00e9p\u00edt\u00e9s\u00e9t tekintve.

Nyissunk egy \u00faj termin\u00e1lt, \u00e9s source-oljuk a telep\u00edt\u00e9st, hogy a ros2 parancsok m\u0171k\u00f6djenek.

Navig\u00e1ljunk az m\u00e1r l\u00e9trehozott ros2_ws k\u00f6nyvt\u00e1rba.

Fontos, hogy a csomagokat az src k\u00f6nyvt\u00e1rban kell l\u00e9trehozni, nem a munkater\u00fclet gy\u00f6ker\u00e9ben. Teh\u00e1t navig\u00e1ljunk a ros2_ws/src mapp\u00e1ba, \u00e9s futtassuk a package l\u00e9trehoz\u00f3 parancsot:

cd ~/ros2_ws/src\nros2 pkg create --build-type ament_cmake simple_sub_cpp\n

A termin\u00e1l egy \u00fczenetet k\u00fcld vissza, amely meger\u0151s\u00edti a simple_sub_cpp csomag \u00e9s az \u00f6sszes sz\u00fcks\u00e9ges f\u00e1jl \u00e9s mappa l\u00e9trehoz\u00e1s\u00e1t.

"},{"location":"erzekeles/practice/#irjuk-meg-a-subscriber-node-ot-print_posecpp-simple_sub_node","title":"\u00cdrjuk meg a subscriber node-ot (print_pose.cpp >> simple_sub_node)","text":"

L\u00e9pj\u00fcnk a ros2_ws/src/simple_sub_cpp/src mapp\u00e1ba.

cd ~/ros2_ws/src/simple_sub_cpp/src\n

Ez az a k\u00f6nyvt\u00e1r minden CMake package-ben, ahov\u00e1 a forr\u00e1sf\u00e1jlok tartoznak (pl. .cpp kiterjeszt\u00e9ssel).

T\u00f6lts\u00fck le a p\u00e9lda feliratkoz\u00f3 k\u00f3dj\u00e1t:

wget -O print_pose.cpp https://raw.githubusercontent.com/sze-info/arj_packages/main/etc/print_pose.cpp\n

Ez a parancs l\u00e9trehozta a print_pose.cpp f\u00e1jlt.

L\u00e9pj\u00fcnk vissza egy szinttel: cd ~/ros2_ws/src/simple_sub_cpp k\u00f6nyvt\u00e1rba, ahol a CMakeLists.txt \u00e9s a package.xml f\u00e1jlok m\u00e1r l\u00e9trej\u00f6ttek. Nyissuk meg pl. VS code seg\u00edts\u00e9g\u00e9vel a mapp\u00e1t: code . parancs. Itt a . a code ut\u00e1n az aktu\u00e1lis mapp\u00e1t jelenti. Tipp: ha nem a k\u00f6nyvt\u00e1rban \u00e1lln\u00e1nk, akkor is lehets\u00e9ges teljes k\u00f6nyvt\u00e1rat megnyitni, ami k\u00e9s\u0151bb p\u00e1r dolgot egyszer\u0171s\u00edt:

code ~/ros2_ws/src/simple_sub_cpp/\n

// ros2 topic type /lexus3/gps/duro/current_pose\n// geometry_msgs/msg/PoseStamped\n// ros2 interface show geometry_msgs/msg/PoseStamped\n\n#include <memory>\n#include \"rclcpp/rclcpp.hpp\"\n#include \"geometry_msgs/msg/pose_stamped.hpp\"\n\nusing std::placeholders::_1;\n\nclass SimplePoseSub : public rclcpp::Node\n{\npublic:\n  SimplePoseSub() : Node(\"simple_pose_sub\")\n  {\n    sub1_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(\"/lexus3/gps/duro/current_pose\", 10, std::bind(&SimplePoseSub::topic_callback, this, _1));\n  }\n\nprivate:\n  void topic_callback(const geometry_msgs::msg::PoseStamped &msg) const\n  {\n    RCLCPP_INFO(this->get_logger(), \"x: %.3f, y: %.3f\", msg.pose.position.x, msg.pose.position.y);\n  }\n  rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr sub1_;\n};\n\nint main(int argc, char *argv[])\n{\n  rclcpp::init(argc, argv);\n  rclcpp::spin(std::make_shared<SimplePoseSub>());\n  rclcpp::shutdown();\n  return 0;\n}\n

Python megfelel\u0151je

A C++ k\u00f3d python verzi\u00f3ja szint\u00e9n el\u00e9rhet\u0151 a github.com/sze-info/arj_packages c\u00edmen. \u00c9rdemes \u00f6sszehasonl\u00edtani a C++ \u00e9s a python k\u00f3dokat.

"},{"location":"erzekeles/practice/#fuggosegek-hozzaadasa","title":"F\u00fcgg\u0151s\u00e9gek hozz\u00e1ad\u00e1sa","text":"

Mindig \u00e9rdemes kit\u00f6lteni a <description>, <maintainer> \u00e9s <license> tag-eket:

<description>Examples of minimal publisher/subscriber using rclcpp</description>\n<maintainer email=\"you@email.com\">Your Name</maintainer>\n<license>Apache License 2.0</license>\n

Adjunk hozz\u00e1 egy \u00faj sort az ament_cmake buildtool f\u00fcgg\u0151s\u00e9ge ut\u00e1n, \u00e9s illessz\u00fck be a k\u00f6vetkez\u0151 f\u00fcgg\u0151s\u00e9geket a node include utas\u00edt\u00e1sainak megfelel\u0151en:

<depend>rclcpp</depend>\n<depend>geometry_msgs</depend>\n

Ez deklar\u00e1lja, hogy a pacakge-nek sz\u00fcks\u00e9ges az rclcpp \u00e9s a geometry_msgs ford\u00edt\u00e1skor \u00e9s futtat\u00e1skor.

"},{"location":"erzekeles/practice/#cmakeliststxt","title":"CMakeLists.txt","text":"

Most nyissuk meg a CMakeLists.txt f\u00e1jlt. A megl\u00e9v\u0151 find_package(ament_cmake REQUIRED) f\u00fcgg\u0151s\u00e9g al\u00e1 adjuk hozz\u00e1 a k\u00f6vetkez\u0151 sorokat:

find_package(rclcpp REQUIRED)\nfind_package(geometry_msgs REQUIRED)\n

Ezut\u00e1n adjuk hozz\u00e1 a v\u00e9grehajthat\u00f3 f\u00e1jlt (ez most a print_pose.cpp-b\u0151l fog csak \u00e1llni), \u00e9s nevezz\u00fck el simple_sub_node-nak, hogy az ros2 run haszn\u00e1lat\u00e1val futtassa a node-ot:

add_executable(simple_sub_node src/print_pose.cpp)\nament_target_dependencies(simple_sub_node rclcpp geometry_msgs)\n

V\u00e9g\u00fcl az install(TARGETS...) r\u00e9szt adjuk hozz\u00e1, hogy az ros 2 megtal\u00e1lja a futtathat\u00f3 \u00e1llom\u00e1nyt, amit leford\u00edtottunk:

install(TARGETS\nsimple_sub_node\nDESTINATION lib/${PROJECT_NAME})\n

A CMakeLists.txt megtiszt\u00edthat\u00f3 n\u00e9h\u00e1ny felesleges szakasz \u00e9s megjegyz\u00e9s elt\u00e1vol\u00edt\u00e1s\u00e1val, \u00edgy a k\u00f6vetkez\u0151k\u00e9ppen n\u00e9z ki:

cmake_minimum_required(VERSION 3.8)\nproject(simple_sub_cpp)\n\n# Default to C++14\nif(NOT CMAKE_CXX_STANDARD)\nset(CMAKE_CXX_STANDARD 14)\nendif()\n\nif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\nadd_compile_options(-Wall -Wextra -Wpedantic)\nendif()\n\nfind_package(ament_cmake REQUIRED)\nfind_package(rclcpp REQUIRED)\nfind_package(geometry_msgs REQUIRED)\n\nadd_executable(simple_sub_node src/print_pose.cpp)\nament_target_dependencies(simple_sub_node rclcpp geometry_msgs)\n\ninstall(TARGETS\nsimple_sub_node\nDESTINATION lib/${PROJECT_NAME})\n\nament_package()\n

\u00d6sszefoglal\u00e1sk\u00e9pp, a k\u00f6vetkez\u0151 m\u00f3dos\u00edt\u00e1sokat hajtottuk v\u00e9gre:

"},{"location":"erzekeles/practice/#build-es-futtatas","title":"Build \u00e9s futtat\u00e1s","text":"

Success

M\u00e1r buildelhet\u0151 a package:

cd ~/ros2_ws/\n
colcon build --packages-select simple_sub_cpp\n

Futtassuk a szok\u00e1sos m\u00f3don:

source ~/ros2_ws/install/setup.bash\n
ros2 run simple_sub_cpp simple_sub_node\n

Kimenet:

[simple_pose_sub]: x: 697201.725, y: 5285679.845\n[simple_pose_sub]: x: 697201.796, y: 5285679.548\n[simple_pose_sub]: x: 697201.838, y: 5285679.251\n[simple_pose_sub]: x: 697201.886, y: 5285678.949\n
"},{"location":"erzekeles/practice/#hazi-feladat","title":"H\u00e1zi feladat","text":"

H\u00e1zi feladat

Otthon k\u00e9sz\u00edts\u00fck el a simple_sub_py package-t, ami a simple_sub_cpp python megfelel\u0151je.

"},{"location":"erzekeles/practice/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
"},{"location":"eszleles/","title":"\u00c9szlel\u00e9s","text":"

Az \u00e9szlel\u00e9s (perception) az \u00e9rz\u00e9kelt nyers adatokb\u00f3l t\u00f6rt\u00e9n\u0151 inform\u00e1ci\u00f3 kinyer\u00e9se.

Az \u00e9szlel\u00e9s c\u00e9lja lehet:

  • Objektumfelismer\u00e9s (detekci\u00f3), pl:
    • Gyalogos, biciklis j\u00e1rm\u0171 felimer\u00e9s
    • T\u00e1bla felismer\u00e9s, jelz\u0151l\u00e1mpa felismer\u00e9s
    • Vezethet\u0151 fel\u00fclet \u00e9s fogalmi s\u00e1v felismer\u00e9s (lokaliz\u00e1ci\u00f3hoz \u00e9s tervez\u00e9shez is)
  • Objektumklasszifik\u00e1ci\u00f3:
    • A m\u00e1r felismert objektumok oszt\u00e1lyz\u00e1sa. Pl a jelz\u0151l\u00e1mpa milyen sz\u00edn\u0171 \u00e9ppen, melyik j\u00e1rm\u0171 kisteheraut\u00f3 \u00e9s melyik lovaskocsi.
  • Objektum k\u00f6vet\u00e9s \u00e9s predikci\u00f3:
    • Merre haladtak eddig a j\u00e1rm\u0171vek, gyalogosok illetve becsl\u00e9s, hogy merre haladnak majd a j\u00f6v\u0151ben. Ez \u00f6sszef\u00fcgghet a klasszifik\u00e1ci\u00f3val, hiszen b\u00e1r egy lovaskocsi m\u00e9retre hasonl\u00f3 egy ut\u00e1nfut\u00f3s aut\u00f3hoz, m\u00e9gis eg\u00e9sz m\u00e1s gyorsul\u00e1sra k\u00e9pes. Az \u00edgy gy\u0171jt\u00f6tt infrom\u00e1ci\u00f3nak megfele\u0151en lehet \u00fatvonalat, tarjekt\u00f3ri\u00e1t tevezni.
  • Lokaliz\u00e1ci\u00f3 \u00e9s t\u00e9rk\u00e9p\u00e9p\u00edt\u00e9s
    • SLAM: nem illetve nem csak GNSS alap\u00fa helymeghat\u00e1roz\u00e1s kieg\u00e9sz\u00edt\u00e9se lok\u00e1lis t\u00e9rk\u00e9pp k\u00e9sz\u00edt\u00e9ssel. LOAM: LIDAR alap\u00fa odometria.

A felhaszn\u00e1lt szenzorok alapj\u00e1n lehet: - LIDAR - Kamera - Radar - IMU - GNSS/GPS - Mikrofon - A fenti szenzorok tetsz\u0151leges kombin\u00e1ci\u00f3ja

Danger

Magyar nyelven k\u00f6nny\u0171 \u00f6sszekeverni az \u00e9rz\u00e9kel\u00e9s (sensing) \u00e9s az \u00e9szlel\u00e9s (perception) foglamakat. Az \u00e9szlel\u00e9s \u00f6sszetett funkci\u00f3 a nyers adatokb\u00f3l feldolgozott, \u00e9rtelmezett kimenet el\u0151\u00e1ll\u00edt\u00e1s\u00e1val foglakozik.

flowchart LR\n\nL[Tervez\u00e9s]:::light\n\nsubgraph Perception [\u00c9szlel\u00e9s]\n  T[T\u00e9rk\u00e9pez\u00e9s]:::light \n  H[Lokaliz\u00e1ci\u00f3]:::light\n  P[Objektum\n  predikci\u00f3]:::light \n  D[Objektum\n  detekci\u00f3]:::light\n  K[Objektum \n  klasszifik\u00e1ci\u00f3]:::light\n  D-->K\nend\nsubgraph Sensing [\u00c9rz\u00e9kel\u00e9s]\n  GPS[GPS/GNSS]:::light -.-> T\n  GPS -.-> H\n  LIDAR[LIDAR]:::light\n  KAM[Kamera]:::light\n  IMU[IMU]:::light\n  LIDAR -.-> D\n  LIDAR -.-> P\n  LIDAR -.-> T\n  KAM-.-> P\n  KAM-.-> D\n  IMU-.-> T\n  D-.->P\nend\n\nT -->|t\u00e9rk\u00e9p| L\nH -->|pose| L\nP -->|obj.| L\nK -->|obj.| L\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n

Ez a tananyagr\u00e9sz a TU M\u00fcnchen Autonomous Driving Software Engineering tant\u00e1rgy tananyag\u00e1n alapszik, amit az Institute of Automotive Technology int\u00e9zet munkat\u00e1rsai \u00e1ll\u00edtottak \u00f6ssze. Az \u00f3rai vide\u00f3 el\u00e9rhet\u0151 n\u00e9met nyelven:

"},{"location":"eszleles/#kihivasok-nehezsegek","title":"Kih\u00edv\u00e1sok, neh\u00e9zs\u00e9gek","text":"

Sz\u00e1mos kih\u00edv\u00e1s nehez\u00edtheti a felismer\u00e9st illetve annak pontoss\u00e1g\u00e1t:

  • Id\u0151j\u00e1r\u00e1s (es\u0151, h\u00f3, k\u00f6d, ...)
  • Napszak (\u00e9jszaka, naplemente, napfelkelte ...)
  • Takar\u00e1s (objektumok csak r\u00e9szlegesen l\u00e1tszanak)
  • Sz\u00e1m\u00edt\u00e1si id\u0151 (nagyobb sebess\u00e9gekn\u00e9l hatv\u00e1nyozottan)
  • K\u00fcl\u00f6nb\u00f6z\u0151 k\u00f6nyezetek (v\u00e1rosi, aut\u00f3p\u00e1lya, erd\u0151s szakasz ...)
"},{"location":"eszleles/#use-case-esettanulmanyok","title":"Use case (esettanulm\u00e1nyok)","text":"

Mivel az \u00e9szlel\u00e9s minden egyes aspektus\u00e1t neh\u00e9z lenne bemutani, ink\u00e1bb p\u00e1r use-case seg\u00edts\u00e9g\u00e9vel mutatn\u00e1nk be.

"},{"location":"eszleles/#kamera-alapu-jelzolampa-klasszifikacio","title":"Kamera-alap\u00fa jelz\u0151l\u00e1mpa klasszifik\u00e1ci\u00f3","text":"

Mesters\u00e9ges intelligencia (neur\u00e1lis h\u00e1l\u00f3: YOLOv7) seg\u00edts\u00e9g\u00e9vel kamerak\u00e9p feldolgoz\u00e1s.

"},{"location":"eszleles/#lidar-alapu-egyszeru-magassag-szures","title":"LIDAR-alap\u00fa egyszer\u0171 magass\u00e1g sz\u0171r\u00e9s","text":"

A gyakorlaton is el\u0151ker\u00fcl\u0151 feladat egyszer\u0171 LIDAR sz\u0171r\u00e9s, X, Y \u00e9s Z koordin\u00e1t\u00e1k szerint. Mivel a LIDAR a 3D k\u00f6rnyezet egyszer\u0171 reprezent\u00e1ci\u00f3j\u00e1t adja bizonyos szempontb\u00f3l k\u00f6nnyebb dolgunk van vele, mint a kamer\u00e1val. Gyakori technol\u00f3gia, hogy az \u00fat szintj\u00e9t sz\u0171rik ki a LIDAR adatb\u00f3l(ground-segmentation), majd a marad\u00e9k pontok (non-ground) jelentik az \u00f6sszes objektumot. Itt egy sokkal egyszer\u0171bb technol\u00f3gi\u00e1t demonstr\u00e1lunk:

"},{"location":"eszleles/#klaszterezes","title":"Klaszterez\u00e9s","text":"

Miut\u00e1n az \u00fat szintj\u00e9t kisz\u0171rt\u00fck a LIDAR adatb\u00f3l (ground-segmentation), \u00fat pontok (ground) \u00e9s marad\u00e9k pontok (non-ground) keletkeztek. A non-ground pontokat term\u00e9szetesen klaszterezni (cluster) kell, hogy kialakuljanak az objektumokat le\u00edr\u00f3 pontok. A klaszterez\u00e9s l\u00e9nyege, hogy egy adott objektum (pl egy aut\u00f3) pontjai egym\u00e1shoz k\u00f6zel \u00e1llnak.

Forr\u00e1s: codeahoy.com

Forr\u00e1s: saj\u00e1t

"},{"location":"eszleles/#szenzorfuzio","title":"Szenzorf\u00fazi\u00f3","text":"

A k\u00f6vetkez\u0151 vide\u00f3 egy val\u00f3 \u00e9letb\u0151l vett p\u00e9ld\u00e1n kereszt\u00fcl mutatja be az \u00e9szlel\u00e9st.

"},{"location":"eszleles/#lidar-alapu-utfelulet-padka-detekcio","title":"LIDAR-alap\u00fa \u00fatfel\u00fclet / padka detekci\u00f3","text":"

Egyetem\u00fcnk egyik saj\u00e1t fejleszt\u00e9s\u0171 algoritmusa.

"},{"location":"eszleles/#lidar-alapu-objektum-kovetes-es-predikcio","title":"LIDAR-alap\u00fa objektum k\u00f6vet\u00e9s \u00e9s predikci\u00f3","text":""},{"location":"eszleles/#slam-lidar-es-kamera-fuzio","title":"SLAM LIDAR \u00e9s kamera f\u00fazi\u00f3","text":"

A Simultaneous Localization and Mapping (SLAM) l\u00e9nyege, hogy egy mozg\u00f3 rendszer (robot vagy j\u00e1rm\u0171) poz\u00edci\u00f3j\u00e1t \u00e9s a k\u00f6rnyezet\u00e9t t\u00e9rk\u00e9pezze egyszerre, mik\u00f6zben navig\u00e1l.

"},{"location":"eszleles/#forrasok","title":"Forr\u00e1sok","text":"
  • github.com/TUMFTM/Lecture_ADSE
  • Kim and Kum (2019) \u2013 Deep Learning based Vehicle Position and Orientation Estimation via Inverse Perspective Mapping Image
  • Object Perception: LIDAR youtube APEX AI
  • Object Perception: CAMERA youtube APEX AI
  • Object Perception: Radar youtube APEX AI
"},{"location":"eszleles/ground_filter/","title":"Ground filter","text":"

El\u00e9rhet\u0151: - url-kaist/patchwork-plusplus-ros/tree/ROS2 - github.com/MohamedHussein736/patchwork-plusplus-ros/tree/ROS2 - github.com/jkk-research/patchwork-plusplus-ros az eredeti repo forkja, ami csak az ROS 2-es brenchet tartalmazza, az eredeti Urban Robotics Lab repora a SZE-JKK pull request-j\u00e9t mergelt\u00e9k.

cd ~/ros2_ws/src\n
git clone https://github.com/jkk-research/patchwork-plusplus-ros\n
cd ~/ros2_ws/src\n
colcon build --packages-select patchworkpp\n
ros2 launch patchworkpp demo.launch\n

TODO

ros2 bag play kitti_00_sample.db3\n
"},{"location":"eszleles/practice/","title":"El\u0151k\u00e9sz\u00fcletek","text":"

Kor\u00e1bbi gyakorlaton megismerkedt\u00fcnk a rosbag form\u00e1tummal (ROS 2-ben a form\u00e1tum m\u00e1r .mcap).

El\u0151k\u00e9sz\u00fcletk\u00e9nt n\u00e9zz\u00fck meg, hogy l\u00e9tezik-e a C:\\temp k\u00f6nyvt\u00e1r

test -d \"/mnt/c/temp\" && echo Letezik || echo Nem letezik\n
Vagy egyszer\u0171bben:
ls /mnt/c/temp\n

  • Ha nem l\u00e9tezik (No such file or directory), akkor hozzuk l\u00e9tre: mkdir /mnt/c/temp
  • Ha l\u00e9tezik, akkor nincs teend\u0151nk, l\u00e9pj\u00fcnk a k\u00f6vetkez\u0151 l\u00e9p\u00e9sre, m\u00e1soljuk \u00e1t ide az .mcap f\u00e1jlokat

Tanteremben a m\u00e1sol\u00e1s a k\u00f6vetkez\u0151 parancsok egyike legyen:

rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample01.mcap  /mnt/c/temp/\n
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample02.mcap  /mnt/c/temp/\n
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample03.mcap  /mnt/c/temp/\n
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3sample04.mcap  /mnt/c/temp/\n

Otthon a k\u00f6vetkez\u0151 linkr\u0151l (z\u00f6ld gomb), vagy parancsk\u00e9nt wget-el lehet let\u00f6lteni:

wget  -O lexus3sample02.mcap https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/EakTOhcjblNInqjRMfaGVmsB0diDv0SWpXw9rwo0MD7f3w?download=1\n

Rosbag let\u00f6lt\u00e9se 300 MB

"},{"location":"eszleles/practice/#1-feladat","title":"1. feladat","text":"

A feladat egyszer\u0171 LIDAR sz\u0171r\u00e9s, X, Y \u00e9s Z koordin\u00e1t\u00e1k szerint.

Ha m\u00e9g nem tett\u00fck volna, kl\u00f3nozzuk az arj_packages repot \u00e9s buildelj\u00fck az arj_simple_perception package-t.

cd ~/ros2_ws/src\n
git clone https://github.com/sze-info/arj_packages\n

Ha m\u00e1r l\u00e9tezik, akkor az el\u0151z\u0151 l\u00e9p\u00e9s helyett, csak friss\u00edts\u00fck.

cd ~/ros2_ws/src/arj_packages/\n
git status\n
git checkout -- .\n

git pull\n
A git checkout -- . az \u00f6sszes esetleges lok\u00e1lis v\u00e1ltoz\u00e1s visszavon\u00e1s\u00e1ra j\u00f3.

cd ~/ros2_ws\n
MAKEFLAGS=\"-j4\" colcon build --packages-select arj_simple_perception --cmake-args -DCMAKE_BUILD_TYPE=Release\n

Tip

A klasszikus colcon build --packages-select arj_simple_perception is m\u0171k\u00f6dik, csup\u00e1n egy kicsit lassabb, ez\u00e9rt haszn\u00e1ljuk most a build flageket.

source ~/ros2_ws/install/setup.bash\n
ros2 run arj_simple_perception lidar_filter_simple\n
ros2 bag play /mnt/c/temp/lexus3sample02.mcap --loop --clock --rate 0.5 --read-ahead-queue-size 2048\n

N\u00e9zz\u00fck meg, hogy a k\u00f6vetkez\u0151 toicok l\u00e9teznek-e? - /lexus3/os_center/points - /lidar_filter_output

ros2 topic list\n

K\u00e9rdezz\u00fck le a topicok t\u00edpus\u00e1t.

ros2 topic type /lidar_filter_output\n
ros2 topic type /lexus3/os_center/points\n

Mindk\u00e9t esetben sensor_msgs/msg/PointCloud2 kell, hogy legyen.

Vizsg\u00e1ljuk meg k\u00f6zelebbr\u0151l a node-ot.

ros2 node info /lidar_filter_simple\n
Subscribers:\n    /lexus3/os_center/points: sensor_msgs/msg/PointCloud2\n    /parameter_events: rcl_interfaces/msg/ParameterEvent\nPublishers:\n    /lidar_filter_output: sensor_msgs/msg/PointCloud2\n    /parameter_events: rcl_interfaces/msg/ParameterEvent\n    /rosout: rcl_interfaces/msg/Log\n

\u00daj terminalban vizsg\u00e1ljuk meg a gr\u00e1fot:

ros2 run rqt_graph rqt_graph\n

"},{"location":"eszleles/practice/#2-feladat","title":"2. feladat","text":"

Nyissuk meg VS code-ban a package-t:

code ~/ros2_ws/src/arj_packages/arj_simple_perception\n

Hasnol\u00edtsuk \u00f6ssze a lidar_filter_simple_param.cpp-t a lidar_filter_simple.cpp-vel. Vs code jobb kilikk a f\u00e1jlon Select for compare \u00e9s Compare with Selected.

Az el\u0151z\u0151 feladatban haszn\u00e1lt egyszer\u0171 filter minimum \u00e9s maximum X,Y,Z \u00e9rt\u00e9keit dinamikusan v\u00e1ltoztassuk.

source ~/ros2_ws/install/setup.bash\n
ros2 run arj_simple_perception lidar_filter_simple_param\n
source ~/ros2_ws/install/setup.bash\n
ros2 launch arj_simple_perception run_rviz1.launch.py\n

\u00c1ll\u00edtsuk \u00e1t a param\u00e9tereket:

ros2 run rqt_reconfigure rqt_reconfigure\n

A 3 terminal helyett haszn\u00e1lhatunk egy launch f\u00e1jlt is:

source ~/ros2_ws/install/setup.bash\n

ros2 launch arj_simple_perception run_all.launch.py\n

Nagyj\u00e1b\u00f3l \u00edgy fog kin\u00e9zni az rqt_reconfigure meg az rviz2:

"},{"location":"eszleles/practice/#onallo-feladat-1","title":"\u00d6n\u00e1ll\u00f3 feladat 1","text":"

\u00cdrjunk egy launch f\u00e1jlt, nevezz\u00fck run_fliter_and_rviz.launch.py-nak, ami a filtert \u00e9s az rviz configot ind\u00edtja. \u00cdgy lehessen ind\u00edtani:

ros2 launch arj_simple_perception run_fliter_and_rviz.launch.py\n
"},{"location":"eszleles/practice/#onallo-feladat-2","title":"\u00d6n\u00e1ll\u00f3 feladat 2","text":"

M\u00f3dos\u00edtsuk a lidar_filter_simple_param.cpp-t, \u00fagy, hogy amennyiben a minimum \u00e9rt\u00e9k nagyobb, mint a maximum, akkor is m\u0171k\u00f6dj\u00f6n. Ebben az esetben kezelje a minimum \u00e9rt\u00e9ket maximumk\u00e9nt \u00e9s ford\u00edtva.

\u00cdrjon ki egy warning \u00fczenetet.

if ...\nRCLCPP_WARN_STREAM(this->get_logger(), \"Minimum is bigger than maximum, inverse usage.\");\n
"},{"location":"eszleles/practice/#utolso-lepesek","title":"Utols\u00f3 l\u00e9p\u00e9sek","text":"

A tanteremben \u00e1ll\u00edtsuk vissza az eredeti \u00e1llapotot. (Otthon commitolhatjuk saj\u00e1t repo-ba, ha szeretn\u00e9nk.)

cd ~/ros2_ws/src/arj_packages/\n
git status\n
A git checkout -- .: Minden nem staged (unstaged) v\u00e1ltoz\u00e1s elvet\u00e9se lok\u00e1lisan. VS code-ban kb ez a \"discard all changes\" parancs lenne.
git checkout -- .\n
N\u00e9zz\u00fck \u00fajra a st\u00e1tuszt:

git status\n
git pull\n
"},{"location":"eszleles/practice_cluster/","title":"ROS 2 LIDAR klaszterez\u00e9s","text":"

A r\u00f6vid gyakorlat / workshop c\u00e9lja, hogy a LIDAR adatok objektumokk\u00e1 t\u00f6rt\u00e9n\u0151 sz\u0171r\u00e9s\u00e9t bemutassa. Teh\u00e1t az egyes LIDAR pontob\u00f3l nagyobb objektumoat / klasztereket k\u00e9sz\u00edt\u00fcnk. Ezek az objektumok lehetnek gyalogosok, aut\u00f3k, \u00e9p\u00fcletek stb. A gyakorlat ROS 2 kompatibilis.

"},{"location":"eszleles/practice_cluster/#kovetelmenyek-magas-szintu-attekintes","title":"K\u00f6vetelm\u00e9nyek (magas szint\u0171 \u00e1ttekint\u00e9s)","text":"
  1. ROS 2 Humble: \ud83d\udfe0 l\u00e1sd a kor\u00e1bbi tananyagok vagy a docs.ros.org/en/humble/Installation.html
  2. Logf\u00e1jl nyers LIDAR adatokkal (MCAP form\u00e1tum, bag) \u2705
  3. A patchworkpp csomag az alaps\u00edk kisz\u0171r\u00e9s\u00e9re \u2705
  4. A lidar_cluster csomag a klaszterez\u00e9s v\u00e9grehajt\u00e1s\u00e1hoz \u2705
"},{"location":"eszleles/practice_cluster/#video-attekintese","title":"Vide\u00f3 \u00e1ttekint\u00e9se","text":"

A k\u00f6vetkez\u0151 k\u00e9perny\u0151felv\u00e9tel bemutatja a sz\u00fcks\u00e9ges l\u00e9p\u00e9seket:

"},{"location":"eszleles/practice_cluster/#1-lepes-ha-meg-nincs-meg-korabbrol-toltsuk-le-a-nyers-adatokat","title":"1. l\u00e9p\u00e9s. - Ha m\u00e9g nincs meg kor\u00e1bbr\u00f3l, t\u00f6lts\u00fck le a nyers adatokat","text":"

A LIDAR adatok klaszterez\u00e9s\u00e9hez el\u0151sz\u00f6r \u2013 nem meglep\u0151 m\u00f3don \u2013 LIDAR adatokra van sz\u00fcks\u00e9g. Haszn\u00e1lja a k\u00f6vetkez\u0151 3 lehet\u0151s\u00e9g valamelyik\u00e9t, amennyiben m\u00e9g nincs meg az els\u0151z\u0151 gyakorlatokb\u00f3l.

"},{"location":"eszleles/practice_cluster/#a-lehetoseg-mcap-letoltese-az-alabbi-linkrol","title":"A lehet\u0151s\u00e9g: MCAP let\u00f6lt\u00e9se az al\u00e1bbi linkr\u0151l","text":"

Download MCAP [~540MB]

P\u00e9ld\u00e1inkban az .mcap f\u00e1jl a /mnt/c/bag/ mapp\u00e1ba ker\u00fcl ment\u00e9sre. Ha m\u00e1sik k\u00f6nyvt\u00e1rat szeretne haszn\u00e1lni, k\u00e9rj\u00fck, m\u00f3dos\u00edtsad azt ennek megfelel\u0151en.

"},{"location":"eszleles/practice_cluster/#b-lehetoseg-toltsuk-le-mcap-unkat-a-terminaljan-keresztul","title":"B lehet\u0151s\u00e9g: T\u00f6lts\u00fck le MCAP-unkat a termin\u00e1lj\u00e1n kereszt\u00fcl","text":"Ne felejtse el el\u0151sz\u00f6r a k\u00f6nyvt\u00e1rat m\u00f3dos\u00edtani. Eset\u00fcnkben a `/mnt/c/bag/` a hely, ahova tenni fogjuk:
cd /mnt/c/bag/\n

wget https://laesze-my.sharepoint.com/:u:/g/personal/herno_o365_sze_hu/Eclwzn42FS9GunGay5LPq-EBA6U1dZseBFNDrr6P0MwB2w?download=1  -O lexus3-2024-04-05-gyor.mcap\n
Tanteremben ez \u00edgy n\u00e9z ki:
rsync -avzh --progress /mnt/kozos/measurement_files/lexus3-2024-04-05-gyor.mcap /mnt/c/temp/\n
Windows b\u00f6ng\u00e9sz\u0151b\u0151l is meg lehet tenni, de a termin\u00e1lb\u00f3l csak egy parancs.

"},{"location":"eszleles/practice_cluster/#c-lehetoseg-sajat-mcap-hasznalata","title":"C lehet\u0151s\u00e9g: Saj\u00e1t MCAP haszn\u00e1lata","text":"

Haszn\u00e1lhatunk saj\u00e1t MCAP f\u00e1jt, de ebben az esetben a k\u00f6vetkez\u0151ket kell m\u00f3dos\u00edtani:

  • A LIDAR topic
  • P\u00e9ld\u00e1nkban ez a /lexus3/os_center/points
  • LIDAR frame
  • P\u00e9ld\u00e1nkban ez a lexus3/os_center_a_laser_data_frame

K\u00e9s\u0151bb se felejts\u00fck el friss\u00edteni ezeket a tov\u00e1bbi l\u00e9p\u00e9sekben.

"},{"location":"eszleles/practice_cluster/#ellenorizzuk-a-nyers-adatokat","title":"Ellen\u0151rizz\u00fck a nyers adatokat","text":"

J\u00e1tsszuk le a bag-et k\u00f6vetkez\u0151h\u00f6z hasonl\u00f3 paranccsal:

ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap -l\n

Info

Az -l kapcsol\u00f3 a play parancsban v\u00e9gtelen\u00edtett lej\u00e1tsz\u00e1st jelent.

Success

Ha minden a v\u00e1rt m\u00f3don m\u0171k\u00f6dik, t\u00f6bb topicot kellene l\u00e1tnunk egy m\u00e1sik termin\u00e1lon Topic-ok Egy m\u00e1sik termin\u00e1lkiad\u00e1sban a k\u00f6vetkez\u0151 parancsot adjuk ki:

ros2 topic list\n
Hasonl\u00f3 topiclist\u00e1t kellene l\u00e1tni:

/clock\n/events/read_split\n/lexus3/gps/duro/current_pose\n/lexus3/gps/duro/imu\n/lexus3/gps/duro/mag\n/lexus3/gps/duro/navsatfix\n/lexus3/gps/duro/status_flag\n/lexus3/gps/duro/status_string\n/lexus3/gps/duro/time_diff\n/lexus3/gps/duro/time_ref\n/lexus3/os_center/points\n/lexus3/os_left/points\n/lexus3/os_right/points\n/lexus3/zed2i/zed_node/left/image_rect_color/compressed\n/parameter_events\n/rosout\n/tf\n/tf_static   \n

Also there must be at least one sensor_msgs/msg/PointCloud2, check with:

 ros2 topic type /lexus3/os_center/points\n
Result:
sensor_msgs/msg/PointCloud2\n

"},{"location":"eszleles/practice_cluster/#2-lepes-ros-2-package-ek-telepitese","title":"2. l\u00e9p\u00e9s - ROS 2 package-ek telep\u00edt\u00e9se","text":"

Info

Amennyiben nincs ~/ros2_ws/ workspace, a k\u00f6vetkez\u0151 parancsara lesz sz\u00fcks\u00e9g\u00fcnk:

mkdir -p ~/ros2_ws/src\n
Ett\u0151l elt\u00e9r\u0151 workspace n\u00e9v szerint \u00e9rtelemszer\u0171en m\u00f3dos\u00edtani kell a k\u00f6vetkez\u0151 parancsokat is.

"},{"location":"eszleles/practice_cluster/#clone-patchworkpp-package","title":"Clone patchworkpp package","text":"

A patchwork-plusplus-ros a Patchwork++ (@ IROS'22) ROS 2 csomagja, amely gyors \u00e9s robusztus LIDAR talajszegment\u00e1l\u00e1st biztos\u00edt. Javasoljuk a JKK-research fork-ot, amely n\u00e9h\u00e1ny fejleszt\u00e9st tartalmaz, vagy haszn\u00e1lhatjuk az eredeti KAIST v\u00e1ltozat\u00e1t is.

cd ~/ros2_ws/src\n
git clone https://github.com/jkk-research/patchwork-plusplus-ros\n
or
git clone https://github.com/url-kaist/patchwork-plusplus-ros -b ROS2\n

"},{"location":"eszleles/practice_cluster/#clone-lidar_cluster-package","title":"Clone lidar_cluster package","text":"
cd ~/ros2_ws/src\n
git clone https://github.com/jkk-research/lidar_cluster_ros2\n
"},{"location":"eszleles/practice_cluster/#build","title":"Build","text":"
cd ~/ros2_ws\n
colcon build --packages-select patchworkpp lidar_cluster --symlink-install\n
"},{"location":"eszleles/practice_cluster/#3-lepes-futtatas","title":"3. l\u00e9p\u00e9s - Futtat\u00e1s","text":""},{"location":"eszleles/practice_cluster/#milyen-az-elvart-mukodes","title":"Milyen az elv\u00e1rt m\u0171k\u00f6d\u00e9s?","text":"
graph TD;\n\n    p1[ /lexus3/os_center/points<br/>sensor_msgs::PointCloud2]:::white --> patchwork([ /patchwork_node]):::light\n    patchwork --> p\n    p[ /nonground<br/>sensor_msgs::PointCloud2]:::white --> cluster([ /cluster_node]):::light\n    cluster --> f1[ /clustered_points<br/>sensor_msgs::PointCloud2]:::white\n    cluster --> f2[ /clustered_marker<br/>visualization_msgs::MarkerArray]:::white\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274\n    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
Ne felejts\u00fcnk el source-olni
source ~/ros2_ws/install/setup.bash\n
ros2 bag play /mnt/c/temp/lexus3-2024-04-05-gyor.mcap -l\n

ros2 launch patchworkpp demo.launch.py  cloud_topic:=/lexus3/os_center/points cloud_frame:=lexus3/os_center_a_laser_data_frame\n
Haszn\u00e1ljuk a k\u00f6vetkez\u0151 klaszterez\u00e9si algoritmusok egyik\u00e9t:

ros2 launch lidar_cluster dbscan_spatial.launch.py\n
A DBSCAN (Density-Based Spatial Clustering of Applications with Noise) egy nem-grid-alap\u00fa klaszterez\u00e9si algoritmus. Egy modern 6 magos vagy jobb CPU-n legal\u00e1bb 10 Hz-es teljes\u00edtm\u00e9nyre sz\u00e1m\u00edthatunk.

ros2 launch lidar_cluster euclidean_spatial.launch.py\n
Nem-grid klaszterez\u00e9s euklideszi t\u00e1vols\u00e1g alapj\u00e1n. Egy modern 6 magos vagy jobb CPU-n legal\u00e1bb 5 Hz-es teljes\u00edtm\u00e9nyre sz\u00e1m\u00edthatunk.

ros2 launch lidar_cluster euclidean_grid.launch.py\n
Voxel grid alap\u00fa klaszterez\u00e9s az euklideszi t\u00e1vols\u00e1g alapj\u00e1n. Egy modern 6 magos vagy jobb CPU-n legal\u00e1bb 100 Hz-es teljes\u00edtm\u00e9nyre sz\u00e1m\u00edthatunk.

ros2 launch lidar_cluster rviz02.launch.py\n

Success

Ha minden a v\u00e1rt m\u00f3don m\u0171k\u00f6dik, hasonl\u00f3 rviz ablakot kell l\u00e1tnunk.

"},{"location":"eszleles/practice_cluster/#linkek","title":"Linkek","text":"
  • English version of clutering jkk-research.github.io/workshops/clustering_a
"},{"location":"eszleles/road_filter/","title":"Road filter","text":""},{"location":"eszleles/slam/","title":"SLAM \u00e9s LOAM","text":"

Simultaneous localization and mapping (SLAM) \u00e9s LIDAR-based odometry and or mapping (LOAM).

Egy gy\u0151ri m\u00e9r\u00e9sb\u0151l \u00f6ssze\u00e1ll\u00edtott gob\u00e1lis pontfelh\u0151:

"},{"location":"eszleles/slam/#direct-lidar-inertial-odometry","title":"Direct LIDAR-Inertial Odometry","text":"

A DLIO egy k\u00f6nny\u0171s\u00faly\u00fa LIDAR-inerci\u00e1lis odometra algoritmus, amely \u00fajszer\u0171 coarse-to-fine (durva-finom) megk\u00f6zel\u00edt\u00e9ssel folytonos idej\u0171 trajekt\u00f3ri\u00e1t gener\u00e1l.

"},{"location":"eszleles/slam/#telepites","title":"Telep\u00edt\u00e9s","text":"

El\u00e9rhet\u0151:

  • github.com/vectr-ucla/direct_lidar_inertial_odometry/tree/feature/ros2 ROS 2 branch
  • github.com/jkk-research/direct_lidar_inertial_odometry csak az ROS 2 branch-et tartalmaz\u00f3 fork

N\u00e9zz\u00fck meg, hogy telep\u00edtve van-e a pcl-ros:

sudo apt install ros-humble-pcl-ros\n
cd ~/ros2_ws/src/\n
git clone https://github.com/jkk-research/direct_lidar_inertial_odometry\n
cd ~/ros2_ws/\n
colcon build --packages-select direct_lidar_inertial_odometry \n
"},{"location":"eszleles/slam/#futtatas","title":"Futtat\u00e1s","text":"
code ~/ros2_ws/src/direct_lidar_inertial_odometry/launch/dlio.launch.py\n
rviz = LaunchConfiguration('rviz', default='true')\npointcloud_topic = LaunchConfiguration('pointcloud_topic', default='/lexus3/os_center/points')\nimu_topic = LaunchConfiguration('imu_topic', default='/lexus3/os_center/imu')\n

Els\u0151 opci\u00f3: Colon-n\u00e1l vagy --symlink-install-t haszn\u00e1lunk: ekkor a f\u00e1jlok forr\u00e1sb\u00f3l val\u00f3 m\u00e1sol\u00e1sa helyett szimbolikus hivatkoz\u00e1sokat haszn\u00e1l. \u00cdgy elker\u00fclhet\u0151, hogy pl. minden egyes launch f\u00e1jl m\u00f3dos\u00edt\u00e1s eset\u00e9n \u00fajra kelljen buildelni a package-t.

cd ~/ros2_ws/ && colcon build --symlink-install --packages-select direct_lidar_inertial_odometry  \n

M\u00e1sodik opci\u00f3: \u00fajra buildel\u00fcnk minden egyes launch f\u00e1jl m\u00f3dos\u00edt\u00e1s eset\u00e9n:

cd ~/ros2_ws/ && colcon build --packages-select direct_lidar_inertial_odometry \n
"},{"location":"eszleles/slam/#kiss-icp","title":"KISS-ICP","text":"

KISS-ICP egy LIDAR odometria pipeline megold\u00e1s, amely tegt\u00f6bb esetben komolyabb param\u00e9ter \u00e1ll\u00edt\u00e1s n\u00e9l\u00fcl is j\u00f3l m\u0171k\u00f6dik.

"},{"location":"eszleles/slam/#telepites_1","title":"Telep\u00edt\u00e9s","text":"
cd ~/ros2_ws/src/\n
git clone https://github.com/PRBonn/kiss-icp\n
cd ~/ros2_ws/\n
colcon build --packages-select kiss_icp\n
"},{"location":"eszleles/slam/#futtatas_1","title":"Futtat\u00e1s","text":"
ros2 launch kiss_icp odometry.launch.py topic:=/lexus3/os_left/points\n
"},{"location":"eszleles/slam/#linkek","title":"Linkek","text":"
  • fastcampus_slam_codes oktat\u00f3anyag: github.com/changh95/fastcampus_slam_codes
  • learn opencv: learnopencv.com/lidar-slam-with-ros2
"},{"location":"feleves_beadando/","title":"Kis beadand\u00f3 \u00e9s nagy f\u00e9l\u00e9ves","text":"

A kis beadand\u00f3 c\u00e9lja, hogy a hallgat\u00f3k az \u00f3r\u00e1n megszerzett kezd\u0151 szint\u0171 elm\u00e9leti tud\u00e1s mell\u00e9 gyakorlati tapasztalatot szerezzenek ROS 2-r\u0151l \u00e9s GitHub-r\u00f3l. A kis beadand\u00f3 viszonylag kev\u00e9s id\u0151 alatt elv\u00e9gezhet\u0151: egy oktat\u00f3 p\u00e1r \u00f3ra alatt, egy \u00e1tlag hallgat\u00f3 p\u00e1r d\u00e9lut\u00e1n alatt elk\u00e9sz\u00fclhet vele. Terjedelme lehet r\u00f6vid, teh\u00e1t 30-100 k\u00f3dsor node-onk\u00e9nt.

Ezzel szemben a nagy f\u00e9l\u00e9ves egy kicsit t\u00f6bb id\u0151t vesz ig\u00e9nybe, de sokkal \u00e9rdekesebb feladatra is van lehet\u0151s\u00e9g \u00e9s id\u0151. R\u00e1ad\u00e1sul a j\u00f3 \u00e9s jeles \u00e9rdemjegyet is csak \u00edgy lehet megszerezni.

A jegyszerz\u00e9s m\u00e1sik lehet\u0151s\u00e9ge a ZH-k, erre azonban csak szer\u00e9ny \u00e9rdemjegy kaphat\u00f3.

flowchart TD\n\nK([K\u00f6telez\u0151</br>kis beadand\u00f3 ]):::light ------> |sikertelen| X0\nK --> A([Al\u00e1\u00edr\u00e1s]):::green \nA -->|ZH ir\u00e1ny| ZH1([ZH1]):::light\nA --> |f\u00e9l\u00e9ves ir\u00e1ny| N([Nagy f\u00e9l\u00e9ves]):::light\nPZH --> |sikertelen| X1\nZH2 --> |sikertelen| PZH([P\u00f3t ZH]):::light\nZH1 --> ZH2([ZH2]):::light\nZH2 --> |siker| OK1\nPZH --> |siker| OK1\nN ----> |siker| OK2\nX0([Al\u00e1\u00edr\u00e1s megtagad\u00e1s]):::red\nX1([1, el\u00e9gtelen]):::red\nOK2([4/5 \u00e9rdemjegy]):::green\nOK1([2/3 \u00e9rdemjegy]):::green\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\nclassDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"feleves_beadando/#hataridok-felev-beosztasa","title":"Hat\u00e1rid\u0151k, f\u00e9l\u00e9v beoszt\u00e1sa","text":"

Fontos, tudni, hogy a kis beadand\u00f3 al\u00e1\u00edr\u00e1s felt\u00e9tel. A GitHub regisztr\u00e1ci\u00f3, a beadand\u00f3 link bek\u00fcld\u00e9s elmulaszt\u00e1sa, m\u00e1r a szemeszter viszonlag korai szaksz\u00e1ban sikeretelen f\u00e9l\u00e9vet eredm\u00e9nyezhet. Ezek kis feladatok, megl\u00e9t\u00fcket m\u00e9gis szigor\u00faan ellen\u0151rizz\u00fck.

flowchart LR\n\nH2([2 alkalom]) --- H2A([Github<br>regisztr\u00e1ci\u00f3])--- H2B([Copilot regisztr\u00e1ci\u00f3<br>ind\u00edt\u00e1sa])\nH3([3 alkalom]) --- H3A([Beadand\u00f3 Github<br>link elk\u00fcld\u00e9se]) --- H3B([Copilot<br>regisztr\u00e1ci\u00f3 k\u00e9sz])\nH5([5 alkalom]) --- H5A([Kis beadand\u00f3<br>v\u00e9glegest\u00e9se])\nH7([7 alkalom]) --- H7A([ZH1]) --- H7B([Nagy f\u00e9l\u00e9ves Github<br>link elk\u00fcld\u00e9se])\nH10([10 alkalom]) --- H10A([ZH2])\nH13([13 alkalom]) --- H13A([P\u00f3tZH])\nV2([Vizsgaid\u0151szak 2. h\u00e9t]) --- V2A([Nagy f\u00e9l\u00e9ves<br>v\u00e9gleges\u00edt\u00e9s])\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\nclassDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff\n\nclass H2,H3,H5,H7,H10,H13,V2 white\nclass H2A,H2B,H3B,H7A,H7B,H10A,V2A light\nclass H3A,H5A,H13A, red
"},{"location":"feleves_beadando/kisbeadando/","title":"Kis beadand\u00f3","text":"

A kis beadand\u00f3 c\u00e9lja, hogy a hallgat\u00f3k az \u00f3r\u00e1n megszerzett kezd\u0151 szint\u0171 elm\u00e9leti tud\u00e1s mell\u00e9 gyakorlati tapasztalatot szerezzenek ROS 2-r\u0151l \u00e9s GitHub-r\u00f3l. A kis beadand\u00f3 viszonylag kev\u00e9s id\u0151 alatt elv\u00e9gezhet\u0151: egy oktat\u00f3 p\u00e1r \u00f3ra alatt, egy \u00e1tlag hallgat\u00f3 p\u00e1r d\u00e9lut\u00e1n alatt elk\u00e9sz\u00fclhet vele. Fontos, hogy a beadand\u00f3 al\u00e1\u00edr\u00e1s felt\u00e9tel.

Elv\u00e1rt kvalit\u00e1sok:

  • Egy package, 1 vagy 2 node
  • Minimum 1 publisher vagy 1 subscriber (t\u00f6bb lehet)
  • R\u00f6vid dokument\u00e1ci\u00f3, ami a build menet\u00e9t, a node-topic kapcsolatokat tartalmazza, a p\u00e9ld\u00e1k szerinti r\u00e9szletess\u00e9ggel
  • Helyes n\u00e9vad\u00e1s
  • Template haszn\u00e1lata vagy saj\u00e1t megold\u00e1s, de a p\u00e9ld\u00e1k szerinti kidolgozotts\u00e1gi szint
  • Lehet\u0151leg hiba n\u00e9lk\u00fcl forduljon, de a build warning sok esetben megengedhet\u0151, a l\u00e9nyeg a tanul\u00e1s
  • Min\u00e9l t\u00f6bb commit, hogy a munkafolyamatot is l\u00e1ssuk
  • Terjedelem r\u00f6vid: 30-100 k\u00f3dsor node-onk\u00e9nt + CMakeLists.txt, package.xml, README.md, launch f\u00e1jlok (nem baj, ha hosszabb, de nem elv\u00e1rt)
  • Lehet\u0151leg k\u00e9ppel illusztr\u00e1lva (l\u00e1sd p\u00e9ld\u00e1k)
  • Lehet\u0151leg mermaid diagram a node-ok, topic-ok viszony\u00e1r\u00f3l (l\u00e1sd p\u00e9ld\u00e1k, le\u00edr\u00e1s)

Danger

A kis beadand\u00f3 akkor lesz elfogadhat\u00f3, ha a node buildelhet\u0151 \u00e9s a feladatki\u00edr\u00e1snak megfelel\u0151 kimenetet adja! Amennyiben ez nem teljes\u00fcl a hallgat\u00f3nak egy hete lesz a jav\u00edt\u00e1sra az issue ki\u00edr\u00e1s\u00e1t\u00f3l sz\u00e1m\u00edtva!

"},{"location":"feleves_beadando/kisbeadando/#peldak","title":"P\u00e9ld\u00e1k","text":"

P\u00e9lda a kis beadand\u00f3ra, amit az oktat\u00f3k k\u00e9sz\u00edtettek:

  • github.com/szepilot/sze_sw1_szinusz: A package k\u00e9t node-b\u00f3l \u00e1ll. A /gen_node sz\u00ednusz jelet \u00e9s v\u00e9letlen sz\u00e1mokat genert\u00e1l, amiket k\u00e9t std_msgs/float32 topicban hirdet. A /sum_node a \u00f6sszegzi az el\u0151\u00e1llott topicokat \u00e9s egy \u00fajabb std_msgs/float32 topicban hirdeti. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • github.com/horverno/hor_d20_batman_turtle: A package egy node-b\u00f3l \u00e1ll, ez a turtlesim szimul\u00e1torban k\u00e9pes a trajekt\u00f3ra kirajzol\u00e1s\u00e1val egy \"Batman logo\" el\u0151\u00e1ll\u00edt\u00e1s\u00e1ra. A hirdetett topic geometry_msgs/twist t\u00edpus\u00fa. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • github.com/gfigneczi1/ign_b7e_array_sorter:A package egy node-b\u00f3l \u00e1ll. Ez az /array_sorter node feliratkozik egy std_msgs/msg/float32_multi_array t\u00edpus\u00fa topicra, majd hirdeti a szint\u00e9n ilyen t\u00edpus\u00fa, de n\u00f6vekv\u0151 sorrendbe rendezett verzi\u00f3j\u00e1t. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • github.com/gfigneczi1/ign_b7e_temp_sens: A package k\u00e9t node-b\u00f3l \u00e1ll. A /sensor_node szimul\u00e1lt szenzordataokat gener\u00e1l: h\u0151m\u00e9rs\u00e9kletet \u00e9s p\u00e1ratartalmat, ezeket k\u00e9t k\u00fcl\u00f6n sensor_msgs/Temperature \u00e9s sensor_msgs/RelativeHumidity t\u00edpus\u00fa topicban hirdeti. A /monitor_node ezen adatokat figyeli, \u00e9s ha a h\u0151m\u00e9rs\u00e9klet meghalad egy bizonyos k\u00fcsz\u00f6b\u00e9rt\u00e9ket vagy a p\u00e1ratartalom meghalad egy m\u00e1sikat, egy riaszt\u00e1st k\u00fcld egy std_msgs/String t\u00edpus\u00fa topicban. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • A package egy node-b\u00f3l \u00e1ll. A /minecraft_node egy visualization_msgs/Marker t\u00edpus\u00fa topicot hirdet. A topicra feliratkozva egy Minecraft karaktert jelen\u00edthet\u00fcnk meg RViz2-ben. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • github.com/umiklos/ung_isl_ajr_point_and_orientation: A package k\u00e9t node-b\u00f3l \u00e1ll. Az egyik node egy geometry_msgs/Point t\u00edpust \u00e1ll\u00edt el\u0151, a m\u00e1sik node pedig orient\u00e1ci\u00f3val kieg\u00e9sz\u00edtve ebb\u0151l egy geometry_msgs/Pose t\u00edpus\u00fat hirdet. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • github.com/umiklos/ung_isl_ajr_data_generation_and_control: A package k\u00e9t node-b\u00f3l \u00e1ll. Az /sensor_data_generator egy fikt\u00edv szenzorral szimul\u00e1lt adatokat gener\u00e1l, p\u00e9ld\u00e1ul t\u00e1vols\u00e1got \u00e9s sebess\u00e9get, ezeket k\u00e9t k\u00fcl\u00f6n sensor_msgs/Range \u00e9s geometry_msgs/Twist t\u00edpus\u00fa topicban hirdeti. A m\u00e1sik node, a /control_node ezeket az adatokat figyeli \u00e9s vez\u00e9rl\u00e9si d\u00f6nt\u00e9seket hoz a robot sz\u00e1m\u00e1ra, amit ki\u00edr a terminalban. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.
  • A package k\u00e9t node-b\u00f3l \u00e1ll. Az /imu_data_publisher gyorsul\u00e1sm\u00e9r\u0151 \u00e9s giroszk\u00f3p szenzor adatokat szolg\u00e1ltat, ezeket egy sensor_msgs/Imu t\u00edpus\u00fa topicban hirdeti. A m\u00e1sik node, a /imu_data_analyzer ezeket az IMU adatokat elemzi \u00e9s jelent\u00e9seket k\u00e9sz\u00edt a robot \u00e1llapot\u00e1r\u00f3l egy diagnostic_msgs/DiagnosticArray t\u00edpus\u00fa topicban. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.

\u00c9rdemes, de nem k\u00f6telez\u0151 a diagnostic_msgs, geometry_msgs, nav_msgs, sensor_msgs, shape_msgs, std_msgs, trajectory_msgs, visualization_msgs k\u00f6z\u00fcl v\u00e1lasztani.

"},{"location":"feleves_beadando/kisbeadando/#ajanlott-modszer-a-kis-beadando-repo-letrhozasara-template","title":"Aj\u00e1nlott m\u00f3dszer a kis beadand\u00f3 repo l\u00e9trhoz\u00e1s\u00e1ra: template","text":"

C++ \u00e9s Python nyelven is l\u00e9trehoztunk egy \u00fagynevezett template repo-t, amely megk\u00f6nny\u00edti az els\u0151 pacakage-t tartalmaz\u00f3 repository l\u00e9trehoz\u00e1s\u00e1t:

  • github.com/sze-info/ros2_cpp_template
  • github.com/sze-info/ros2_py_template

Tip

Err\u0151l le\u00edr\u00e1s itt olvashat\u00f3.

"},{"location":"feleves_beadando/kisbeadando/#repo-neve","title":"Repo neve","text":"
  • A repository neve a k\u00f6vetkez\u0151 mint\u00e1t k\u00f6vesse: VVV_NNN_opcionalis, ahol
  • a VVV a vezet\u00e9kn\u00e9v els\u0151 3 karaktere, kisbet\u0171vel
  • az NNN a neptunk\u00f3d els\u0151 3 karaktere, kisbet\u0171vel
  • az opcionalis pedig opcion\u00e1lis kieg\u00e9sz\u00edt\u00e9s, kisbet\u0171vel
  • a fentieket alulvon\u00e1s _ karakter v\u00e1lassza el \u00e9s kisbet\u0171 legyen mindenhol
  • Pl: Szab\u00f3 Istv\u00e1n, F99AXW neptunk\u00f3ddal egy v\u00e9letlensz\u00e1mmal foglakoz\u00f3 kis beadand\u00f3j\u00e1nak url-je lehet pl: github.com/szaboistvan/sza_f99_random.
"},{"location":"feleves_beadando/nagyfeleves/","title":"Nagy f\u00e9l\u00e9ves","text":"

A nagy f\u00e9l\u00e9ves projekt elk\u00e9sz\u00edt\u00e9se t\u00f6bb id\u0151t ig\u00e9nyel, azonban lehet\u0151s\u00e9g van sokkal \u00e9rdekesebb feladatokat kidolgozni, r\u00e1ad\u00e1sul j\u00f3val t\u00f6bb h\u00e9t alatt. A f\u00e9l\u00e9vesre alapozva, a t\u00e1rgy teljes\u00edt\u00e9se ut\u00e1n ak\u00e1r diplomamunka, szakdolgozat, projektmunka, TDK dolgozat is k\u00e9sz\u00edthet\u0151, illetve van lehet\u0151s\u00e9g a k\u00f6telez\u0151 szakmai gyakorlat teljes\u00edt\u00e9s\u00e9re is.

"},{"location":"feleves_beadando/nagyfeleves/#peldak","title":"P\u00e9ld\u00e1k","text":"

P\u00e9lda a nagy f\u00e9l\u00e9vesre, amit az oktat\u00f3k k\u00e9sz\u00edtettek:

  • github.com/horverno/simple_random_trees: A package egy egyszer\u0171 \u00fatvonaltervez\u00e9sre haszn\u00e1lhat\u00f3 v\u00e9letlenszer\u0171 fa algoritmus. Ez a megval\u00f3s\u00edt\u00e1sa a vizualiz\u00e1ci\u00f3ra \u00f6sszpontos\u00edt, nem pedig egy \u00e1tfog\u00f3 v\u00e9letlenszer\u0171 fa-alap\u00fa \u00fatvonal tervez\u0151 rendszer. A /display_tree node egy /path_marker_topic-ot hirdet, ami visualization_msgs/marker_array t\u00edpus\u00fa. A faadatstruk\u00far\u00e1t megval\u00f3s\u00edt\u00f3 f\u00fcggv\u00e9nyek k\u00fcl\u00f6n header f\u00e1jlban kaptak helyet. Megval\u00f3s\u00edt\u00e1s ROS 2 Humble alatt.

Az al\u00e1bbi p\u00e9ld\u00e1k nem felt\u00e9tlen\u00fcl f\u00e9l\u00e9ves munk\u00e1nak k\u00e9sz\u00fcltek, de annak elfogadhat\u00f3ak lenn\u00e9nek:

  • github.com/jkk-research/wayp_plan_tools
  • github.com/jkk-research/sim_wayp_plan_tools
  • github.com/jkk-research/pointcloud_to_grid
  • github.com/jkk-research/urban_road_filter
  • github.com/dobaybalazs/curb_detection
  • github.com/kkira07/Szakdolgozat
  • github.com/szenergy/rviz_markers
  • github.com/linklab-uva/f1tenth_gtc_tutorial
  • github.com/Farraj007/Jkk-task
  • github.com/leander-dsouza/breakout_gazebo
  • github.com/fjp/ros-turtle-pong

Megjegyz\u00e9s: a t\u00e1rgyban az ROS 2 Humble verzi\u00f3t haszn\u00e1ljuk, de a f\u00e9l\u00e9ves beadand\u00f3t (indokl\u00e1ssal) m\u00e1s verzi\u00f3ban is elfogadjuk.

"},{"location":"feleves_beadando/nagyfeleves/#a-feleves-feladatnal-pozitiv-hatast-kelt","title":"A f\u00e9l\u00e9ves feladatn\u00e1l pozit\u00edv hat\u00e1st kelt:","text":"
  • \ud83d\udc4d J\u00f3l k\u00f6vethet\u0151 magyar \u00e9s/vagy angol nyelv\u0171 dokument\u00e1ci\u00f3 is, k\u00e9pekkel illusztr\u00e1lva. Markdown haszn\u00e1lata.
  • \ud83d\udc4d Alap inform\u00e1ci\u00f3k a README.md-ben, (opcion\u00e1lis) dokument\u00e1ci\u00f3 a /wiki-ben.
  • \ud83d\udc4d Issue-k.
  • \ud83d\udc4d Branch-ek.
  • \ud83d\udc4d Gitignore.
  • \ud83d\udc4d Licensz.
  • \ud83d\udc4d Repository topic-ok, k\u00f6zt\u00fck a t\u00e1rgyk\u00f3d \u00e9s a SZE. A topic-ok alapj\u00e1n azt\u00e1n pl itt is list\u00e1z\u00f3dik a repository: github.com/topics/sze.
  • \ud83d\udc4d Plusz jegy adhat\u00f3, amennyiben a jelen tananyag kieg\u00e9sz\u00edt\u00e9sre / hibajav\u00edt\u00e1sra ker\u00fcl (tem\u00e9szetesen pull request \u00e1ltal).
"},{"location":"feleves_beadando/nagyfeleves/#komoly-hibak-ami-miatt-a-feleves-akar-tobb-erdemjeggyel-is-rosszabb-lehet","title":"Komoly hib\u00e1k, ami miatt a f\u00e9l\u00e9ves ak\u00e1r t\u00f6bb \u00e9rdemjeggyel is rosszabb lehet:","text":"
  • \ud83d\ude21 T\u00f6m\u00f6r\u00edtett \u00e1llom\u00e1ny a GitHub repositoryban (pl. zip \u00e9s m\u00e9g rosszabb, ha rar). Kiv\u00e9tel lehet, ha direkt t\u00f6m\u00f6r\u00edtett \u00e1llom\u00e1nykezel\u00e9s a c\u00e9l, de forr\u00e1sk\u00f3d, k\u00e9p, stb. soha ne ker\u00fclj\u00f6n \u00edgy fel.
  • \ud83d\ude21 Nem eredeti munka, vagy az \u00e1tvett k\u00f3d nincs hivatkozva.
  • \ud83d\ude21 Csapatban csak egy hallgat\u00f3 commitol. (Ez nyilv\u00e1n nem vonatkozis egyf\u0151s feladatokra).
  • \ud83d\ude21 Kev\u00e9s commit. Az\u00e9rt lenne fontos a megfelel\u0151 sz\u00e1m\u00fa commit, mert ebb\u0151l tudjuk, meg\u00edt\u00e9lni, hogyan haladt el\u0151re a munkafolyamat, ki, mit \u00e9s mikor dolgozott.
  • \ud83d\ude21 Nincs README.md, hi\u00e1nyzik a r\u00f6vid dokument\u00e1ci\u00f3 vagy a k\u00e9pek.
  • \ud83d\ude21 A dokument\u00e1ci\u00f3 pdf / docx-k\u00e9nt felt\u00f6ltve a /wiki helyett.
  • \ud83d\ude21 File upload commit helyett.
  • \ud83d\ude21 Forr\u00e1sk\u00f3d kik\u00e9pmetsz\u0151zve markdown szintaxis kiemel\u00e9s helyett. (Mivel k\u00e9pk\u00e9nt nem m\u00e1solhat\u00f3, kereshet\u0151, stb a k\u00f3d.)
"},{"location":"feleves_beadando/nagyfeleves/#otletek-temavalasztashoz","title":"\u00d6tletek t\u00e9mav\u00e1laszt\u00e1shoz","text":"
  • Insprir\u00e1ci\u00f3 lehet a kor\u00e1bbi vagy jelenlegi szakdolgozatok / diplomamunk\u00e1k t\u00e9m\u00e1i: horverno.github.io/temaajanlatok
  • Olyan t\u00e9m\u00e1t c\u00e9lszer\u0171 v\u00e1lasztani, amin sz\u00edvesen dolgozn\u00e1l heteken/h\u00f3napokon kereszt\u00fcl is. Ha pl. a vizualiz\u00e1ci\u00f3, az algoritmusok gyakorlata, a 3D vagy \u00e9pp a mesters\u00e9ges intelligencia vonz\u00f3, akkor ennek megfelel\u0151 t\u00e9m\u00e1t c\u00e9lszer\u0171 v\u00e1lasztani.
  • Kor\u00e1bbi szakdolgozatok, f\u00e9l\u00e9vesek el\u00e9rhet\u0151ek, ezeket ig\u00e9nyelni itt lehet. Fontos, hogy ezeket tilos tov\u00e1bbosztani, csak oktat\u00e1si c\u00e9llal \u00e1llnak rendelkez\u00e9sre.
  • Sz\u00e1mos ROS 2 projekt itt: github.com/fkromer/awesome-ros2

Tip

Er\u0151sen aj\u00e1nlott a GitHub Student Developer Pack beszerz\u00e9se, t\u00f6bbek k\u00f6z\u00f6tt Copilot is j\u00e1r hozz\u00e1. Err\u0151l itt lehet r\u00e9szletesen olvasni: sze-info.github.io/ajr/bevezetes/copilot/#github-copilot-beszerzese-sze-hallgatoknak

"},{"location":"feleves_beadando/nagyfeleves/#ertekelesi-szempontok","title":"\u00c9rt\u00e9kel\u00e9si szempontok","text":"

A szempontok kialak\u00edt\u00e1s\u00e1na\u00e1l az \u00d3budai Egyetem hasonl\u00f3 kurzus\u00e1nak \u00e9rt\u00e9kel\u00e9si szempontjait vett\u00fck alapul. - Saj\u00e1t munka \u00e9s fehaszn\u00e1lt k\u00f3db\u00e1zis ar\u00e1nya (megfelel\u0151 hivatkoz\u00e1sok megl\u00e9te) - \u00c9rt\u00e9kelhet\u0151 eredm\u00e9nyeket produk\u00e1l\u00f3 munka - A bemutat\u00f3 min\u0151s\u00e9ge (ppt, vide\u00f3k, \u00e9l\u0151 demo, b\u00e1rmilyen plusz felhaszn\u00e1lt eszk\u00f6z) - A megold\u00e1s teljess\u00e9ge - Megfelel\u0151 ROS 2 kommunik\u00e1ci\u00f3 / best practice alkalmaz\u00e1sa - A program szerkezete - Az implement\u00e1ci\u00f3 min\u0151s\u00e9ge - A k\u00f3d dokument\u00e1l\u00e1sa - Konzult\u00e1ci\u00f3 - A v\u00e1lasztott feladat neh\u00e9zs\u00e9ge

"},{"location":"feleves_beadando/nagyfeleves/#ajanlott-modszer-a-feleves-repo-letrhozasara-template","title":"Aj\u00e1nlott m\u00f3dszer a f\u00e9l\u00e9ves repo l\u00e9trhoz\u00e1s\u00e1ra: template","text":"

C++ \u00e9s Python nyelven is l\u00e9trehoztunk egy \u00fagynevezett template repo-t, amely megk\u00f6nny\u00edti az els\u0151 pacakage-t tartalmaz\u00f3 repository l\u00e9trehoz\u00e1s\u00e1t:

  • github.com/sze-info/ros2_cpp_template
  • github.com/sze-info/ros2_py_template

Info

Err\u0151l le\u00edr\u00e1s itt olvashat\u00f3.

"},{"location":"feleves_beadando/nagyfeleves/#meme","title":"Meme","text":"

Credit: pycoders

Credit: knowyourmeme

"},{"location":"kalman_filter/","title":"K\u00e1lm\u00e1n filter","text":"

K\u00e1lm\u00e1n Rudolf Emil (Budapest, 1930. m\u00e1jus 19. \u2013 Gainesville, 2016. j\u00falius 2.) amerikai magyar villamosm\u00e9rn\u00f6k, matematikus, a m\u0171szaki tudom\u00e1nyok doktora, a Magyar Tudom\u00e1nyos Akad\u00e9mia tiszteleti tagja. Munk\u00e1ss\u00e1ga a matematikai elj\u00e1r\u00e1sok folyamatir\u00e1ny\u00edt\u00e1si \u00e9s szab\u00e1lyoz\u00e1selm\u00e9leti alkalmaz\u00e1s\u00e1ban, az oper\u00e1ci\u00f3kutat\u00e1sban jelent\u0151s, t\u00f6bbek k\u00f6z\u00f6tt a nev\u00e9hez f\u0171z\u0151dik a K\u00e1lm\u00e1n-sz\u0171r\u0151 elv\u00e9nek kidolgoz\u00e1sa.

Newton's Equations of Motion

\\[ x = x_0 + v_{x0} * t + \\frac{1}{2}a_x * t^2 \\] \\[ y = y_0 + v_{y0} * t + \\frac{1}{2}a_y * t^2 \\]

State Transition (no control input)

\\[x_{k+1} = \\begin{bmatrix}1 & 0 & \\Delta t & 0 & \\frac{1}{2}\\Delta t^2 & 0 \\\\ 0 & 1 & 0 & \\Delta t & 0 & \\frac{1}{2}\\Delta t^2 \\\\ 0 & 0 & 1 & 0 & \\Delta t & 0 \\\\ 0 & 0 & 0 & 1 & 0 & \\Delta t \\\\ 0 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & 0 & 0 & 1\\end{bmatrix} \\cdot \\begin{bmatrix} x \\\\ y \\\\ \\dot x \\\\ \\dot y \\\\ \\ddot x \\\\ \\ddot y\\end{bmatrix}_{k}\\] \\[y = H \\cdot x\\]

Acceleration (IMU) and position (GNSS) (x\u02d9\u02d9, y\u02d9\u02d9, x, y) sensors are used.

\\[y = \\begin{bmatrix}0 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & 0 & 0 & 1 \\\\ 1 & 0 & 0 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 & 0 & 0 \\end{bmatrix} \\cdot x\\]"},{"location":"kalman_filter/practice/","title":"Gyakorlat","text":"

GitHub link

"},{"location":"kalman_filter/practice/#import","title":"Import","text":"
import numpy as np\nimport matplotlib.pyplot as plt\nfrom scipy.stats import norm\n%matplotlib inline\nplt.rcParams[\"figure.figsize\"] = [16, 9]\nplt.rc(\"xtick\", labelsize=20)\nplt.rc(\"ytick\", labelsize=20)\n
"},{"location":"kalman_filter/practice/#kalman-filter-for-constant-acceleration-model","title":"Kalman Filter for Constant Acceleration Model","text":""},{"location":"kalman_filter/practice/#state-vector-constant-acceleration","title":"State Vector - Constant Acceleration","text":"

Constant Acceleration Model for Ego Motion in Plane

\\[x_{k+1} = A \\cdot x_{k} + B \\cdot u\\]"},{"location":"kalman_filter/practice/#newtons-equations-of-motion","title":"Newton's Equations of Motion","text":"

$$ x = x_0 + v_{x0} * t + \\frac{1}{2}a_x * t^2 $$

\\[ y = y_0 + v_{y0} * t + \\frac{1}{2}a_y * t^2 \\]"},{"location":"kalman_filter/practice/#state-transition-no-control-input","title":"State Transition (no control input)","text":"\\[x_{k+1} = \\begin{bmatrix}1 & 0 & \\Delta t & 0 & \\frac{1}{2}\\Delta t^2 & 0 \\\\ 0 & 1 & 0 & \\Delta t & 0 & \\frac{1}{2}\\Delta t^2 \\\\ 0 & 0 & 1 & 0 & \\Delta t & 0 \\\\ 0 & 0 & 0 & 1 & 0 & \\Delta t \\\\ 0 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & 0 & 0 & 1\\end{bmatrix} \\cdot \\begin{bmatrix} x \\\\ y \\\\ \\dot x \\\\ \\dot y \\\\ \\ddot x \\\\ \\ddot y\\end{bmatrix}_{k}\\] \\[y = H \\cdot x\\]

Acceleration (IMU) and position (GNSS) (\\(\\ddot x\\), \\(\\ddot y\\), \\(x\\), \\(y\\)) sensors are used.

\\[y = \\begin{bmatrix}0 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & 0 & 0 & 1 \\\\ 1 & 0 & 0 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 & 0 & 0 \\end{bmatrix} \\cdot x\\]"},{"location":"kalman_filter/practice/#initial-state","title":"Initial State","text":"
plt.figure(figsize=(18, 10))\nx = np.matrix([[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]).T\nn = x.size  # States\nplt.scatter(float(x[0]), float(x[1]), s=100)\nplt.title(\"Initial Location\", fontsize=20)\nplt.ylabel(\"y in m\", fontsize=20)\nplt.xlabel(\"x in m\", fontsize=20)\nplt.grid(True)\n#### Initial Uncertainty\nP = np.matrix(\n    [\n        [10.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n        [0.0, 10.0, 0.0, 0.0, 0.0, 0.0],\n        [0.0, 0.0, 10.0, 0.0, 0.0, 0.0],\n        [0.0, 0.0, 0.0, 10.0, 0.0, 0.0],\n        [0.0, 0.0, 0.0, 0.0, 10.0, 0.0],\n        [0.0, 0.0, 0.0, 0.0, 0.0, 10.0],\n    ]\n)\nprint(P)\n\nfig = plt.figure(figsize=(6, 6))\nim = plt.imshow(P, interpolation=\"none\", cmap=plt.get_cmap(\"binary\"))\nplt.title(\"Initial Covariance Matrix $P$\")\nylocs, ylabels = plt.yticks()\n# set the locations of the yticks\nplt.yticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.yticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nxlocs, xlabels = plt.xticks()\n# set the locations of the yticks\nplt.xticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.xticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nplt.xlim([-0.5, 5.5])\nplt.ylim([5.5, -0.5])\n\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\n\ndivider = make_axes_locatable(plt.gca())\ncax = divider.append_axes(\"right\", \"5%\", pad=\"3%\")\nplt.colorbar(im, cax=cax)\n\nplt.tight_layout()\n
"},{"location":"kalman_filter/practice/#dynamic-matrix","title":"Dynamic Matrix","text":"

It is calculated from the dynamics of the Egomotion.

\\(\\(x_{k+1} = x_{k} + \\dot x_{k} \\cdot \\Delta t + \\ddot x_k \\cdot \\frac{1}{2}\\Delta t^2\\)\\)

\\[y_{k+1} = y_{k} + \\dot y_{k} \\cdot \\Delta t + \\ddot y_k \\cdot \\frac{1}{2}\\Delta t^2\\]

\\(\\(\\dot x_{k+1} = \\dot x_{k} + \\ddot x \\cdot \\Delta t\\)\\)

\\[\\dot y_{k+1} = \\dot y_{k} + \\ddot y \\cdot \\Delta t\\]

\\(\\(\\ddot x_{k+1} = \\ddot x_{k}\\)\\)

\\[\\ddot y_{k+1} = \\ddot y_{k}\\]
dt = 0.1  # Time Step between Filter Steps\n\nA = np.matrix(\n    [\n        [1.0, 0.0, dt, 0.0, 1 / 2.0 * dt ** 2, 0.0],\n        [0.0, 1.0, 0.0, dt, 0.0, 1 / 2.0 * dt ** 2],\n        [0.0, 0.0, 1.0, 0.0, dt, 0.0],\n        [0.0, 0.0, 0.0, 1.0, 0.0, dt],\n        [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],\n        [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n    ]\n)\nprint(A)\n## Measurement Matrix\nThis matrix determines how the sensor measurements map to the vehicle state. In this example, the position and the accelerations are measured ($x$, $y$, $\\ddot x$, $\\ddot y$).\nH = np.matrix(\n    [\n        [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],\n        [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],\n        [1.0, 0.0, 0.0, 0.0, 0.0, 0.0],\n        [0.0, 1.0, 0.0, 0.0, 0.0, 0.0],\n    ]\n)\nprint(H)\n## Measurement Noise Covariance\nra = 10.0 ** 2\nrp = 2.0 ** 2\n\nR = np.matrix(\n    [[ra, 0.0, 0.0, 0.0], [0.0, ra, 0.0, 0.0], [0.0, 0.0, rp, 0.0], [0.0, 0.0, 0.0, rp]]\n)\nprint(R)\n
"},{"location":"kalman_filter/practice/#process-noise-covariance-matrix-q-for-ca-model","title":"Process Noise Covariance Matrix Q for CA Model","text":"

The Position of an object can be influenced by a force (e.g. wind), which leads to an acceleration disturbance (noise). This process noise has to be modeled with the process noise covariance matrix Q.

\\[Q = \\begin{bmatrix} \\sigma_{x}^2 & 0 & \\sigma_{x \\dot x} & 0 & \\sigma_{x \\ddot x} & 0 \\\\ 0 & \\sigma_{y}^2 & 0 & \\sigma_{y \\dot y} & 0 & \\sigma_{y \\ddot y} \\\\ \\sigma_{\\dot x x} & 0 & \\sigma_{\\dot x}^2 & 0 & \\sigma_{\\dot x \\ddot x} & 0 \\\\ 0 & \\sigma_{\\dot y y} & 0 & \\sigma_{\\dot y}^2 & 0 & \\sigma_{\\dot y \\ddot y} \\\\ \\sigma_{\\ddot x x} & 0 & \\sigma_{\\ddot x \\dot x} & 0 & \\sigma_{\\ddot x}^2 & 0 \\\\ 0 & \\sigma_{\\ddot y y} & 0 & \\sigma_{\\ddot y \\dot y} & 0 & \\sigma_{\\ddot y}^2 \\end{bmatrix} \\cdot \\sigma_{j}\\]"},{"location":"kalman_filter/practice/#symbolic-calculation","title":"Symbolic Calculation","text":"
from sympy import Symbol, Matrix\nfrom sympy.interactive import printing\n\ndts = Symbol(\"\\Delta t\")\nsj = 0.1\n\nQ = (\n    np.matrix(\n        [\n            [(dt ** 6) / 36, 0, (dt ** 5) / 12, 0, (dt ** 4) / 6, 0],\n            [0, (dt ** 6) / 36, 0, (dt ** 5) / 12, 0, (dt ** 4) / 6],\n            [(dt ** 5) / 12, 0, (dt ** 4) / 4, 0, (dt ** 3) / 2, 0],\n            [0, (dt ** 5) / 12, 0, (dt ** 4) / 4, 0, (dt ** 3) / 2],\n            [(dt ** 4) / 6, 0, (dt ** 3) / 2, 0, (dt ** 2), 0],\n            [0, (dt ** 4) / 6, 0, (dt ** 3) / 2, 0, (dt ** 2)],\n        ]\n    )\n    * sj ** 2\n)\n\nprint(Q)\nfig = plt.figure(figsize=(6, 6))\nim = plt.imshow(Q, interpolation=\"none\", cmap=plt.get_cmap(\"binary\"))\nplt.title(\"Process Noise Covariance Matrix $Q$\")\nylocs, ylabels = plt.yticks()\n# set the locations of the yticks\nplt.yticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.yticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nxlocs, xlabels = plt.xticks()\n# set the locations of the yticks\nplt.xticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.xticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nplt.xlim([-0.5, 5.5])\nplt.ylim([5.5, -0.5])\n\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\n\ndivider = make_axes_locatable(plt.gca())\ncax = divider.append_axes(\"right\", \"5%\", pad=\"3%\")\nplt.colorbar(im, cax=cax)\n\nplt.tight_layout()\n## Identity Matrix\nI = np.eye(n)\n## Measurement\nimport pandas as pd\nfrom pyproj import Proj\n\n# Read data\n\n# Use every 5th value to get GPS updates in every timestep\nn_rows = 10800  # len(df)\nskip = np.arange(n_rows)\nskip = np.delete(skip, np.arange(0, n_rows, 5))\ndf = pd.read_csv(\"data/2014-03-26-000-Data.csv\", skiprows=skip)\n\n# Extract values\nax = df[\"ax\"].dropna()\nay = df[\"ay\"].dropna()\npx = df[\"latitude\"].dropna()\npy = df[\"longitude\"].dropna()\n\nm = len(df[\"ax\"])  # Measurements\n\n# Lat Lon to UTM\nutm_converter = Proj(\n    \"+proj=utm +zone=33U, +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs\"\n)\n\nfor i in range(len(px)):\n    py[i], px[i] = utm_converter(py[i], px[i])\n    px[i] = px[i] + np.random.normal(0, 2.0, 1)\n    py[i] = py[i] + np.random.normal(0, 2.0, 1)\n    # px[i] = 0 #TODO\n    # py[i] = 0 #TODO\n\n# Start from position (0 ,0)\npy_offset = py[0]\npx_offset = px[0]\npx = px - px_offset\npy = py - py_offset\n\n# Stack measurement vector\nmeasurements = np.vstack((ax, ay, px, py))\nfig = plt.figure(figsize=(16, 9))\nplt.step(range(m), ax, label=\"$a_x$\")\nplt.step(range(m), ay, label=\"$a_y$\")\nplt.ylabel(\"Acceleration in m / $s^2$\", fontsize=20)\nplt.xlabel(\"Number of measurements\", fontsize=20)\nplt.title(\"IMU Measurements\", fontsize=20)\nplt.ylim([-20, 20])\nplt.legend(loc=\"best\", prop={\"size\": 18})\nfig = plt.figure(figsize=(16, 9))\nplt.step(px, py, label=\"$GNSS$\")\nplt.xlabel(\"x in m\", fontsize=20)\nplt.ylabel(\"y in m\", fontsize=20)\nplt.title(\"GNSS Measurements\", fontsize=20)\nplt.xlim([min(px), max(px)])\nplt.ylim([min(py), max(py)])\nplt.legend(loc=\"best\", prop={\"size\": 18})\n# Preallocation for Plotting\nxt = []\nyt = []\ndxt = []\ndyt = []\nddxt = []\nddyt = []\nZx = []\nZy = []\nPx = []\nPy = []\nPdx = []\nPdy = []\nPddx = []\nPddy = []\nKx = []\nKy = []\nKdx = []\nKdy = []\nKddx = []\nKddy = []\n
"},{"location":"kalman_filter/practice/#kalman-filter","title":"Kalman Filter","text":"

for n in range(m):\n\n    # Time Update (Prediction)\n    # ========================\n    # Project the state ahead\n    x = A * x\n\n    # Project the error covariance ahead\n    P = A * P * A.T + Q\n\n    # Measurement Update (Correction)\n    # ===============================\n    # Compute the Kalman Gain\n    S = H * P * H.T + R\n    K = (P * H.T) * np.linalg.pinv(S)\n\n    # Update the estimate via z\n    Z = measurements[:, n].reshape(H.shape[0], 1)\n    y = Z - (H * x)  # Innovation or Residual\n    x = x + (K * y)\n\n    # Update the error covariance\n    P = (I - (K * H)) * P\n\n    # Save states for Plotting\n    xt.append(float(x[0]))\n    yt.append(float(x[1]))\n    dxt.append(float(x[2]))\n    dyt.append(float(x[3]))\n    ddxt.append(float(x[4]))\n    ddyt.append(float(x[5]))\n    Zx.append(float(Z[0]))\n    Zy.append(float(Z[1]))\n    Px.append(float(P[0, 0]))\n    Py.append(float(P[1, 1]))\n    Pdx.append(float(P[2, 2]))\n    Pdy.append(float(P[3, 3]))\n    Pddx.append(float(P[4, 4]))\n    Pddy.append(float(P[5, 5]))\n    Kx.append(float(K[0, 0]))\n    Ky.append(float(K[1, 0]))\n    Kdx.append(float(K[2, 0]))\n    Kdy.append(float(K[3, 0]))\n    Kddx.append(float(K[4, 0]))\n    Kddy.append(float(K[5, 0]))\n## Plots\n### Covariance Matrix\nfig = plt.figure(figsize=(6, 6))\nim = plt.imshow(P, interpolation=\"none\", cmap=plt.get_cmap(\"binary\"))\nplt.title(\"Covariance Matrix $P$ (after %i Filter Steps)\" % (m), fontsize=20)\nylocs, ylabels = plt.yticks()\n# set the locations of the yticks\nplt.yticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.yticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nxlocs, xlabels = plt.xticks()\n# set the locations of the yticks\nplt.xticks(np.arange(7))\n# set the locations and labels of the yticks\nplt.xticks(\n    np.arange(6),\n    (\"$x$\", \"$y$\", \"$\\dot x$\", \"$\\dot y$\", \"$\\ddot x$\", \"$\\ddot y$\"),\n    fontsize=22,\n)\n\nplt.xlim([-0.5, 5.5])\nplt.ylim([5.5, -0.5])\n\nfrom mpl_toolkits.axes_grid1 import make_axes_locatable\n\ndivider = make_axes_locatable(plt.gca())\ncax = divider.append_axes(\"right\", \"5%\", pad=\"3%\")\nplt.colorbar(im, cax=cax)\n\n\nplt.tight_layout()\n## State Vector\nfig = plt.figure(figsize=(16, 12))\n\nplt.subplot(311)\nplt.step(range(len(measurements[0])), ddxt, label=\"$\\ddot x$\")\nplt.step(range(len(measurements[0])), ddyt, label=\"$\\ddot y$\")\n\nplt.title(\"Estimate (Elements from State Vector $x$)\", fontsize=20)\nplt.legend(loc=\"best\", prop={\"size\": 22})\nplt.ylabel(\"Acceleration in m/ $s^2$\", fontsize=20)\n\nplt.subplot(312)\nplt.step(range(len(measurements[0])), dxt, label=\"$\\dot x$\")\nplt.step(range(len(measurements[0])), dyt, label=\"$\\dot y$\")\n\nplt.ylabel(\"\")\nplt.legend(loc=\"best\", prop={\"size\": 22})\nplt.ylabel(\"Velocity in m/s\", fontsize=20)\n\nplt.subplot(313)\nplt.step(range(len(measurements[0])), xt, label=\"$x$\")\nplt.step(range(len(measurements[0])), yt, label=\"$y$\")\n\nplt.xlabel(\"Filter Step\", fontsize=20)\nplt.ylabel(\"Position in m\", fontsize=20)\nplt.legend(loc=\"best\", prop={\"size\": 22})\n## Position x/y\nfig = plt.figure(figsize=(16, 9))\n\nplt.step(px, py, label=\"$GNSS$\")\n\nplt.scatter(xt[0], yt[0], s=100, label=\"Start\", c=\"g\")\nplt.scatter(xt[-1], yt[-1], s=100, label=\"Goal\", c=\"r\")\nplt.plot(xt, yt, label=\"State\", alpha=0.5)\nplt.xlabel(\"x in m\", fontsize=20)\nplt.ylabel(\"y in m\", fontsize=20)\nplt.title(\"Position\", fontsize=20)\nplt.legend(loc=\"best\", fontsize=20)\nplt.xlim(min(xt), max(xt))\nplt.ylim(min(yt), max(yt))\n

"},{"location":"linkek/","title":"Linkek","text":""},{"location":"linkek/#linux-ismeretek","title":"Linux ismeretek","text":"
  • Egyszer\u0171 linux parancsok - [hun]
  • ROS training - 0.1 Intro to Ubuntu GUI - [eng]
  • ROS training - 0.2 The Linux File System - [eng]
  • ROS training - 0.3 Using the Terminal - [eng]
  • Terminal kezel\u00e9se - [hun]
  • 60 Linux Commands you need to know [video, eng]
  • The 50 Most Popular Linux & Terminal Commands, freeCodeCamp [video, eng]
  • Raspberry Pi-hez k\u00e9sz\u00fclt seg\u00e9danyag: [hun]
  • Git kezel\u00e9se:
  • Beadand\u00f3 le\u00edr\u00e1s, Git \u00e9s GitHub - [hun]
  • GitHub first-contributions magyar ford\u00edt\u00e1s - [hun]
  • GitHub Learning Lab - [eng]
  • VS code - [hun], [vid]
  • Python [hun]
  • Python freeCodeCamp video [eng]
  • Python 60 days with python videos [eng]
  • C++ [hun]
  • C++ Optimizations Diary [eng]
  • C++ Code for yourself videos [eng]
"},{"location":"linkek/#robotikai-ismeretek","title":"Robotikai ismeretek","text":"
  • Alap robotikai ismeretek [eng]
  • K\u00e1lm\u00e1n filter [eng]
  • Universitat Polit\u00e8cnica de Catalunya BarcelonaTech (UPC) - [eng]
  • Pozna Tan\u00e1r \u00dar \u00e9s Antonya Csaba \u00e1ltal \u00edrt angol nyelv\u0171 oktat\u00f3anyag - Autocarsim [eng]
"},{"location":"linkek/#stanford-university","title":"Stanford University","text":"
  • Stanford University - Introduction to Robotics Oussama Khatib - [eng, video playlist]
"},{"location":"linkek/#tu-munchen","title":"TU M\u00fcnchen","text":"
  • Github link: github.com/TUMFTM/Lecture_ADSE
Number Session Description Video Lecture Slides 1 Python intro Some basics of programming in python for beginners. ResearchGate 2 Basics of mapping and localization Exemplary implementation of a Kalman filter and application for localization via GNSS-signal. YouTube ResearchGate 3 SLAM The google cartographer SLAM algorithm is applied to data from the KITTI-dataset. Note, that this lecture is held in Linux and has its own dependencies, please refer to the local readme. YouTube ResearchGate 4 Detection Overview about the YOLO-approach from network architecture to exemplary usage. YouTube ResearchGate 5 Prediction Implementation of the pipeline to setup a motion prediction algorithm based on a Encoder-Decoder architecture. YouTube ResearchGate 6 Global plannings A global optimal race line optimization is shown. This lecture has its own dependencies, please refer to the local readme. YouTube ResearchGate 7 Local planning A local planning algorithm based on a graph-based approach is presented. YouTube ResearchGate 8 Control The design of a velocity controller and numerical solver for differential equation are covered. YouTube ResearchGate 9 Safety assessment The evaluation of the criticality of planned trajectories based on various metrics and their sensitivity is discussed. YouTube ResearchGate 10 Teleoperated driving How to send and receive data via MQTT over network is shown in this practice session. YouTube ResearchGate 11 End-to-End The exemplary pipeline of data collection from expert demonstration, training and application are treated in this session. This lecture has its own dependencies, please refer to the local YouTube ResearchGate"},{"location":"linkek/#magyar-nyelvu-ros-oktatoanyagok","title":"Magyar nyelv\u0171 ROS oktat\u00f3anyagok","text":"
  • ROS-gyakorlatok kezd\u0151oldal: horverno.github.io/ros-gyakorlatok
  • ROS telep\u00edt\u00e9se (hun) - Melodic
  • ROS \u00d3budai Egytem - Antal Bejczy Center for Intelligent Robotics (hun)
"},{"location":"linkek/#angol-nyelvu-ros-oktatoanyagok","title":"Angol nyelv\u0171 ROS oktat\u00f3anyagok","text":"
  • ROS telep\u00edt\u00e9se (eng)
  • ETH Z\u00fcrich - Programming for Robotics (ROS)
  • edX - Hello (Real) World with ROS
  • ROS.org tutorials
  • ROS PCL tutorial
  • Felipe Boseong Jeon ROS2 tutorials
"},{"location":"linkek/#apex-ai","title":"Apex AI","text":"
  • Apex AI youtube
  • 1: Development Environment
  • 2: ROS2 101
  • 3: ROS 2 Tooling - Develop Like a Pro
  • 4: Platform HW, RTOS and DDS
  • 5: Autonomous Driving Stacks
  • 6: Autoware 101
  • 7: Object Perception: LIDAR
  • 8: Object Perception: CAMERA
  • 9: Object Perception: Radar
  • 10: State Estimation for Localization
  • 11: LGSVL Simulator
  • 12: Motion Control
  • 13: Data Storage and Analytics
  • 14: HD Maps
  • F1/10 ROS
"},{"location":"linkek/#eth-zurich","title":"ETH Z\u00fcrich","text":"
  • Programming for Robotics - ROS: P\u00e9ter Fankhauser, Dominic Jud, Martin Wermelinger, Prof. Dr. Marco Hutter. rsl.ethz.ch/education-students/lectures/ros.html
2021TopicsMaterial 22.02.
  • ROS architecture & philosophy
  • ROS master, nodes, and topics
  • Console commands
  • Catkin workspace and build system
  • Launch-files
  • Gazebo simulator
  • Programming Tools
  • Lecture Slides (PDF, 2.4 MB)
  • Exercises (PDF, 314 KB)
  • Files: smb_common.zip (ZIP, 2.3 MB)
  • Video Recording
24.02.
  • ROS package structure
  • Integration and programming with Eclipse
  • ROS C++ client library (roscpp)
  • ROS subscribers and publishers
  • ROS parameter server
  • RViz visualization
  • Lecture Slides (PDF, 2.4 MB)
  • Exercises (PDF, 219 KB)
  • Files: smb_highlevel_controller.zip (ZIP, 3 KB)
  • Video Recording
26.02.
  • TF Transformation System
  • rqt User Interface
  • Robot models (URDF)
  • Simulation descriptions (SDF)
  • Lecture Slides (PDF, 2 MB)
  • Exercises (PDF, 170 KB)
  • Files: smb_common_v2.zip (ZIP, 2.3 MB)
  • Files: singlePillar.world (WORLD, 1 KB)
  • Video Recording
01.03.
  • ROS services
  • ROS actions (actionlib)
  • ROS time
  • ROS bags
  • Debugging strategies
  • Introduction to ROS2
  • Lecture Slides (PDF, 932 KB)
  • Exercises (PDF, 283 KB)
  • Files: smb_navigation.bag (BAG, 158.9 MB)
  • Video Recording
05.03.
  • Case study: Using ROS in complex real-world applications
  • Exercises (PDF, 67 KB)
2021:
  • ANYbotics Case Study (PDF, 8.6 MB)
  • Video Recording
2020:
  • ANYbotics Case Study (PDF, 7.6 MB)
2018:
  • Building a Legged Robot with ROS slides (PDF, 11.5 MB)
  • mANYpulator \u2013 Mobile Manipulation slides (PDF, 2 MB)
  • Using ROS with other Simulators slides (PDF, 1.6 MB)
2017:
  • ANYmal at the ARGOS Challenge slides
"},{"location":"linkek/#university-of-bonn","title":"University of Bonn","text":"

Link: ipb.uni-bonn.de/sdc-2021

Self-Driving Cars: An Introduction (Cyrill Stachniss) Introduction lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi.

Self-Driving Cars: Localization (Daniel Wilbers) Localization lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. Further Information on Deep Learning and CNNs, see our Machine Learning for Robotics and Computer Vision Course: Youtube Link

Self-Driving Cars: Control (Nived Chebrolu) Control lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

Model Predictive Control \u2013 Part 1: Introduction to MPC (Lasse Peters) Introduction to Model Predictive Control; lecture presented by Lasse Peters. Youtube Link

Model Predictive Control \u2013 Part 2: Numerical Methods for MPC (Lasse Peters) Numerical Methods for Model Predictive Control; lecture presented by Lasse Peters. Youtube Link

Self-Driving Cars: Planning (Benedikt Mersch) Planning lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

Self-Driving Cars: Behavior Estimation (Benedikt Mersch) Behavior estimation lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi, Lasse Peters. Youtube Link

Self-Driving Cars: Perception \u2013 Part 1 (Jens Behley) Youtube Link Perception lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. Further Information on Deep Learning and CNNs, see our Machine Learning for Robotics and Computer Vision Course: Youtube playlist

Self-Driving Cars: Perception \u2013 Part 2 (Jens Behley) Perception lecture for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. Youtube Link

Self-Driving Cars: View from Practice (Igor Bogoslavskyi) Lecture giving a view from practice for the course \u201cTechniques for Self-Driving Cars\u201d taught at the University of Bonn. A course by Cyrill Stachniss, Jens Behley, Nived Chebrolu, Benedikt Mersch, Igor Bogoslavskyi. Youtube Link

"},{"location":"linkek/#articulated-robotics","title":"Articulated Robotics","text":"

ROS 2

  • Youtube playlist
  • articulatedrobotics.xyz
"},{"location":"linkek/#the-robotics-back-end","title":"The Robotics Back-End","text":"

ROS 2

  • Youtube playlist
  • roboticsbackend.com
"},{"location":"linkek/#foxglove-ros-2-tutorials","title":"Foxglove ROS 2 tutorials","text":"
  • foxglove.dev/tutorials
  • Install ROS 2 Galactic on Ubuntu
  • Install ROS 2 Galactic on Ubuntu
  • Install ROS 2 Humble on Ubuntu
  • Install ROS 2 Humble on macOS with Docker
  • Introduction to ROS 2
  • Use a Rosbridge connection
  • Create services
  • Create actions
  • Use parameters
  • Use launch files
  • Understand transforms
  • Publish and visualize transforms
  • Calculate object positions across frames
"},{"location":"linkek/#official-ros-2-documentation","title":"Official ROS 2 documentation","text":"
  • docs.ros.org/en/humble
  • docs.ros.org
"},{"location":"linkek/#egyeb","title":"Egy\u00e9b","text":"
  • VS code \u00e9s ROS 2 aj\u00e1nlott be\u00e1ll\u00edt\u00e1sok: picknik.ai/vscode/docker/ros2/2024/01/23/ROS2-and-VSCode.html
  • ROS felhaszn\u00e1l\u00f3k a vil\u00e1gban: metrorobots.com/rosmap.html
  • Colcon cheatsheet: github.com/ubuntu-robotics/ros2_cheats_sheet/blob/master/colcon%2Fcolcon_cheats_sheet.pdf
  • IEEE robots guide robotsguide.com/robots
"},{"location":"mesterseges_intelligencia/","title":"Mesters\u00e9ges intelligencia","text":"

Az AI az \u00e9szlel\u00e9s mellett ak\u00e1r a tervez\u00e9sn\u00e9l vagy a szab\u00e1lyoz\u00e1sn\u00e1l is megjelenhet.

B\u00e1r legfontosabb auton\u00f3m alkamaz\u00e1si k\u00f6re az \u00e9szlel\u00e9s, ahogy a fenti \u00e1br\u00e1n is l\u00e1tszik: tervez\u00e9si illetve szab\u00e1lyoz\u00e1si felhaszn\u00e1l\u00e1sa is van.

A mesters\u00e9ges intelligencia (AI) \u00f3rai prezent\u00e1ci\u00f3 itt tal\u00e1lhat\u00f3 meg: Link

P\u00e9lda vide\u00f3k:

"},{"location":"mesterseges_intelligencia/practice/","title":"Mesters\u00e9ges intelligencia gyakorlat","text":""},{"location":"mesterseges_intelligencia/practice/#gyakorlati-anyag-letoltese","title":"Gyakorlati anyag let\u00f6lt\u00e9se","text":"

A gyakorlati anyag friss\u00edt\u00e9s\u00e9hez adjuk ki a k\u00f6vetkez\u0151 parancsokat:

cd ~/ros2_ws/src/arj_packages\n
git checkout -- .\n
git pull\n

"},{"location":"mesterseges_intelligencia/practice/#conda-kornyezet-telepitese","title":"Conda k\u00f6rnyezet telep\u00edt\u00e9se","text":"

Az anaconda (miniconda) egy izol\u00e1lt virtu\u00e1lis k\u00f6rnyezetet biztos\u00edt, ahol az \u00e9ppen aktu\u00e1lis munk\u00e1hoz sz\u00fcks\u00e9ges verzi\u00f3sz\u00e1m\u00fa Python csomagokat tudjuk telep\u00edteni.

mkdir -p ~/miniconda3\n
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh\n
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3\n
rm -rf ~/miniconda3/miniconda.sh\n
~/miniconda3/bin/conda init bash\n

A solver hangolja \u00f6ssze a verzi\u00f3kat az el\u0151re defini\u00e1lt k\u00f6rnyezethez (environment.yml) sz\u00fcks\u00e9ges csomagok k\u00f6z\u00f6tt. A libmamba-solver az alap\u00e9rtelmezetthez solverhez k\u00e9pest egy gyorsabb hangol\u00e1st tesz lehet\u0151v\u00e9.

source ~/.bashrc\n
conda config --set auto_activate_base false\n
conda update -n base conda\n
conda install -n base conda-libmamba-solver\n
conda config --set solver libmamba\n

Miut\u00e1n a Conda telep\u00fclt, l\u00e9trehozzuk a saj\u00e1t virtu\u00e1lis k\u00f6rnyezet\u00fcnket:

cd ~/ros2_ws/src/arj_packages/arj_ai\n
conda env create -f environment.yml\n

"},{"location":"mesterseges_intelligencia/practice/#gyakorlat-megnyitasa","title":"Gyakorlat megnyit\u00e1sa","text":"

Az anyag a k\u00f6vetkez\u0151k\u00e9ppen nyithat\u00f3 meg:

conda activate gyakorlat\n
cd ~/ros2_ws/src/arj_packages/arj_ai \n
code .\n

V\u00e1lassszuk ki a k\u00f6rnyezetet:

"},{"location":"mesterseges_intelligencia/practice/#hibaelharitas","title":"Hibaelh\u00e1r\u00edt\u00e1s","text":"

TODO

ImportError                               Traceback (most recent call last)\nCell In[1], line 10\n      8 import matplotlib.patches as patches\n      9 import matplotlib.pyplot as plt\n---> 10 import torch\n     11 import torchvision.transforms as transforms\n     12 from PIL import Image\n\nFile ~/miniconda3/envs/gyakorlat/lib/python3.8/site-packages/torch/__init__.py:189\n    187     if USE_GLOBAL_DEPS:\n    188         _load_global_deps()\n--> 189     from torch._C import *\n    191 # Appease the type checker; ordinarily this binding is inserted by the\n    192 # torch._C module initialization code in C\n    193 if False:\n\nImportError: /home/he/miniconda3/envs/gyakorlat/lib/python3.8/site-packages/torch/lib/libtorch_cpu.so: undefined symbol: iJIT_IsProfilingActive\n
"},{"location":"mesterseges_intelligencia/practice/#conda-deaktivalas","title":"Conda deaktiv\u00e1l\u00e1s","text":"
conda deactivate\n
"},{"location":"onallo/","title":"\u00d6n\u00e1ll\u00f3 feladatok, otthoni gyakorl\u00e1s","text":""},{"location":"onallo/bashalias/","title":"Bash aliases","text":"

A .bash_aliases egy konfigur\u00e1ci\u00f3s f\u00e1jl a Bash sz\u00e1m\u00e1ra, amely lehet\u0151v\u00e9 teszi aliasok (parancs \u00e1tnevez\u00e9sek/alternat\u00edv\u00e1k) l\u00e9trehoz\u00e1s\u00e1t \u00e9s egy\u00e9ni parancsok defini\u00e1l\u00e1s\u00e1t. Az aliasok haszn\u00e1lat\u00e1val r\u00f6vid\u00edtheted a gyakran haszn\u00e1lt parancsokat, vagy megadhatsz olyan parancsokat, amelyeket gyakran szeretn\u00e9l ugyan\u00fagy futtatni, de hosszabb vagy bonyolultabb param\u00e9terekkel.

Arra j\u00f3, hogy pl. a gyakran haszn\u00e1lt source ~/ros2_ws/install/setup.bash parancsot az r2 r\u00f6vid\u00edt\u00e9ssel futtathatod.

N\u00e9zz\u00fck meg mi tal\u00e1lhat\u00f3 jelenleg a .bash_aliases f\u00e1jlban:

cat ~/.bash_aliases\n

Az el\u0151retelep\u00edtett verz\u00f3kban hasonl\u00f3 tartalom fogad:

# some more ls aliases for JKK, Szenergy and friends\nalias r2='source ~/ros2_ws/install/setup.bash && echo \"source ~/ros2_ws/install/setup.bash\"'\nalias aw='source ~/autoware/install/setup.bash && echo \"source ~/autoware/install/setup.bash\"'\nalias r1='screen -mdS roscore1 bash -c 'roscore' && echo \"screen roscore1\"'\n

Ha nincs ilyen f\u00e1jl, akkor hozzuk l\u00e9tre \u00e9s t\u00f6lts\u00fck le a fenti tartalmat:

cd ~; wget https://raw.githubusercontent.com/jkk-research/jkk_utils/ros2/.bash_aliases\n

Ha van ilyen f\u00e1jl, de szeretn\u00e9d friss\u00edteni, akkor t\u00f6r\u00f6ld \u00e9s t\u00f6ltsd le \u00fajra:

cd ~; rm .bash_aliases; wget https://raw.githubusercontent.com/jkk-research/jkk_utils/ros2/.bash_aliases\n
"},{"location":"onallo/joystick/","title":"Joystick bevezet\u00e9s","text":"

Todo

"},{"location":"onallo/joystick/#joystick-wsl-alatt","title":"Joystick WSL alatt","text":"

T\u00f6lts\u00fck le a foxe extension-t Foxglove Studio-hoz, majd drag and drop m\u00f3dszerrel h\u00fazzuk bele a foxglove-joystick csomagot.

Let\u00f6lthet\u0151 a github.com/joshnewans/foxglove-joystick/releases GitHub oldalr\u00f3l.

ros2 topic echo /joy --csv\n

"},{"location":"onallo/joystick/#josytick-linux-alatt","title":"Josytick Linux alatt","text":"
$ lsusb\nBus 001 Device 004: ID 046d:c219 Logitech, Inc. Cordless RumblePad 2\n$ ls -l /dev/input/js0 \n$ sudo chmod a+rw /dev/input/js0\n
ros2 topic echo /joy\n
"},{"location":"onallo/joystick/#ros-2-joy-package","title":"ROS 2 joy package","text":"
sudo apt install ros-humble-joy\n
"},{"location":"onallo/linux/","title":"Linux gyakorl\u00e1s","text":""},{"location":"onallo/linux/#mapparendszer-letrehozasa-terminal","title":"Mapparendszer l\u00e9trehoz\u00e1sa - terminal","text":"

A feladathoz telep\u00edts\u00fck a tree parancsot:

sudo apt install tree\n

A feladathoz megold\u00e1s\u00e1hoz touch, chmod, mkdir parancsok kellenek.

Hozzuk l\u00e9tre a k\u00f6vetkez\u0151 mapparendszert, ami a cd ~ && tree tmp_dir/ parancsra a k\u00f6vetkez\u0151k\u00e9pp n\u00e9z ki:

~/tmp_dir/\n\u251c\u2500\u2500 animals\n\u2502   \u251c\u2500\u2500 cat\n\u2502   \u2514\u2500\u2500 dog\n\u2502       \u251c\u2500\u2500 komondor\n\u2502       \u251c\u2500\u2500 puli\n\u2502       \u2514\u2500\u2500 vizsla\n\u251c\u2500\u2500 colors\n\u2502   \u251c\u2500\u2500 blue\n\u2502   \u251c\u2500\u2500 green\n\u2502   \u2514\u2500\u2500 red\n\u251c\u2500\u2500 py_exec.py\n\u251c\u2500\u2500 simple_text.txt\n\u2514\u2500\u2500 top\n    \u2514\u2500\u2500 middle\n        \u2514\u2500\u2500 bottom\n            \u2514\u2500\u2500 hello.txt\n13 directories, 3 files\n

Az ls -l ~/tmp_dir/ parancsra pedig a k\u00f6vetkez\u0151h\u00f6z hasonl\u00f3 rwx \u00e9rt\u00e9keket mutatja:

drwxr-xr-x 4 he he 4096 Feb 17 14:54 animals\ndrwxr-xr-x 5 he he 4096 Feb 17 14:55 colors\n-rwxrwxrwx 1 he he    0 Feb 17 14:52 py_exec.py\n-rw-r--r-- 1 he he    0 Feb 17 14:53 simple_text.txt\ndrwxr-xr-x 3 he he 4096 Feb 17 14:43 top\n
"},{"location":"onallo/linux/#megoldas-segedlet","title":"Megold\u00e1s seg\u00e9dlet","text":"
mkdir -p top/middle/bottom\nmkdir -p colors/{red,green,blue}\nmkdir -p animals/{cat,dog/{vizsla,puli,komondor}}\n
"},{"location":"onallo/linux/#szoveges-fajlok","title":"Sz\u00f6veges f\u00e1jlok","text":"

Ha m\u00e9g nem hozuk l\u00e9tre, akkor k\u00e9sz\u00edts\u00fcnk egy ~/tmp_text/ mapp\u00e1t.

A mapp\u00e1n bel\u00fcl k\u00e9sz\u00edts\u00fcnk egy hello.py f\u00e1jlt, majd termin\u00e1lb\u00f3l t\u00f6lts\u00fck fel a k\u00f6vetkez\u0151 tartalommal:

import sys\nprint('\\nHello vilag!\\nA verzio pedig:\\n' + sys.version)\n

Tegy\u00fck futtathat\u00f3v\u00e1 \u00e9s futtassuk.

"},{"location":"onallo/linux/#megoldas-segedlet_1","title":"Megold\u00e1s seg\u00e9dlet","text":"
echo \"import sys\" >> hello.py\necho \"print('\\nHello vilag!\\nA verzio pedig:\\n' + sys.version)\" >> hello.py\n
"},{"location":"onallo/mermaid/","title":"Mermaid gyakorl\u00e1s","text":"

A mermaid hasznos kieg\u00e9sz\u0151je lehet a markdown f\u00e1jlainknak (pl README.md). K\u00fcl\u00f6nb\u00f6z\u0151 grafikononokat, flowchartokat tudunk vele viszonylag k\u00f6nnyen l\u00e9trehozni.

"},{"location":"onallo/mermaid/#vs-code-extension","title":"VS code extension","text":"

Bal oldalt az Extension ikonra kattintva vagy a Ctrl + Shift + X ut\u00e1n a meraid kulcssz\u00f3t be\u00edrva el\u0151j\u00f6n a Markdown Preview kieg\u00e9sz\u00edt\u0151, ez egy katint\u00e1ssal telep\u00edthet\u0151 \u00e9s haszn\u00e1lhat is. Ezut\u00e1n a Markdown el\u0151n\u00e9zet\u00e9ben (Ctrl + Shift + V vagy fels\u0151 ikon) m\u00e1r l\u00e1that\u00f3 is lesz az el\u0151ln\u00e9zet.

Mermaid, VS code extension Mermaid, VS code

C\u00e9lszer\u0171 a Mermaid Markdown Syntax Highlighting \u00e9s a Color Highlight extension-t is haszn\u00e1lni, ekkor a k\u00f6vetkez\u0151k\u00e9pp jelenik meg a gr\u00e1f k\u00f3dja:

Mermaid, VS code highlight"},{"location":"onallo/mermaid/#peldak","title":"P\u00e9ld\u00e1k","text":""},{"location":"onallo/mermaid/#egyszeru-pelda","title":"Egyszer\u0171 p\u00e9lda","text":"

Ay egyik legegyszer\u0171bb flowchart k\u00f3dja k\u00f6vetkez\u0151 2 sorb\u00f3l \u00e1ll:

graph LR;\nnode1 --> topic --> node2\n

Az els\u0151 sor a gr\u00e1f t\u00edpusa, a m\u00e1sodik (vagy tov\u00e1bbi) sorokban a kapcsolatokat --> a nyilak defini\u00e1lj\u00e1k.

graph LR;\nnode1 --> topic --> node2
"},{"location":"onallo/mermaid/#teglalap-helyett-formakkal","title":"T\u00e9glalap helyett form\u00e1kkal","text":"

Az LR a left-right r\u00f6vid\u00edt\u00e9se. A form\u00e1k lehetnek lekerek\u00edtettek ([ ]), sz\u00f6gletesek [ ], hexagonok {{ }} paralellogramm\u00e1k [/ /] \u00e9s tov\u00e1bbiak is. ROS-ben megtanultuk, hogy a node lekerek\u00edtett, m\u00edg a topic sz\u00f6gletes. Az azonos\u00edt\u00f3kat itt pl: id1, id2, id3 a z\u00e1r\u00f3jel el\u00e9 lehet \u00edrni. A kapcsolatkoat vagy k\u00fcl\u00f6n sorban (mint itt) vagy egy sorban (k\u00e9s\u0151bbi p\u00e9lda) is defini\u00e1lhatjuk.

graph LR;\nid1([node1])\nid2([node2])\nid3[topic]\n\nid1 --> id3 --> id2\n
graph LR;\nid1([node1])\nid2([node2])\nid3[topic]\n\nid1 --> id3 --> id2
"},{"location":"onallo/mermaid/#balrol-jobbra-helyett-fentrol-lefele","title":"Balr\u00f3l jobbra helyett fentr\u0151l lefele","text":"

Az TD a top-down r\u00f6vid\u00edt\u00e9se:

graph TD;\nid1([node1])\nid2([node2])\nid3[topic]\n\nid1 --> id3 --> id2\n
graph TD;\nid1([node1])\nid2([node2])\nid3[topic]\n\nid1 --> id3 --> id2
"},{"location":"onallo/mermaid/#szinek-hasznalata","title":"Sz\u00ednek haszn\u00e1lata","text":"

classDef seg\u00edts\u00e9g\u00e9vel sz\u00edneket, vonalakat, defin\u00e1lhatunk, majd 3 db kett\u0151spont ut\u00e1n ::: azonos\u00edthatjuk a megfelel\u0151 oszt\u00e1lyhoz:

graph TD;\nid1([node1]):::red\nid2([node2]):::red\nid3[topic]:::light\n\nid1 --> id3 --> id2\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
graph TD;\nid1([node1]):::red\nid2([node2]):::red\nid3[topic]:::light\n\nid1 --> id3 --> id2\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
"},{"location":"onallo/mermaid/#tobb-node-es-topic","title":"T\u00f6bb node \u00e9s topic","text":"

Tov\u00e1bbi, t\u00f6bb node-ot \u00e9s topicot tartalmaz\u00f3 p\u00e9lda:

graph LR;\n\ngen([ /gen_node]) --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32]\nsine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])\nsum --> out[ /out<br/>std_msgs/Float32]\nrand --> sum\nin[ /in<br/>std_msgs/Float32] --> sum\n
graph LR;\n\ngen([ /gen_node]) --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32]\nsine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])\nsum --> out[ /out<br/>std_msgs/Float32]\nrand --> sum\nin[ /in<br/>std_msgs/Float32] --> sum
"},{"location":"onallo/mermaid/#az-elobbi-pelda-csak-szinekkel","title":"Az el\u0151bbi p\u00e9lda, csak sz\u00ednekkel","text":"
graph LR\n\ngen([ /gen_node]):::red --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32]:::light \nsine[ /sine<br/>std_msgs/Float32]:::light --> sum([ /sum_node]):::red\nsum --> out[ /out<br/>std_msgs/Float32]:::light \nrand --> sum\nin[ /in<br/>std_msgs/Float32]:::light --> sum\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
graph LR\n\ngen([ /gen_node]):::red --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32]:::light \nsine[ /sine<br/>std_msgs/Float32]:::light --> sum([ /sum_node]):::red\nsum --> out[ /out<br/>std_msgs/Float32]:::light \nrand --> sum\nin[ /in<br/>std_msgs/Float32]:::light --> sum\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"onallo/mermaid/#alternativ-verzio-class-hasznalatara","title":"Alternat\u00edv verzi\u00f3 class haszn\u00e1lat\u00e1ra","text":"

A h\u00e1rom ::: pont helyett egyszer\u0171en a class kulcssz\u00f3 ut\u00e1n felsorolhatjuk az oszt\u00e1lyokat:

graph LR\n\ngen([ /gen_node]) --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32] \nsine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])\nsum --> out[ /out<br/>std_msgs/Float32]\nrand --> sum\nin[ /in<br/>std_msgs/Float32] --> sum\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n\nclass gen,sum red\nclass rand,sine,in,out light\n
graph LR\n\ngen([ /gen_node]) --> sine\ngen --> rand[ /rand<br/>std_msgs/Float32] \nsine[ /sine<br/>std_msgs/Float32] --> sum([ /sum_node])\nsum --> out[ /out<br/>std_msgs/Float32]\nrand --> sum\nin[ /in<br/>std_msgs/Float32] --> sum\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n\nclass gen,sum red\nclass rand,sine,in,out light\n
flowchart LR\n\nA[/ max_deg</br>param /]:::gray --> D([display_tree</br>node]):::gray\nB[/ max_dist</br>param /]:::gray --> D\nC[/ seed_size</br>param /]:::gray --> D\nD --> |visualization_msgs/marker_array| P[ /path_marker_topic</br>topic]:::gray\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef gray fill:#f6f8fa,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"onallo/mermaid/#parameterek","title":"Param\u00e9terek","text":"

Gyakran j\u00f3l j\u00f6n a defini\u00e1lt param\u00e9terek vizualiz\u00e1l\u00e1sa. Erre jelen tud\u00e1sunk szerint nincs szabv\u00e1nyos jel\u00f6l\u00e9s hexagonok {{ }} vagy paralellogramm\u00e1k [/ /] lehetnek az opci\u00f3k.

flowchart LR\n\nA[/ max_deg</br>param /]:::gray --> D([display_tree</br>node]):::gray\nB[/ max_dist</br>param /]:::gray --> D\nC[/ seed_size</br>param /]:::gray --> D\nD --> |visualization_msgs/marker_array| P[ /path_marker_topic</br>topic]:::gray\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef gray fill:#f6f8fa,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\nclassDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff
"},{"location":"onallo/mermaid/#rendszerterv","title":"Rendszerterv","text":"
flowchart TD\n    S[State Machine <br>/plan_state_machine] -.->|/plan_state*| LS[LIDAR segementation<br>/prcp_ground_obstacle_segm_lidar]\n    S -.-> CS[Cone detection camera<br> and de-projection]\n    S -.-> O[Object fusion]\n    CS -->|/prcp_obj_list_camera| O\n    LS -->|/prcp_obj_list_lidar| O\n    O -->|/prcp_obj_list_fused| T[Trajectory planner<br>/plan_trajectory_planner]\n    T --> C[Control<br>/ctrl_vehicle_control]\n    S -.-> T\n    S -.-> C\n    O --> M[Map Creation<br>/prc_slam]\n    M -->|/prcp_map| T\n    L[Localization<br>/prcp_odometry_kf_prediction] --> T\n    C --> CAN[To CAN]\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274\n    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n    classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff\n    class CS,LS,L,T,M,C white\n    class O light\n    class S dash\n    class CAN red\n
flowchart TD\n    S[State Machine <br>/plan_state_machine] -.->|/plan_state*| LS[LIDAR segementation<br>/prcp_ground_obstacle_segm_lidar]\n    S -.-> CS[Cone detection camera<br> and de-projection]\n    S -.-> O[Object fusion]\n    CS -->|/prcp_obj_list_camera| O\n    LS -->|/prcp_obj_list_lidar| O\n    O -->|/prcp_obj_list_fused| T[Trajectory planner<br>/plan_trajectory_planner]\n    T --> C[Control<br>/ctrl_vehicle_control]\n    S -.-> T\n    S -.-> C\n    O --> M[Map Creation<br>/prc_slam]\n    M -->|/prcp_map| T\n    L[Localization<br>/prcp_odometry_kf_prediction] --> T\n    C --> CAN[To CAN]\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274\n    classDef dash fill:#ffffff,stroke:#152742,stroke-width:2px,color:#15274, stroke-dasharray: 5 5\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n    classDef green fill:#138b7b,stroke:#152742,stroke-width:2px,color:#fff\n    class CS,LS,L,T,M,C white\n    class O light\n    class S dash\n    class CAN red
"},{"location":"onallo/mermaid/#korcikk","title":"K\u00f6rcikk","text":"

Az metrics.ros.org/rosdistro_rosdistro.html alapj\u00e1n egy k\u00f6rcikk diagram:

pie title ROS distros used\n    \"Melodic (ROS 1)\" : 0.0010\n    \"Noetic (ROS 1)\" : 0.0951\n    \"Humble\" : 0.3333\n    \"Iron\" : 0.1905\n    \"Rolling\" : 0.1904\n
pie title ROS distros used\n    \"Melodic (ROS 1)\" : 0.001\n    \"Noetic (ROS 1)\" : 0.095\n    \"Humble\" : 0.33\n    \"Iron\" : 0.19\n    \"Rolling\" : 0.19
"},{"location":"onallo/mermaid/#linkek","title":"Linkek","text":"
  • Mermaid flowchart
  • Mermaid pie chart
  • Mermaid intro
"},{"location":"onallo/ros2git/","title":"Git alapismeretek","text":""},{"location":"onallo/ros2git/#par-parancs","title":"P\u00e1r parancs","text":"
  • git clone: git repo kl\u00f3noz\u00e1sa
  • git config --global user.name \"Sanyika\": felhszn\u00e1l\u00f3n\u00e9v be\u00e1ll\u00edt\u00e1sa
  • git config --global user.email \"sanyika@gggmail.com: email be\u00e1ll\u00edt\u00e1sa
  • git init: lok\u00e1lis rep\u00f3 inicializ\u00e1l\u00e1sa
  • git add <file>: f\u00e1jl hozz\u00e1ad\u00e1sa
  • git status: aktu\u00e1lis st\u00e1tusz lek\u00e9rdez\u00e9se
  • git commit -m \"My beautiful commit\": commit, \u00fczenettel
  • git push: push
  • git pull: pull, v\u00e1ltoz\u00e1sok lok\u00e1lis lefriss\u00edt\u00e9se
  • git branch <new_branch_name>: branch k\u00e9sz\u00edt\u00e9se
  • git checkout <branch_name>: \u00faj branch
  • git checkout -- .: Minden nem staged (unstaged) v\u00e1ltoz\u00e1s elvet\u00e9se lok\u00e1lisan. VS code-ban kb ez a \"discard all changes\" parancs. (\u00dajabb git verzi\u00f3kban a git restore . is hasonl\u00f3 m\u00f3don m\u0171k\u00f6dik.)
  • git merge <branch_name>: a jelenlegi branch-be mergeli a branch-t

Forr\u00e1s: link

"},{"location":"onallo/ros2git/#terminologia","title":"Terminol\u00f3gia","text":"
  • Local repository: a helyi munka repo, pl lok\u00e1lisan a ~/ros2_ws/src/my_repo
  • Remote repository: \u00e1ltal\u00e1ban online t\u00e1voli backup repo pl: github.com/my_name/my_repo
"},{"location":"onallo/ros2git/#elokeszuletek","title":"El\u0151k\u00e9sz\u00fcletek","text":"

Ha m\u00e9g nem tetted volna meg, regisztr\u00e1lj GitHub-ra.

"},{"location":"onallo/ros2git/#a-template-hasznalata","title":"A template haszn\u00e1lata","text":"

Navig\u00e1lj a https://github.com/sze-info/ros2_cpp_template URL-re.

Itt haszn\u00e1ld a z\u00f6ld gombot, hozd l\u00e9tre a saj\u00e1t felhaszn\u00e1l\u00f3ddal a my_awesome_package nev\u0171 package-t:

Ut\u00e1na ez az oldal fogad, itt ki kell t\u00f6lteni a repo nev\u00e9t, ut\u00e1na pedig a z\u00f6ld gombra kattintva l\u00e9trej\u00f6n a repo:

"},{"location":"onallo/ros2git/#klonozd-git-clone-segitsegevel-a-sajat-package-d","title":"Kl\u00f3nozd git clone seg\u00edts\u00e9g\u00e9vel a saj\u00e1t package-d","text":"

Ha a Github userneved mycoolusername a repo (\u00e9s egyben a package) neve pedig my_awesome_package, akkor pl \u00edgy tudod megtenni:

cd ~/ros2_ws/src\n
git clone https://github.com/mycoolusername/my_awesome_package\n
git clone https://github.com/horverno/my_awesome_package\n

"},{"location":"onallo/ros2git/#vs-code-ban-cserelj-ki-mindent","title":"VS code-ban cser\u00e9lj ki mindent","text":"

cd ~/ros2_ws/src/my_awesome_package\n
code .\n

  1. ros2_cpp_template >> my_awesome_package
  2. sze-info >> mycoolusername
  3. todo >> \u00e9rtelemszer\u0171en

"},{"location":"onallo/ros2git/#build","title":"Build","text":"

M\u00e1r buildelhet\u0151 a package:

cd ~/ros2_ws/\n
colcon build --packages-select my_awesome_package\n
A termin\u00e1l egy \u00fczenetet k\u00fcld vissza, amely meger\u0151s\u00edti, hogy a my_awesome_package csomag lebuildelt.

"},{"location":"onallo/ros2git/#futtatas","title":"Futtat\u00e1s","text":"

Futtat\u00e1s a szok\u00e1sos m\u00f3don:

source ~/ros2_ws/install/local_setup.bash\n
ros2 launch my_awesome_package launch_example1.launch.py\n

"},{"location":"onallo/ros2git/#valtozasok-kovetese-git-status-segitsegevel","title":"V\u00e1ltoz\u00e1sok k\u00f6vet\u00e9se git status seg\u00edts\u00e9g\u00e9vel","text":"

Amikor lecser\u00e9lt\u00fck a package nevet, t\u00f6bb f\u00e1jl is m\u00f3dosult:

cd ~/ros2_ws/src/my_awesome_package\n
git status\n

Git status

Ugyanez VS code-ban \u00edgy n\u00e9z ki:

Git status VS code"},{"location":"onallo/ros2git/#tavoli-repo-frissitese-git-push-segitsegevel","title":"T\u00e1voli repo friss\u00edt\u00e9se git push seg\u00edts\u00e9g\u00e9vel","text":"

Minden m\u00f3dos\u00edt\u00e1st szeretnnk a commithoz adni:

git add .\n

T\u00f6lts\u00fck ki az \u00fczenetet:

git commit -m \"Initial commit of my_awesome_package\"\n

T\u00e9nylegesen push-oljuk a m\u00f3dos\u00edt\u00e1st a GitHub szervereire:

git push\n
Git status add ut\u00e1n

VS code-ban ez is egyszer\u0171bb, Commit, majd Sync Changes:

Git status Sync (push)"},{"location":"onallo/ros2git/#lokalis-repo-frissitese-git-pull-segitsegevel","title":"Lok\u00e1lis repo friss\u00edt\u00e9se git pull seg\u00edts\u00e9g\u00e9vel","text":"

Abban az esetben, ha nem a legfrissebb verzi\u00f3 lenne lok\u00e1lisan, a github-on online t\u00e1rolt remote lefriss\u00edtehet\u0151:

Git status (pull)"},{"location":"onallo/ros2git/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
"},{"location":"onallo/ros2launchmarker/","title":"Le\u00edr\u00e1s","text":"

\u00d6n\u00e1ll\u00f3 feladatk\u00e9nt k\u00e9sz\u00edts\u00fcnk egy my_launch_pkg nev\u0171 package-t, amiben egy run_transforms_and_markers.launch.py elind\u00edtja a:

  • node-ot, ami a map, orbit1 \u00e9s orbit2 frame-ket publik\u00e1lja (ros2 run arj_transforms_cpp pub_transforms)
  • az rqt_reconfigure-t (ros2 run rqt_reconfigure rqt_reconfigure)
  • a statikus orbit3 frame-et (ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3)
  • \u00e9s az Rviz2-t ind\u00edt\u00f3 launch-t is (ros2 launch arj_transforms_cpp rviz1.launch.py)

Ellen\u0151rizz\u00fck rviz2-ben a helyes m\u0171k\u00f6d\u00e9st.

Teh\u00e1t ind\u00edthat\u00f3 legyen az \u00f6n\u00e1ll\u00f3 feladat v\u00e9g\u00e9n a k\u00f6vetkez\u0151 paranccsal:

ros2 launch my_launch_pkg run_transforms_and_markers.launch.py\n
"},{"location":"onallo/ros2launchmarker/#hozzuk-letre-a-my_launch_pkg-package-t","title":"Hozzuk l\u00e9tre a my_launch_pkg package-t","text":"

El\u0151k\u00f6vetelm\u00e9ny, hogy a arj_transforms_cpp package m\u00e1r buildelve \u00e9s futtathat\u00f3 legyen.

Ha esetleg m\u00e1r l\u00e9tezne a my_launch_pkg package akkor t\u00f6r\u00f6lj\u00fck. (G\u00e9pteremben elk\u00e9pzelehet\u0151, hogy el\u0151z\u0151 f\u00e9l\u00e9vben valaki l\u00e9trehozta.)

cd ~ && test -d \"ros2_ws/src/my_launch_pkg\" && echo Letezik || echo Nem letezik\n
rm -r  ~/ros2_ws/src/my_launch_pkg\n

Nyissunk egy \u00faj termin\u00e1lt, \u00e9s source-oljuk a telep\u00edt\u00e9st (ha nincs bashrc-ben), hogy a ros2 parancsok m\u0171k\u00f6djenek.

Navig\u00e1ljunk az m\u00e1r l\u00e9trehozott ros2_ws k\u00f6nyvt\u00e1rba.

Fontos, hogy a csomagokat az src k\u00f6nyvt\u00e1rban kell l\u00e9trehozni, nem a munkater\u00fclet gy\u00f6ker\u00e9ben. Teh\u00e1t navig\u00e1ljunk a ros2_ws/src mapp\u00e1ba, \u00e9s futtassuk a package l\u00e9trehoz\u00f3 parancsot:

cd ~/ros2_ws/src\n
ros2 pkg create --build-type ament_cmake my_launch_pkg\n

A termin\u00e1l egy \u00fczenetet k\u00fcld vissza, amely meger\u0151s\u00edti a my_launch_pkg csomag \u00e9s az \u00f6sszes sz\u00fcks\u00e9ges f\u00e1jl \u00e9s mappa l\u00e9trehoz\u00e1s\u00e1t.

"},{"location":"onallo/ros2launchmarker/#launch-mappa","title":"Launch mappa","text":"

Hozzunk l\u00e9tre egy mapp\u00e1t a launch f\u00e1jlok r\u00e9sz\u00e9re:

cd ~/ros2_ws/src/my_launch_pkg\n
mkdir launch\n
"},{"location":"onallo/ros2launchmarker/#launch-fajl-letrehozasa","title":"Launch f\u00e1jl l\u00e9trehoz\u00e1sa","text":"
cd launch\n
code run_transforms_and_markers.launch.py\n

\u00c1ll\u00edtsunk \u00f6ssze egy launch f\u00e1jlt:

from launch import LaunchDescription\nfrom launch_ros.actions import Node\nfrom launch.actions import IncludeLaunchDescription\nfrom launch.launch_description_sources import PythonLaunchDescriptionSource\nfrom launch_ros.substitutions import FindPackageShare\n\n\ndef generate_launch_description():\n    return LaunchDescription([\n        # ros2 run arj_transforms_cpp pub_transforms\n        Node(\n            package='arj_transforms_cpp',\n            executable='pub_transforms',\n        ),\n        # ros2 run rqt_reconfigure rqt_reconfigure\n        Node(\n            package='rqt_reconfigure',\n            executable='rqt_reconfigure',\n        ),\n        # ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3\n        Node(\n            package='tf2_ros',\n            executable='static_transform_publisher',\n            arguments=['1.0', '0.2', '1.4','0', '0', '0', '1', 'orbit2','orbit3'],\n        ),     \n        # ros2 launch arj_transforms_cpp rviz1.launch.py\n        IncludeLaunchDescription(\n            PythonLaunchDescriptionSource([\n                FindPackageShare(\"arj_transforms_cpp\"), '/launch/', 'rviz1.launch.py'])\n        ),\n    ])\n
"},{"location":"onallo/ros2launchmarker/#ros2-launch-hasznalata","title":"ROS2 launch haszn\u00e1lata","text":"

A l\u00e9trehozott launch f\u00e1jl elind\u00edt\u00e1sa az al\u00e1bbi m\u00f3don t\u00f6rt\u00e9nik:

cd ~/ros2_ws/src/my_launch_pkg/launch # bel\u00e9p\u00fcnk a launch f\u00e1jlt tartalmaz\u00f3 mapp\u00e1ba\n
ros2 launch run_transforms_and_markers.launch.py\n

A fent bemutatott direkt m\u00f3don k\u00edv\u00fcl egy launch f\u00e1jl futtathat\u00f3 csomag \u00e1ltal is:

ros2 launch <csomag_megnevez\u00e9se> <launch_f\u00e1jl_neve>\n

Olyan csomagok eset\u00e9ben, amelyek launch f\u00e1jlt tartalmaznak, \u00e9rdemes l\u00e9trehozni egy exec_depend f\u00fcgg\u0151s\u00e9get a ros2launch csomagra vonatkoz\u00f3an a csomag package.xml f\u00e1jlj\u00e1ban:

<exec_depend>ros2launch</exec_depend>\n

Ezzel biztos\u00edthat\u00f3, hogy az ros2 launch parancs el\u00e9rhet\u0151 a csomag buildel\u00e9se ut\u00e1n.

"},{"location":"onallo/ros2launchmarker/#adjuk-hozza-a-package-hez-hogy-barhonnan-indithassuk","title":"Adjuk hozz\u00e1 a package-hez, hogy b\u00e1rhonnan ind\u00edthassuk","text":"
cd ~/ros2_ws/src/my_launch_pkg\n
code .\n

A package.xml-hez a <test_depend> el\u00e9 sz\u00farjuk be k\u00f6vetkez\u0151 sort:

<exec_depend>ros2launch</exec_depend>\n

A CMakeLists.txt-hez a ament_package() el\u00e9 sz\u00farjuk be k\u00f6vetkez\u0151 2 sort:

install(DIRECTORY launch\n  DESTINATION share/${PROJECT_NAME})\n

Buildelj\u00fck a szok\u00e1so m\u00f3don:

cd ~/ros2_ws\n
colcon build --packages-select my_launch_pkg\n
source ~/ros2_ws/install/setup.bash\n

Ez a parancs most m\u00e1r b\u00e1rhonnan kiadhat\u00f3:

ros2 launch my_launch_pkg run_transforms_and_markers.launch.py\n
"},{"location":"onallo/ros2launchmarker/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
"},{"location":"ros2halado/","title":"ROS 2 halad\u00f3","text":""},{"location":"ros2halado/#ros-2-halado-funkciok","title":"ROS 2 halad\u00f3 funkci\u00f3k","text":""},{"location":"ros2halado/#ellenorzo-kerdesek","title":"Ellen\u0151rz\u0151 k\u00e9rd\u00e9sek","text":"
  • Melyik ROS verzi\u00f3t haszn\u00e1ljuk a f\u00e9l\u00e9vben?
  • Mi a node?
  • Mi a topic?
  • Milyen t\u00edpus\u00fa adatokat k\u00fcldhet\u00fcnk a topicokon kereszt\u00fcl? (p\u00e9ld\u00e1k)
"},{"location":"ros2halado/#ros-2-launch-fajlok","title":"ROS 2 launch f\u00e1jlok","text":""},{"location":"ros2halado/#ros-2-launch-szemleltetes","title":"ROS 2 launch szeml\u00e9ltet\u00e9s","text":"

flowchart LR\n    %% Launch file\n    A[LAUNCH<br>FILE]:::dark --o B1\n    A ---o B2\n    A ---o B3\n    D --o C1\n\n    %% SENSE THINK ACT PACKAGE\n    subgraph sense_think_act_package[\"SENSE THINK ACT<br>PACKAGE\"]\n        direction TB\n        B1([Sensor<br>Node]) \n        B2([Compute<br>Node])\n        B3([Motor<br>Node])\n    end\n\n    %% PARAMS PACKAGE\n    subgraph params_package[\"PARAMS PACKAGE\"]\n        direction TB\n        C1([Robot<br>Node])\n    end\n\n    %% Configuration parameters\n    A --o D[Configuration parameters]\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
Forr\u00e1s: foxglove.dev

"},{"location":"ros2halado/#ros-2-launch-fajlok_1","title":"ROS 2 launch f\u00e1jlok","text":"

T\u00f6bb ROS 2 node futtat\u00e1sa sok id\u0151t vesz ig\u00e9nybe \u00e9s t\u00f6bb termin\u00e1lablakra van sz\u00fcks\u00e9g. M\u00e9g a kisebb projektek vagy robotok is egyszerre t\u00f6bb node-ot futtathatnak.

K\u00e9pzelj\u00fcnk el egy robotot, amely a \"\u00e9rz\u00e9kel-gondolkodik-cselekszik\" (sense-think-act) modell alapj\u00e1n m\u0171k\u00f6dik, \u00e9s minden l\u00e9p\u00e9shez k\u00fcl\u00f6n node-ot futtat. Egy sensor_node felel\u0151s az \u00e9rz\u00e9kel\u0151 adatainak olvas\u00e1s\u00e1\u00e9rt, egy compute_node fogadja ezeket az adatokat, \u00e9s parancsot k\u00fcld a kerekeknek, v\u00e9g\u00fcl pedig egy motor_node fogadja a parancsot, \u00e9s a sz\u00fcks\u00e9ges fesz\u00fclts\u00e9get adja a motoroknak.

Ahelyett, hogy minden egyes node-ot k\u00fcl\u00f6n termin\u00e1lablakban futtatn\u00e1nk minden alkalommal, amikor elind\u00edtjuk a robotot, haszn\u00e1lhatunk egy ind\u00edt\u00f3f\u00e1jlt, hogy mindezeket egyszerre futtassuk \u2013 egyetlen parancs seg\u00edts\u00e9g\u00e9vel, egyetlen termin\u00e1lablakban.

"},{"location":"ros2halado/#hogyan-tehetjuk-ezt-meg","title":"Hogyan tehetj\u00fck ezt meg?","text":"

H\u00e1rom lehet\u0151s\u00e9g\u00fcnk van launch f\u00e1jlt \u00edrni, pythonban, yaml-ben vagy xml-ben. Ebb\u0151l kett\u0151t bemutatunk: az xml f\u00e1jlok egyszer\u0171bbek, de a python f\u00e1jlok sokkal rugalmasabbak \u00e9s k\u00f6nnyebben kezelhet\u0151ek.

PythonXML
# This function is always needed\ndef generate_launch_description():\n\n# Declare a variable Node for each node\ncompute_node = Node(\n    package=\"launch_pkg\",\n    executable=\"compute_node\"\n)\nsensor_node = Node(\n    package=\"launch_pkg\",\n    executable=\"sensor_node\"\n)\nmotor_node = Node(\n    package=\"launch_pkg\",\n    executable=\"motor_node\"\n)\n
<launch>\n    <node pkg=\"launch_pkg\" type=\"sensor_node\" name=\"sensor_node\" output=\"screen\"/>\n    <node \n        pkg=\"launch_pkg\" \n        type=\"compute_node\" \n        name=\"compute_node\" \n        output=\"screen\"/>\n    <node \n        pkg=\"launch_pkg\" \n        type=\"motor_node\" \n        name=\"motor_node\" \n        output=\"screen\"/>\n</launch>\n
flowchart LR\n    A([sensor_node]):::red\n    B[ /sensor_data]:::light\n    C([compute_node]):::red\n    D[ /cmd_vel]:::light\n    E([motor_node]):::red\n\n\n    A --> B --> C --> D --> E\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"ros2halado/#namespace","title":"Namespace","text":"

Az launch f\u00e1jlok csoportokba vagy n\u00e9vterekbe is csoportos\u00edthatj\u00e1k a node-okat. Ez megk\u00f6nny\u00edti a node-ok viselked\u00e9s\u00e9nek nyomon k\u00f6vet\u00e9s\u00e9t \u00e9s figyelemmel k\u00eds\u00e9r\u00e9s\u00e9t.

Egy node-nak csak egy neve van, de a n\u00e9vterek t\u00f6bb szintj\u00e9hez is tartozhat. Ezeket a n\u00e9vtereket perjellel (/) lehet \u00f6sszekapcsolni \u2013 minden n\u00e9vt\u00e9r n\u00e9lk\u00fcli csom\u00f3pontban mindig egyetlen / szerepel a neve el\u0151tt (pl. /sensor_node). A deklar\u00e1ci\u00f3 sor\u00e1n megadott n\u00e9vt\u00e9r n\u00e9lk\u00fcli t\u00e9mak\u00f6r\u00f6k \u00f6r\u00f6klik a csom\u00f3pont n\u00e9vter\u00e9t, ahogy az az el\u0151z\u0151 \u00e1br\u00e1n is l\u00e1that\u00f3.

Adjuk hozz\u00e1 h\u00e1rom node-ot a sense_think_act n\u00e9vter\u00e9hez:

sensor_node = Node(\n  namespace=\"sense_think_act\",\n  package=\"launch_pkg\",\n  executable=\"sensor_node\"\n)\n\ncompute_node = Node(\n  namespace=\"sense_think_act\",\n  package=\"launch_pkg\",\n  executable=\"compute_node\"\n)\n\nmotor_node = Node(\n  namespace=\"sense_think_act\",\n  package=\"launch_pkg\",\n  executable=\"motor_node\"\n)\n
flowchart TD\n    A([sense_think_act/sensor_node]):::red\n    B[ sense_think_act/sensor_data]:::light\n    C([sense_think_act/compute_node]):::red\n    D[ sense_think_act/cmd_vel]:::light\n    E([sense_think_act/motor_node]):::red\n\n\n    A --> B --> C --> D --> E\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff

Megjegyz\u00e9s: A balr\u00f3l jobbra elrendez\u00e9s helyett a helykihaszn\u00e1l\u00e1s miatt most a fentr\u0151l lefel\u00e9 elrendez\u00e9st haszn\u00e1ltunk.

"},{"location":"ros2halado/#mas-package-bol-szarmazo-node-ok-parameterek","title":"M\u00e1s package-b\u0151l sz\u00e1rmaz\u00f3 node-ok, param\u00e9terek","text":"
robot_node = Node(\n  namespace=\"core\",\n  package=\"params_pkg\",\n  executable=\"robot_node\",\n  parameters=[{\n    \"robot_name\":\"RobotA\",\n    \"max_speed\":4.2,\n    \"waypoints\":[\"Home\", \"Room 1\", \"Corridor\", \"Home\"]\n  }]\n)\nfoxglove_bridge = Node(\n    package='foxglove_bridge',\n    executable='foxglove_bridge',\n    parameters=[{\n        'port': 8765,\n        },\n    ]\n)\n\nld = [compute_node,\n    foxglove_bridge,\n    sensor_node,\n    motor_node,\n    robot_node]\n
flowchart TD\n    A([sense_think_act/sensor_node]):::red\n    B[ sense_think_act/sensor_data]:::light\n    C([sense_think_act/compute_node]):::red\n    D[ sense_think_act/cmd_vel]:::light\n    E([sense_think_act/motor_node]):::red\n    F([foxglove_bridge]):::red\n    G([core/robot_node]):::red\n\n    A --> B --> C --> D --> E\n    B --> F\n    D --> F\n    %% D --> G\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
"},{"location":"ros2halado/#tovabbi-pelda","title":"Tov\u00e1bbi p\u00e9lda","text":"
  • robot_a namespace:
    • sensor_node_a: \u00c9rz\u00e9kel\u0151 adatokat publik\u00e1l a /robot_a/sensor_data topicra.
    • control_node_a: Feliratkozik a /robot_a/sensor_data topicra, \u00e9s parancsokat k\u00fcld a /robot_a/cmd_vel topicra.
    • motor_node_a: Feliratkozik a /robot_a/cmd_vel topicra, hogy fogadja a motor parancsokat.
  • robot_b namespace:
    • sensor_node_b: \u00c9rz\u00e9kel\u0151 adatokat publik\u00e1l a /robot_b/sensor_data topicra.
    • control_node_b: Feliratkozik a /robot_b/sensor_data topicra, \u00e9s parancsokat k\u00fcld a /robot_b/cmd_vel topicra.
    • motor_node_b: Feliratkozik a /robot_b/cmd_vel topicra, hogy fogadja a motor parancsokat.
  • Megosztott:
    • Mindk\u00e9t robot megoszt egy topicot, a/shared/environment_data-t, ahol a sensor_node_a \u00e9s a sensor_node_b is publik\u00e1lhat vagy feliratkozhat.
    • Mindk\u00e9t robot megoszt egy topicot, a /shared/map_data-t, ahol a map_server publik\u00e1l \u00e9s a sensor_node_a \u00e9s a sensor_node_b feliratkozhat.
flowchart TB\n    %% Robot A\n    subgraph robot_a[\"Namespace: robot_a\"]\n        direction TB\n        sensor_a([sensor_node_a]):::red\n        control_a([control_node_a]):::red\n        motor_a([motor_node_a]):::red\n\n        sensor_a --> |/robot_a/sensor_data| control_a\n        control_a --> |/robot_a/cmd_vel| motor_a\n    end\n\n    %% Robot B\n    subgraph robot_b[\"Namespace: robot_b\"]\n        direction TB\n        sensor_b([sensor_node_b]):::red\n        control_b([control_node_b]):::red\n        motor_b([motor_node_b]):::red\n\n        sensor_b --> |/robot_b/sensor_data| control_b\n        control_b --> |/robot_b/cmd_vel| motor_b\n    end\n\n    map_sever([map_sever]):::red\n    /shared/map_data[ /shared/map_data]:::light\n\n    %% Shared Topic between Robot A and Robot B\n    sensor_a <--> |/shared/environment_data| sensor_b\n    map_sever --> /shared/map_data\n    /shared/map_data --> sensor_a\n    /shared/map_data --> sensor_b\n\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"ros2halado/#video","title":"Vide\u00f3","text":""},{"location":"ros2halado/#vizualizacio-es-debug","title":"Vizualiz\u00e1ci\u00f3 \u00e9s debug","text":""},{"location":"ros2halado/#foxglove-studio-lichtblick-suite","title":"Foxglove Studio / Lichtblick Suite","text":"

A Foxglove Studio egy ny\u00edlt forr\u00e1sk\u00f3d\u00fa, robotikai adatokat vizualiz\u00e1l\u00f3 \u00e9s hibakeres\u0151 eszk\u00f6z. L\u00e9tezik Windows, Linux \u00e9s MacOS rendszerekre. A v1.87.0-ig bez\u00e1r\u00f3lag ny\u00edlt forr\u00e1sk\u00f3du volt, a v2.0.0-t\u00f3l pedig ingyenesen haszn\u00e1lhat\u00f3, de z\u00e1rt forr\u00e1sk\u00f3d\u00fa. Az open source fejleszt\u00e9st t\u00f6bb fork, p\u00e9ld\u00e1ul a Lichtblick Suite vette \u00e1t. El\u00e9rhet\u0151 sz\u00e1mos m\u00f3don:

  • \u00f6n\u00e1ll\u00f3 asztali alkalmaz\u00e1sk\u00e9nt futtathat\u00f3
  • b\u00f6ng\u00e9sz\u0151ben hozz\u00e1f\u00e9rhet\u0151
  • saj\u00e1t domainen, \u00f6n\u00e1ll\u00f3an hostolhat\u00f3

A nat\u00edv robotikai eszk\u00f6z\u00f6k (mint p\u00e9ld\u00e1ul az ROS \u00f6kosziszt\u00e9ma r\u00e9szei) \u00e1ltal\u00e1ban csak Linux rendszeren t\u00e1mogatottak, de a Studio asztali alkalmaz\u00e1s Linuxon, Windows-on \u00e9s macOS-en is m\u0171k\u00f6dik. Ak\u00e1r az ROS stack m\u00e1s oper\u00e1ci\u00f3s rendszeren fut, a Studio k\u00e9pes kommunik\u00e1lni a robottal z\u00f6kken\u0151mentesen.

A Studio gazdag vizu\u00e1lis elemeket \u00e9s hibakeres\u0151 panelokat k\u00edn\u00e1l - interakt\u00edv diagramokt\u00f3l, 3D vizu\u00e1lis elemekig, kamerak\u00e9pekt\u0151l, \u00e9s diagnosztikai adatfolyamokig. Legyen sz\u00f3 val\u00f3s idej\u0171 robotk\u00f6vet\u00e9sr\u0151l, vagy .bag / .mcap f\u00e1jlban t\u00f6rt\u00e9n\u0151 hibakeres\u00e9sr\u0151l, ezek a panelok seg\u00edtenek a k\u00fcl\u00f6nb\u00f6z\u0151, \u00e1ltal\u00e1nos robotikai feladatok megold\u00e1s\u00e1ban.

Ezek a panelok ezut\u00e1n egyedi elrendez\u00e9sekben konfigur\u00e1lhat\u00f3k \u00e9s \u00f6ssze\u00e1ll\u00edthat\u00f3k a projekt egyedi ig\u00e9nyeinek \u00e9s munkafolyamatainak megfelel\u0151en.

  • Foxglove Studio let\u00f6lt\u00e9s
  • Lichtblick Suite let\u00f6lt\u00e9s
"},{"location":"ros2halado/#rviz","title":"Rviz","text":"

Az Rviz2 a ROS 2 nat\u00edv, ny\u00edlt forr\u00e1sk\u00f3d\u00fa, robotikai adatokat vizualiz\u00e1l\u00f3 \u00e9s hibakeres\u0151 eszk\u00f6ze. Ennek \u00e9rtelm\u00e9ben legink\u00e1bb Linux rendszeren haszn\u00e1lhat\u00f3, de a Windows \u00e9s macOS t\u00e1mogat\u00e1s is folyamatosan fejl\u0151dik.

ros2 run rviz2 rviz2\n

ros2 run rviz2 rviz2 --help\n
Parancs seg\u00edts\u00e9g\u00e9vel megtudhatjuk, hogy pl. -d kapcsol\u00f3val bet\u00f6lthet\u00fcnk egy .rviz konfigur\u00e1ci\u00f3s f\u00e1jlt, vagy -f fix frame-et adhatunk meg.

B\u0151vebben: docs.ros.org/en/humble/Tutorials/Intermediate/RViz/RViz-User-Guide/RViz-User-Guide.html

"},{"location":"ros2halado/#rqt_graph","title":"rqt_graph","text":"

Az rqt_graph a node-ok \u00e9s topic-ok vizualiz\u00e1ci\u00f3j\u00e1ra haszn\u00e1lhat\u00f3.

ros2 run rqt_graph rqt_graph\n

"},{"location":"ros2halado/#rqt_console","title":"rqt_console","text":"

Az rqt_console log (info, debug, warn, error, fatal) \u00fczenetek megjelen\u00edt\u00e9sre, sz\u0171r\u00e9s\u00e9re \u00e9s elemz\u00e9s\u00e9re haszn\u00e1lhat\u00f3.

ros2 run rqt_console rqt_console\n

"},{"location":"ros2halado/#rqt_tf_tree","title":"rqt_tf_tree","text":"

Az rqt_tf_tree a transzform\u00e1ci\u00f3k vizualiz\u00e1ci\u00f3j\u00e1ra haszn\u00e1lhat\u00f3.

ros2 run rqt_tf_tree rqt_tf_tree\n

"},{"location":"ros2halado/#rqt_reconfigure","title":"rqt_reconfigure","text":"

Az rqt_reconfigure a node-ok param\u00e9tereinek m\u00f3dos\u00edt\u00e1s\u00e1ra haszn\u00e1lhat\u00f3.

ros2 run rqt_reconfigure rqt_reconfigure\n

"},{"location":"ros2halado/#publish-subscribe-timer","title":"Publish, Subscribe, Timer","text":"

H\u00e1rom alapvet\u0151 m\u0171veletet c\u00e9lszer\u0171 ismerni, amelyeket a ROS 2-ben a node-ok haszn\u00e1lnak a kommunik\u00e1ci\u00f3hoz:

  • Timer: Id\u0151z\u00edtett esem\u00e9nyeket hoz l\u00e9tre a k\u00f6vetkez\u0151 p\u00e9ld\u00e1n\u00e1l ez a timer_callback() f\u00fcggv\u00e9ny. Ezen a f\u00fcggv\u00e9nyen bel\u00fcl p\u00e9ld\u00e1ul publik\u00e1lhatunk egy \u00fczenetet vagy elv\u00e9gezhet\u00fcnk egy sz\u00e1m\u00edt\u00e1st.
  • Subscribe: Feliratkozik egy topic-ra, \u00e9s fogadja az adatokat. Ezt \u00fagy \u00e9ri el, hogy a p\u00e9ld\u00e1n\u00e1l maradva a callback1() f\u00fcggv\u00e9ny minden \u00faj \u00fczenet \u00e9rkez\u00e9skor megh\u00edv\u00f3dik.
  • Publish: Adatokat k\u00fcld a topic-on kereszt\u00fcl. Ezt \u00e1ltal\u00e1ban ism\u00e9tl\u0151d\u0151en tesssz\u00fck, j\u00f3 lehet erre a subscriber callback f\u00fcggv\u00e9nye, vagy a timer callback f\u00fcggv\u00e9nye.
"},{"location":"ros2halado/#pelda-c","title":"P\u00e9lda C++","text":"
#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n#include \"rclcpp/rclcpp.hpp\"\n#include \"std_msgs/msg/float32.hpp\"\nusing namespace std::chrono_literals;\n\nclass CoolNode : public rclcpp::Node\n{\npublic:\n  CoolNode() : Node(\"my_cool_node\")\n  {\n    pub1_ = this->create_publisher<std_msgs::msg::Float32>(\"topic1\", 10);\n    sub1_ = this->create_subscription<std_msgs::msg::Float32>(\"topic2\", 10, std::bind(&CoolNode::callback1, this, std::placeholders::_1));\n    timer_ = this->create_wall_timer(50ms, std::bind(&CoolNode::timer_callback, this)); // 20 hz = 50 ms\n    RCLCPP_INFO_STREAM(get_logger(), this->get_name() << \" has been started.\");\n  }\n\nprivate:\n  void timer_callback()\n  {\n    // create message and publish e.g. pub1_->publish(my_msg);\n  }\n\n  void callback1(const std_msgs::msg::Float32::SharedPtr msg)\n  {\n    // do something with the message\n  }\n  rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr pub1_;\n  rclcpp::Subscription<std_msgs::msg::Float32>::SharedPtr sub1_;\n  rclcpp::TimerBase::SharedPtr timer_;\n};\n\nint main(int argc, char *argv[])\n{\n  rclcpp::init(argc, argv);\n  rclcpp::spin(std::make_shared<CoolNode>());\n  rclcpp::shutdown();\n  return 0;\n}\n
"},{"location":"ros2halado/#pelda-python","title":"P\u00e9lda python","text":"
import rclpy\nfrom rclpy.node import Node\nfrom std_msgs.msg import Float32\n\nclass CoolNode(Node):\n    def __init__(self):\n        super().__init__('my_cool_node')\n        self.pub1_ = self.create_publisher(Float32, 'topic1', 10)\n        self.sub1_ = self.create_subscription(Float32, 'topic2', 10, self.callback1)\n        self.timer_ = self.create_timer(0.05, self.timer_callback)  # 20 Hz = 50 ms\n        self.get_logger().info(f'{self.get_name()} has been started.')\n\n    def timer_callback(self):\n        # create message and publish e.g. self.pub1_.publish(my_msg)\n        pass\n\n    def callback1(self, msg):\n        # do something with the message\n        pass\n\ndef main(args=None):\n    rclpy.init(args=args)\n    node = CoolNode()\n    rclpy.spin(node)\n    rclpy.shutdown()\n\nif __name__ == '__main__':\n    main()\n
"},{"location":"ros2halado/#forrasok","title":"Forr\u00e1sok","text":"
  • foxglove.dev/blog/how-to-use-ros2-launch-files
  • youtube.com/watch?v=PqNGvmE2Pv4&t
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/RViz/RViz-User-Guide/RViz-User-Guide.html
"},{"location":"ros2halado/docker/","title":"Docker","text":"

Sz\u00e1mos tutorial \u00e9s le\u00edr\u00e1s \u00e9rhet\u0151 el a Docker haszn\u00e1lat\u00e1r\u00f3l, ebb\u0151l viszont kev\u00e9s f\u00f3kusz\u00e1l a robotik\u00e1ra.

"},{"location":"ros2halado/docker/#forrasok","title":"Forr\u00e1sok","text":"
  • articulatedrobotics.xyz
  • Youtube playlist articulatedrobotics
"},{"location":"ros2halado/mcap/","title":"MCAP f\u00e1jlok","text":""},{"location":"ros2halado/mcap/#mcap-fajlok","title":"MCAP f\u00e1jlok","text":"

Az ROS 2 az log adatokhoz az MCAP form\u00e1tumot haszn\u00e1lja. Ez a form\u00e1tum nem dedik\u00e1ltan az ROS saj\u00e1t form\u00e1tuma, hanem egy ny\u00edlt forr\u00e1sk\u00f3d\u00fa kont\u00e9nerf\u00e1jl t\u00edpus tetsz\u0151leges multimod\u00e1lis log-adatokhoz. T\u00e1mogatja az id\u0151b\u00e9lyegz\u0151vel ell\u00e1tott, el\u0151re sorba rendezett adatokat. \u00cdgy ide\u00e1lis a pub/sub vagy robotikai alkalmaz\u00e1sokban val\u00f3 haszn\u00e1latra is, a ROS 2 is ez\u00e9rt d\u00f6nt\u00f6tt mellette. A k\u00f6vetkez\u0151kben arr\u00f3l lesz sz\u00f3, hogyan lehets\u00e9ges a form\u00e1tum C++, Go, Python, Rust, Swift vagy TypeScript nyelven t\u00f6rt\u00e9n\u0151 szerkeszt\u00e9se. Illetve egy python p\u00e9ld\u00e1n kereszt\u00fcl gyakorlati oldalr\u00f3l is szeml\u00e9ltetj\u00fck ezt.

Az MCAP egy fejlett logf\u00e1jlform\u00e1tum, amely kifejezetten a pub/sub \u00fczenetek \u00e9s multimod\u00e1lis szenzoradatok id\u0151b\u00e9lyeggel ell\u00e1tott csatorn\u00e1inak t\u00e1rol\u00e1s\u00e1ra szolg\u00e1l. Nem k\u00f6t\u0151dik egyetlen soros\u00edt\u00e1si form\u00e1tumhoz sem, \u00edgy k\u00e9pes b\u00e1rmilyen form\u00e1tum\u00fa bin\u00e1ris \u00fczenetek, p\u00e9ld\u00e1ul Protobuf, DDS (CDR), ROS, JSON \u00e9s m\u00e1sok r\u00f6gz\u00edt\u00e9s\u00e9re \u00e9s visszaj\u00e1tsz\u00e1s\u00e1ra. Az MCAP nagy teljes\u00edtm\u00e9ny\u0171 \u00edr\u00e1st tesz lehet\u0151v\u00e9 a sororient\u00e1lt, csak hozz\u00e1f\u0171z\u0151 tervez\u00e9s\u00e9nek k\u00f6sz\u00f6nhet\u0151en, amely minimaliz\u00e1lja a lemez I/O m\u0171veleteket \u00e9s cs\u00f6kkenti az adatveszt\u00e9s kock\u00e1zat\u00e1t nem tiszta le\u00e1ll\u00edt\u00e1sok eset\u00e9n.

Az MCAP \u00f6n\u00e1ll\u00f3 form\u00e1tum, mivel az \u00fczenetek s\u00e9m\u00e1it is az adatok mellett t\u00e1rolja, \u00edgy a f\u00e1jlok a j\u00f6v\u0151ben is olvashat\u00f3ak maradnak, m\u00e9g akkor is, ha a k\u00f3db\u00e1zis id\u0151k\u00f6zben v\u00e1ltozik. Az MCAP f\u00e1jlok opcion\u00e1lis indexet tartalmaznak, ami gyors \u00e9s hat\u00e9kony adatolvas\u00e1st tesz lehet\u0151v\u00e9, m\u00e9g alacsony s\u00e1vsz\u00e9less\u00e9g\u0171 internetkapcsolaton kereszt\u00fcl is. Opcion\u00e1lis t\u00f6m\u00f6r\u00edt\u00e9st is k\u00edn\u00e1l, p\u00e9ld\u00e1ul LZ4 vagy Zstandard form\u00e1j\u00e1ban, mik\u00f6zben tov\u00e1bbra is t\u00e1mogatja a hat\u00e9kony indexelt olvas\u00e1st.

Az MCAP sz\u00e9les k\u00f6r\u0171 nyelvi t\u00e1mogat\u00e1st ny\u00fajt, nat\u00edv olvas\u00f3 \u00e9s \u00edr\u00f3 k\u00f6nyvt\u00e1rakkal C++, Go, Python, Rust, Swift \u00e9s TypeScript nyelveken. A form\u00e1tum rugalmasan konfigur\u00e1lhat\u00f3 opcion\u00e1lis funkci\u00f3kkal, mint a darabol\u00e1s, indexel\u00e9s, CRC ellen\u0151rz\u0151\u00f6sszegek \u00e9s t\u00f6m\u00f6r\u00edt\u00e9s, hogy a megfelel\u0151 kompromisszumokat k\u00edn\u00e1lja az adott alkalmaz\u00e1shoz. Az MCAP gy\u00e1rt\u00e1sra k\u00e9sz form\u00e1tum, amelyet sz\u00e9les k\u00f6rben haszn\u00e1lnak k\u00fcl\u00f6nb\u00f6z\u0151 c\u00e9gek, p\u00e9ld\u00e1ul auton\u00f3m j\u00e1rm\u0171vek \u00e9s dr\u00f3nok eset\u00e9ben, \u00e9s ez az alap\u00e9rtelmezett logform\u00e1tum a ROS 2-ben.

Az MCAP f\u00e1jlform\u00e1tum ROS 2 agnosztikus, teh\u00e1t nem f\u00fcgg mag\u00e1t\u00f3l az ROS 2-t\u0151l, \u00edgy b\u00e1rmilyen Python projektben haszn\u00e1lhat\u00f3. Fontos megjegyezni, hogy a rosbag2-api python csomag viszont ROS 2 f\u00fcgg\u0151. \u00cdgy c\u00e9lszer\u0171 ink\u00e1bb az mcap-ros2-support python csomag haszn\u00e1lata, amely nem ig\u00e9nyel ROS 2-t, \u00edgy p\u00e9ld\u00e1ul Windowson is futtathat\u00f3.

A Python MCAP ROS2 support csomag (mcap-ros2-support) lehet\u0151v\u00e9 teszi a ROS2 t\u00e1mogat\u00e1st a Python MCAP f\u00e1jlform\u00e1tum olvas\u00f3 sz\u00e1m\u00e1ra. Telep\u00edts\u00fck a k\u00f6vetkez\u0151 parancshoz hasonl\u00f3 m\u00f3don:

pip install mcap mcap-ros2-support matplotlib numpy pandas scipy\n
"},{"location":"ros2halado/mcap/#mcap-fajl-olvasasa-pelda","title":"MCAP f\u00e1jl olvas\u00e1sa p\u00e9lda","text":"

A github.com/jkk-research/jkk_utils/tree/ros2/mcap_scripts el\u00e9r\u00e9sen t\u00f6bb hasonl\u00f3 p\u00e9lda is megtal\u00e1lhat\u00f3:

from mcap_ros2.decoder import DecoderFactory\nfrom mcap.reader import make_reader\ndef main():\n    with open('C:\\\\temp\\\\test.mcap', \"rb\") as f:\n        reader = make_reader(f, decoder_factories=[DecoderFactory()])\n        #list all topics and types\n        channels = reader.get_summary().channels.items()\n        print(\"Available topics are the following:\")\n        for index, (channel_key, channel_value) in enumerate(channels):\n            print(\"%2d. topic: %s\" % (index+1, channel_value.topic))\n
"},{"location":"ros2halado/mcap/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/How-To-Guides/Visualizing-ROS-2-Data-With-Foxglove-Studio.html
  • github.com/jkk-research/jkk_utils/tree/ros2/mcap_scripts
  • mcap.dev
  • mcap.dev/docs/python/raw_reader_writer_example
  • pypi.org/project/mcap-ros2-support (\u2714\ufe0f recommended, no ROS 2 dependency)
  • pypi.org/project/rosbag2-api (\u274c ROS 2 dependency)
"},{"location":"ros2halado/pointcloud_to_grid/","title":"pointcloud_to_grid ROS 2 package","text":"

This package converts sensor_msgs/PointCloud2 LIDAR data to nav_msgs/OccupancyGrid 2D map data based on intensity and / or height.

Link: github.com/jkk-research/pointcloud_to_grid

"},{"location":"ros2halado/py_cpp/","title":"Python \u00e9s C++ \u00f6sszehasonl\u00edt\u00e1sa","text":"PythonC++
#  ros2 topic type /lexus3/gps/duro/current_pose\n#  geometry_msgs/msg/PoseStamped\n#  ros2 interface show geometry_msgs/msg/PoseStamped\n\nimport rclpy\nfrom rclpy.node import Node\nfrom geometry_msgs.msg import PoseStamped\n\n\nclass SimplePoseSub(Node):\n\n    def __init__(self):\n        super().__init__('simple_pose_sub')\n        self.sub1_ = self.create_subscription(PoseStamped, '/lexus3/gps/duro/current_pose', self.topic_callback, 10)\n\n\n\n    def topic_callback(self, msg):\n\n        self.get_logger().info('x: %.3f, y: %.3f', msg.pose.position.x, msg.pose.position.y)\n\n\n\n\ndef main(args=None):\n\n    rclpy.init(args=args)                   ## Initialize the ROS 2 client library\n    simple_pose_sub = SimplePoseSub()\n    rclpy.spin(simple_pose_sub)             ## Create a node and spin\n    simple_pose_sub.destroy_node()\n    rclpy.shutdown()                        ## Shutdown the ROS 2 client library\n\nif __name__ == '__main__':\n    main()\n
// ros2 topic type /lexus3/gps/duro/current_pose\n// geometry_msgs/msg/PoseStamped\n// ros2 interface show geometry_msgs/msg/PoseStamped\n\n#include \"rclcpp/rclcpp.hpp\"\n#include <memory>\n#include \"geometry_msgs/msg/pose_stamped.hpp\"\nusing std::placeholders::_1;\n\nclass SimplePoseSub : public rclcpp::Node{\npublic:\n    SimplePoseSub() : Node(\"simple_pose_sub\")\n    {\n        sub1_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(\"/lexus3/gps/duro/current_pose\", 10, std::bind(&SimplePoseSub::topic_callback, this, _1));\n    }\n\nprivate:\n    void topic_callback(const geometry_msgs::msg::PoseStamped &msg) const\n    {\n        RCLCPP_INFO(this->get_logger(), \"x: %.3f, y: %.3f\", msg.pose.position.x, msg.pose.position.y);\n    }\n    rclcpp::Subscription<geometry_msgs::msg::PoseStamped>::SharedPtr sub1_;\n    };\n\nint main(int argc, char *argv[])\n{\n    rclcpp::init(argc, argv);               // Initialize the ROS 2 client library\n    rclcpp::spin(\n        std::make_shared<SimplePoseSub>()); // Create a node and spin\n\n    rclcpp::shutdown();                     // Shutdown the ROS 2 client library\n    return 0;\n\n}\n
"},{"location":"ros2halado/qos/","title":"DDS protokoll","text":"

A DDS (Data Distribution Service) az Object Management Group (OMG) \u00e1ltal standardiz\u00e1lt kommuink\u00e1ci\u00f3s protokoll.

A DDS protokoll sz\u00e9les k\u00f6rben haszn\u00e1lt az ipari automatiz\u00e1l\u00e1sban, a h\u00e1l\u00f3zatos\u00edtott rendszerekben \u00e9s m\u00e1s ter\u00fcleteken, ahol az elosztott adatkommunik\u00e1ci\u00f3 \u00e9s a val\u00f3s idej\u0171 adatfeldolgoz\u00e1s kiemelt fontoss\u00e1ggal b\u00edr. DDS-\u00e1tvitel rugalmass\u00e1g\u00e1b\u00f3l profit\u00e1l vesztes\u00e9ges vezet\u00e9k n\u00e9lk\u00fcli h\u00e1l\u00f3zatokkal rendelkez\u0151 k\u00f6rnyezetekben, ahol a \"legjobb er\u0151fesz\u00edt\u00e9s\" (best effort) elv lenne megfelel\u0151bb vagy val\u00f3s idej\u0171 sz\u00e1m\u00edt\u00e1stechnikai rendszerekben, ahol pedig a megfelel\u0151 min\u0151s\u00e9g. Az id\u0151z\u00edt\u00e9sek betart\u00e1s\u00e1hoz sz\u00fcks\u00e9g van a szolg\u00e1ltat\u00e1si profilra. A QoS \"h\u00e1zirendek\" halmaza egy QoS \"profilt\" alkot. Tekintettel az adott forgat\u00f3k\u00f6nyvh\u00f6z megfelel\u0151 QoS-ir\u00e1nyelvek kiv\u00e1laszt\u00e1s\u00e1nak bonyolults\u00e1g\u00e1ra, a kommunik\u00e1ci\u00f3 el\u0151re defini\u00e1lt QoS-profilokat biztos\u00edt \u00e1ltal\u00e1nos haszn\u00e1lati esetekre (pl. szenzoradatok).

"},{"location":"ros2halado/qos/#szolgaltatasminoseg-qos","title":"Szolg\u00e1ltat\u00e1smin\u0151s\u00e9g (QoS)","text":"

A szolg\u00e1ltat\u00e1smin\u0151s\u00e9g angol sz\u00f3val Quality of Service vagy r\u00f6viden QoS. Az alap QoS-profil a k\u00f6vetkez\u0151 h\u00e1zirendek be\u00e1ll\u00edt\u00e1sait tartalmazza:

"},{"location":"ros2halado/qos/#mult-history","title":"M\u00falt (history)","text":"
  • Utols\u00f3 megtart\u00e1sa (keep last): legfeljebb N mint\u00e1t t\u00e1rolhat, a sorm\u00e9lys\u00e9g opci\u00f3val konfigur\u00e1lhat\u00f3.
  • Mind megtart\u00e1sa (keep all): az \u00f6sszes mint\u00e1t t\u00e1rolja, az alapul szolg\u00e1l\u00f3 k\u00f6ztes szoftver konfigur\u00e1lt er\u0151forr\u00e1s-korl\u00e1tjait\u00f3l f\u00fcgg\u0151en.
"},{"location":"ros2halado/qos/#melyseg-depth","title":"M\u00e9lys\u00e9g (depth)","text":"
  • Sor m\u00e9rete: csak akkor teljes\u00fcl, ha az \"el\u0151zm\u00e9nyek\" h\u00e1zirend \"utols\u00f3 meg\u0151rz\u00e9sre\" van \u00e1ll\u00edtva.
"},{"location":"ros2halado/qos/#megbizhatosag-relyability","title":"Megb\u00edzhat\u00f3s\u00e1g (relyability)","text":"
  • Legjobb er\u0151fesz\u00edt\u00e9s (best effort): pr\u00f3b\u00e1ljon meg mint\u00e1kat sz\u00e1ll\u00edtani, de elvesz\u00edtheti azokat, ha a h\u00e1l\u00f3zat nem robusztus.
  • Megb\u00edzhat\u00f3 (reliable): garant\u00e1lja a mint\u00e1k kisz\u00e1ll\u00edt\u00e1s\u00e1t, t\u00f6bbsz\u00f6r is pr\u00f3b\u00e1lkozhat.
"},{"location":"ros2halado/qos/#tartossag-durability","title":"Tart\u00f3ss\u00e1g (durability)","text":"
  • \u00c1tmeneti helyi (transient local): a kiad\u00f3 felel\u0151s a \u201ek\u00e9s\u0151n csatlakoz\u00f3\u201d el\u0151fizet\u00e9sek tart\u00f3s mint\u00e1i\u00e9rt.
  • Ill\u00e9kony: nem t\u00f6rt\u00e9nik k\u00eds\u00e9rlet a mint\u00e1k fennmarad\u00e1s\u00e1ra.
"},{"location":"ros2halado/qos/#hatarido-idozites-deadline","title":"Hat\u00e1rid\u0151, id\u0151z\u00edt\u00e9s (deadline)","text":"
  • Id\u0151tartam: a v\u00e1rhat\u00f3 maxim\u00e1lis id\u0151tartam a k\u00f6vetkez\u0151 \u00fczenetek k\u00f6zz\u00e9t\u00e9tele k\u00f6z\u00f6tt egy t\u00e9m\u00e1ban
"},{"location":"ros2halado/qos/#elettartam-lifespan","title":"\u00c9lettartam (lifespan)","text":"
  • Id\u0151tartam: az \u00fczenet k\u00f6zz\u00e9t\u00e9tele \u00e9s fogad\u00e1sa k\u00f6z\u00f6tti maxim\u00e1lis id\u0151tartam an\u00e9lk\u00fcl, hogy az \u00fczenet elavultnak vagy lej\u00e1rtnak min\u0151s\u00fclne (a lej\u00e1rt \u00fczeneteket a rendszer eldobja, \u00e9s gyakorlatilag soha nem \u00e9rkezik meg).
"},{"location":"ros2halado/qos/#elenkseg-liveliness","title":"\u00c9l\u00e9nks\u00e9g (liveliness)","text":"
  • Automatikus: a rendszer a node \u00f6sszes publisherj\u00e9t \u00e9l\u0151nek tekinti egy \u00fajabb \"elenged\u00e9si id\u0151tartamra\", ha valamelyik kiad\u00f3ja k\u00f6zz\u00e9tett egy \u00fczenetet.
  • Manu\u00e1lis: a rendszer a publishert egy m\u00e1sik \" elenged\u00e9si id\u0151tartamra\" \u00e9l\u0151nek tekinti, ha manu\u00e1lisan (a publisher API-j\u00e1nak h\u00edv\u00e1s\u00e1val) azt \u00e1ll\u00edtja, hogy m\u00e9g \u00e9letben van.
"},{"location":"ros2halado/qos/#elengedesi-idotartam-lease-duration","title":"Elenged\u00e9si id\u0151tartam (lease duration)","text":"
  • Id\u0151tartam: az a maxim\u00e1lis id\u0151tartam, ameddig a kommunik\u00e1ci\u00f3s ad\u00f3nak jeleznie kell, hogy \u00e9letben van, miel\u0151tt a rendszer \u00fagy \u00edt\u00e9ln\u00e9 meg, hogy elvesztette az \u00e9l\u0151s\u00e9g\u00e9t.
"},{"location":"ros2halado/qos/#qos-kompatibilitas","title":"QoS kompatibilit\u00e1s","text":""},{"location":"ros2halado/qos/#gyakorlat","title":"Gyakorlat","text":""},{"location":"ros2halado/qos/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Concepts/Intermediate/About-Quality-of-Service-Settings.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
"},{"location":"ros2halado/ros2launch/","title":"ROS 2 launch \u00e9s ROS 2 egy\u00e9b halad\u00f3 koncepci\u00f3k","text":""},{"location":"ros2halado/ros2launch/#bevezeto","title":"Bevezet\u0151","text":"

Az ROS 2 launch rendszere seg\u00edti a felhaszn\u00e1l\u00f3 \u00e1ltal defini\u00e1lt rendszer konfigur\u00e1ci\u00f3j\u00e1nak megad\u00e1s\u00e1t, majd a konfigur\u00e1ci\u00f3 szerinti v\u00e9grehajt\u00e1s\u00e1t. A konfigur\u00e1ci\u00f3s l\u00e9p\u00e9s a k\u00f6vetkez\u0151ket tartalmazza:

  • mely programok ker\u00fcljenek futtat\u00e1sra,
  • milyen argumentumokat kapjanak a futtatott programok,
  • ROS-specifikus konvenci\u00f3knak megfelel\u0151 \u00f6sszetev\u0151k, amelyek a komponensek k\u00f6nny\u0171 \u00fajrahasznos\u00edthat\u00f3s\u00e1g\u00e1t teszik lehet\u0151v\u00e9.

Fontos megeml\u00edteni tov\u00e1bb\u00e1, hogy a megold\u00e1s fel\u00fcgyeli az elind\u00edtott folyamatokat, \u00e9s k\u00e9pes reag\u00e1lni a folyamatok fut\u00e1si \u00e1llapot\u00e1ban bek\u00f6vetkez\u0151 v\u00e1ltoz\u00e1sokra.

Launch f\u00e1jlok k\u00e9sz\u00edt\u00e9se t\u00f6rt\u00e9nhet Python, XML, vagy YAML seg\u00edts\u00e9g\u00e9vel.

"},{"location":"ros2halado/ros2launch/#elokeszuletek","title":"El\u0151k\u00e9sz\u00fcletek","text":""},{"location":"ros2halado/ros2launch/#hozzuk-letre-a-example_launch_cpp-package-t","title":"Hozzuk l\u00e9tre a example_launch_cpp package-t","text":"

Ha esetleg m\u00e1r l\u00e9tezne a example_launch_cpp package akkor t\u00f6r\u00f6lj\u00fck. (G\u00e9pteremben elk\u00e9pzelehet\u0151, hogy el\u0151z\u0151 f\u00e9l\u00e9vben valaki l\u00e9trehozta.)

cd ~ && test -d \"ros2_ws/src/example_launch_cpp\" && echo Letezik || echo Nem letezik\n
rm -r  ~/ros2_ws/src/example_launch_cpp\n

Nyissunk egy \u00faj termin\u00e1lt, \u00e9s source-oljuk a telep\u00edt\u00e9st (ha nincs bashrc-ben), hogy a ros2 parancsok m\u0171k\u00f6djenek.

Navig\u00e1ljunk az m\u00e1r l\u00e9trehozott ros2_ws k\u00f6nyvt\u00e1rba.

Fontos, hogy a csomagokat az src k\u00f6nyvt\u00e1rban kell l\u00e9trehozni, nem a munkater\u00fclet gy\u00f6ker\u00e9ben. Teh\u00e1t navig\u00e1ljunk a ros2_ws/src mapp\u00e1ba, \u00e9s futtassuk a package l\u00e9trehoz\u00f3 parancsot:

cd ~/ros2_ws/src\n
ros2 pkg create --build-type ament_cmake example_launch_cpp\n

A termin\u00e1l egy \u00fczenetet k\u00fcld vissza, amely meger\u0151s\u00edti a example_launch_cpp csomag \u00e9s az \u00f6sszes sz\u00fcks\u00e9ges f\u00e1jl \u00e9s mappa l\u00e9trehoz\u00e1s\u00e1t.

"},{"location":"ros2halado/ros2launch/#launch-mappa","title":"Launch mappa","text":"

Hozzunk l\u00e9tre egy mapp\u00e1t a launch f\u00e1jlok r\u00e9sz\u00e9re:

cd ~/ros2_ws/src/example_launch_cpp\n
mkdir launch\n
"},{"location":"ros2halado/ros2launch/#launch-fajl-letrehozasa","title":"Launch f\u00e1jl l\u00e9trehoz\u00e1sa","text":"
cd launch\n
code turtlesim_mimic_launch.py\n

\u00c1ll\u00edtsunk \u00f6ssze egy launch f\u00e1jlt a turtlesim csomag elemeivel, Python nyelv alkalmaz\u00e1s\u00e1val.

PythonXML
from launch import LaunchDescription\nfrom launch_ros.actions import Node\n\ndef generate_launch_description():\n    return LaunchDescription([\n        Node(\n            package='turtlesim',\n            namespace='turtlesim1',\n            executable='turtlesim_node',\n        ),\n        Node(\n            package='turtlesim',\n            namespace='turtlesim2',\n            executable='turtlesim_node',\n            name='turtle2_green',\n            parameters=[{'background_b': 160, 'background_g': 230, 'background_r': 0}],\n        ),\n        Node(\n            package='turtlesim',\n            executable='mimic',\n            name='mimic',\n            remappings=[\n                ('/input/pose', '/turtlesim1/turtle1/pose'),\n                ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),\n            ]\n        )\n    ])\n
<launch>\n    <node\n        pkg=\"turtlesim\"\n        ns=\"turtlesim1\"\n        exec=\"turtlesim_node\"\n        name=\"turtle1\"/>\n\n    <node\n        pkg=\"turtlesim\"\n        ns=\"turtlesim2\"\n        exec=\"turtlesim_node\"\n        name=\"turtle2_green\">\n        <param name=\"background_b\" value=\"160\"/>\n        <param name=\"background_g\" value=\"230\"/>\n        <param name=\"background_r\" value=\"0\"/>\n    </node>\n\n    <node\n        pkg=\"turtlesim\"\n        exec=\"mimic\"\n        name=\"mimic\">\n        <remap from=\"/input/pose\" to=\"/turtlesim1/turtle1/pose\"/>\n        <remap from=\"/output/cmd_vel\" to=\"/turtlesim2/turtle1/cmd_vel\"/>\n    </node>\n</launch>\n

A fent le\u00edrt m\u00f3don l\u00e9trehozott launch f\u00e1jl a kor\u00e1bbiakban megismert turtlesim csomag h\u00e1rom node-j\u00e1t ind\u00edtja el. A c\u00e9l k\u00e9t turtlesim ablak megnyit\u00e1sa, majd az egyik tekn\u0151s mozg\u00e1s\u00e1nak megism\u00e9tl\u00e9se a m\u00e1sik tekn\u0151ssel. A k\u00e9t turtlesim node ind\u00edt\u00e1s\u00e1ban mind\u00f6ssze a n\u00e9vt\u00e9r (namespace) t\u00e9r el. Az egyedi n\u00e9vterek alkalmaz\u00e1sa lehet\u0151v\u00e9 teszi k\u00e9t azonos node egyidej\u0171 elind\u00edt\u00e1s\u00e1t n\u00e9vkonfliktus n\u00e9lk\u00fcl. \u00cdgy mindk\u00e9t tekn\u0151s ugyanazon a topicon fogad utas\u00edt\u00e1sokat, \u00e9s ugyanazon a topicon k\u00f6zli a helyzet\u00e9t. Az egy\u00e9ni n\u00e9vterek lehet\u0151v\u00e9 teszik a k\u00e9t tekn\u0151s \u00fczeneteinek megk\u00fcl\u00f6nb\u00f6ztet\u00e9s\u00e9t.

Az utols\u00f3 node szint\u00e9n a turtlesim csomagb\u00f3l van, viszont a futtathat\u00f3 f\u00e1jl elt\u00e9r: mimic. Ez a csom\u00f3pont ki van eg\u00e9sz\u00edtve n\u00e9vmegfeleltet\u00e9sekkel. P\u00e9ld\u00e1ul az egyszer\u0171 /input/pose megfelel\u0151je ezesetben /turtlesim1/turtle1/pose \u00e9s a kor\u00e1bban megismert /output/cmd_vel most /turtlesim2/turtle1/cmd_vel. Ez azt jelenti, hogy mimic feliratkozik a /turtlesim1/sim pose topic-ra, \u00e9s \u00fajra publisholja \u00fagy, hogy /turtlesim2/sim sebess\u00e9g utas\u00edt\u00e1sa feliratkozzon r\u00e1. Teh\u00e1t, turtlesim2 ut\u00e1nozni fogja turtlesim1 mozg\u00e1s\u00e1t.

"},{"location":"ros2halado/ros2launch/#kod-reszleteinek-attekintese","title":"K\u00f3d r\u00e9szleteinek \u00e1ttekint\u00e9se","text":"

Ezek a kifejez\u00e9sek Python launch modulokat import\u00e1lnak.

from launch import LaunchDescription\nfrom launch_ros.actions import Node\n

Ezt k\u00f6vet\u0151en kezd\u0151dik a launch le\u00edr\u00e1sa:

def generate_launch_description():\n  return LaunchDescription([\n\n  ])\n

A launch le\u00edr\u00e1sban szerepl\u0151 els\u0151 k\u00e9t utas\u00edt\u00e1s ind\u00edtja a k\u00e9t turtlesim ablakot:

Node(\n    package='turtlesim',\n    namespace='turtle1',\n    executable='turtlesim_node',\n),\nNode(\n    package='turtlesim',\n    namespace='turtle2',\n    executable='turtlesim_node',\n    name='turtle2_green',\n    parameters=[{'background_b': 160, 'background_g': 230, 'background_r': 0}],\n),\n

V\u00e9g\u00fcl megt\u00f6rt\u00e9nik a mozg\u00e1s ut\u00e1nz\u00e1s\u00e1t megval\u00f3s\u00edt\u00f3 node ind\u00edt\u00e1sa is:

Node(\n    package='turtlesim',\n    executable='mimic',\n    name='mimic',\n    remappings=[\n      ('/input/pose', '/turtlesim1/turtle1/pose'),\n      ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),\n    ]\n)\n
"},{"location":"ros2halado/ros2launch/#ros2-launch-hasznalata","title":"ROS2 launch haszn\u00e1lata","text":"

A l\u00e9trehozott launch f\u00e1jl elind\u00edt\u00e1sa az al\u00e1bbi m\u00f3don t\u00f6rt\u00e9nik:

cd ~/ros2_ws/src/example_launch_cpp/launch # bel\u00e9p\u00fcnk a launch f\u00e1jlt tartalmaz\u00f3 mapp\u00e1ba\n
ros2 launch turtlesim_mimic_launch.py\n

K\u00e9t turtlesim ablak fog megny\u00edlni, \u00e9s a k\u00f6vetkez\u0151 [INFO] kimenet lesz l\u00e1that\u00f3, felsorolva az ind\u00edtott node-okat:

[INFO] [launch]: Default logging verbosity is set to INFO\n[INFO] [turtlesim_node-1]: process started with pid [11714]\n[INFO] [turtlesim_node-2]: process started with pid [11715]\n[INFO] [mimic-3]: process started with pid [11716]\n

Hogy kipr\u00f3b\u00e1ljuk az elind\u00edtott rendszer m\u0171k\u00f6d\u00e9s\u00e9t, egy \u00faj termin\u00e1lban hirdess\u00fcnk olyan \u00fczenetet, amellyel a turtle1 mozgathat\u00f3:

ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist \"{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}\"\n

A fent bemutatott direkt m\u00f3don k\u00edv\u00fcl egy launch f\u00e1jl futtathat\u00f3 csomag \u00e1ltal is:

ros2 launch <csomag_megnevez\u00e9se> <launch_f\u00e1jl_neve>\n

Olyan csomagok eset\u00e9ben, amelyek launch f\u00e1jlt tartalmaznak, \u00e9rdemes l\u00e9trehozni egy exec_depend f\u00fcgg\u0151s\u00e9get a ros2launch csomagra vonatkoz\u00f3an a csomag package.xml f\u00e1jlj\u00e1ban:

<exec_depend>ros2launch</exec_depend>\n

Ezzel biztos\u00edthat\u00f3, hogy az ros2 launch parancs el\u00e9rhet\u0151 a csomag buildel\u00e9se ut\u00e1n.

"},{"location":"ros2halado/ros2launch/#tanulmanyozzuk-az-elinditott-rendszert","title":"Tanulm\u00e1nyozzuk az elind\u00edtott rendszert","text":"

\u00dagy, hogy minden eddig elind\u00edtott node fut, egy \u00fajabb termin\u00e1lban futtassuk az rqt_graph eszk\u00f6zt, amely grafikusan szeml\u00e9lteti a launch f\u00e1jl seg\u00edts\u00e9g\u00e9vel kialak\u00edtott rendszert:

rqt_graph\n

vagy a ros2 run paranccsal:

ros2 run rqt_graph rqt_graph\n
graph TD\n    T1([turtlesim1/turtlesim]):::red --> P1[ /turtlesim1/turtle1/pose]:::light --> M1([mimic]):::red\n    M1 --> C2[ /turtlesim2/turtle1/cmd_vel]:::light \n    C2 --> T2([turtlesim2/turtle2_green]):::red \n\n    n1([ /node]):::white -- publishes --> t[ /topic]:::white\n    t -- subscribes --> n2([ /node]):::white\n\n\n    classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \n    classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\n    classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\n    classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"ros2halado/ros2launch/#adjuk-hozza-a-package-hez-hogy-barhonnan-indithassuk","title":"Adjuk hozz\u00e1 a package-hez, hogy b\u00e1rhonnan ind\u00edthassuk","text":"
cd ~/ros2_ws/src/example_launch_cpp\n
code .\n
VS code f\u00e1jlok

A package.xml-hez a <test_depend> el\u00e9 sz\u00farjuk be k\u00f6vetkez\u0151 sort:

<exec_depend>ros2launch</exec_depend>\n

A CMakeLists.txt-hez a ament_package() el\u00e9 sz\u00farjuk be k\u00f6vetkez\u0151 2 sort:

install(DIRECTORY launch\n  DESTINATION share/${PROJECT_NAME})\n

Buildelj\u00fck a szok\u00e1so m\u00f3don:

cd ~/ros2_ws\n
colcon build --packages-select example_launch_cpp --symlink-install\n
\n
source ~/ros2_ws/install/setup.bash\n

Ez a parancs most m\u00e1r b\u00e1rhonnan kiadhat\u00f3:

ros2 launch example_launch_cpp turtlesim_mimic_launch.py\n
"},{"location":"ros2halado/ros2launch/#hazi-feladat","title":"H\u00e1zi feladat","text":"

H\u00e1zi feladat

K\u00e9sz\u00edts egy launch f\u00e1jlt, amely a turtlesim csomagb\u00f3l elind\u00edt egy turtlesim ablakot, \u00e9s egy teleop_turtle csomagb\u00f3l egy teleop_turtle_keyboard node-ot. A teleop_turtle_keyboard node seg\u00edts\u00e9g\u00e9vel a turtlesim ablakban mozgathat\u00f3 a tekn\u0151s a billenty\u0171zetr\u0151l. A turtlesim h\u00e1ttere legyen piros. K\u00e9sz\u00edts\u00fcnk hozz\u00e1 egy example_launch_py python csomagot, \u00e9s ind\u00edtsuk el a launch f\u00e1jlt a csomagb\u00f3l.

"},{"location":"ros2halado/ros2launch/#megjegyzes-python-csomagok-eseten","title":"Megjegyz\u00e9s python csomagok eset\u00e9n","text":"

Amennyiben SetuptoolsDeprecationWarning: setup.py install is deprecated hiba\u00fczenetet kapunk, akkor a setuptools csomag downgrade-el\u00e9se sz\u00fcks\u00e9ges. Ellen\u0151rizz\u00fck a setuptools csomag verzi\u00f3j\u00e1t:

pip3 list | grep setuptools\n

Ha az eredm\u00e9ny \u00fajabb, mint 58.2.0, akkor downgrade-elni kell a setuptools csomagot:

pip install setuptools==58.2.0\n
"},{"location":"ros2halado/ros2launch/#forrasok","title":"Forr\u00e1sok","text":"
  • foxglove.dev/blog/how-to-use-ros2-launch-files
  • youtube.com/watch?v=PqNGvmE2Pv4&t
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-Your-First-ROS2-Package.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html
  • docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Publisher-And-Subscriber.html
"},{"location":"ros2halado/rqt/","title":"rqt haszn\u00e1lata","text":""},{"location":"ros2halado/rqt/#rqt_console-a-log-uzenetek-megjelenitesre","title":"rqt_console a log \u00fczenetek megjelen\u00edt\u00e9sre","text":""},{"location":"ros2halado/rqt/#rqt_tf_tree-a-transzformaciok-vizualizaciojara","title":"rqt_tf_tree a transzform\u00e1ci\u00f3k vizualiz\u00e1ci\u00f3j\u00e1ra","text":""},{"location":"ros2halado/rqt/#rqt_graph-a-node-ok-es-topic-ok-vizualizaciojara","title":"rqt_graph a node-ok \u00e9s topic-ok vizualiz\u00e1ci\u00f3j\u00e1ra","text":""},{"location":"ros2halado/rqt/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Using-Rqt-Console/Using-Rqt-Console.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Broadcaster-Cpp.html
"},{"location":"ros2halado/state/","title":"Behavior tree","text":"

Forr\u00e1s: www.behaviortree.dev

"},{"location":"ros2halado/state/#allapotgepek-state-machine","title":"\u00c1llapotg\u00e9pek (State machine)","text":"

Forr\u00e1s: github.com/jbreckmckye/robot3-viz

"},{"location":"ros2halado/state/#forrasok","title":"Forr\u00e1sok","text":"
  • www.behaviortree.dev/docs/Intro
  • en.wikipedia.org/wiki/Finite-state_machine
  • github.com/jbreckmckye/robot3-viz
"},{"location":"ros2halado/vizualizacio/","title":"ROS 2 vizualiz\u00e1ci\u00f3","text":""},{"location":"ros2halado/vizualizacio/#visualization_msgsmsgmarker-tipus","title":"visualization_msgs/msg/Marker t\u00edpus","text":"

visualization_msgs/msg/Marker dokument\u00e1ci\u00f3

"},{"location":"ros2halado/vizualizacio/#visualization_msgsmsgmarkerarray-tipus","title":"visualization_msgs/msg/MarkerArray t\u00edpus","text":"

visualization_msgs/msg/MarkerArray dokument\u00e1ci\u00f3

"},{"location":"ros2halado/vizualizacio/#mesh","title":"Mesh","text":"
git clone https://github.com/szenergy/rviz_markers\ngit checkout ros2-humble\ncd ~/ros2_ws \ncolcon build --packages-select rviz_markers\nsource ~/ros2_ws/install/setup.bash\n

A mesheket Foxglove Studio-ban is megjelen\u00edthetj\u00fck, csak \u00e1ll\u00edtsuk a package path-t a megfelel\u0151 helyre, pl:

"},{"location":"ros2halado/vizualizacio/#szinek","title":"Sz\u00ednek","text":"

A Google Material Design sz\u00ednrendszer egy \u00e1tfog\u00f3 tervez\u00e9si rendszer, amely pl. ROS-ban \u00e9s Rviz-ben is haszn\u00e1lhat\u00f3. A k\u00e9nyelem kedv\u00e9\u00e9rt a k\u00f6vetkez\u0151kben felsoroljuk a hexadecim\u00e1lis \u00e9rt\u00e9keket (pl. #F44336) \u00e9s az rgb-v\u00e9 alak\u00edtott \u00e9rt\u00e9keket (pl. 0,96 0,26 0,21), ami a ROS 2-ben \u00e1ltal\u00e1nosan elfogadott.

B\u0151vebben: - github.com/jkk-research/colors

100 500 900 1.00 0.80 0.82 md_red_100 0.96 0.26 0.21 md_red_500 0.72 0.11 0.11 md_red_900 0.97 0.73 0.82 md_pink_100 0.91 0.12 0.39 md_pink_500 0.53 0.05 0.31 md_pink_900 0.82 0.77 0.91 md_deep_purple_100 0.40 0.23 0.72 md_deep_purple_500 0.19 0.11 0.57 md_deep_purple_900 0.73 0.87 0.98 md_blue_100 0.13 0.59 0.95 md_blue_500 0.05 0.28 0.63 md_blue_900 0.70 0.87 0.86 md_teal_100 0.00 0.59 0.53 md_teal_500 0.00 0.30 0.25 md_teal_900 0.78 0.90 0.79 md_green_100 0.30 0.69 0.31 md_green_500 0.11 0.37 0.13 md_green_900 0.94 0.96 0.76 md_lime_100 0.80 0.86 0.22 md_lime_500 0.51 0.47 0.09 md_lime_900 1.00 0.93 0.70 md_amber_100 1.00 0.76 0.03 md_amber_500 1.00 0.44 0.00 md_amber_900 1.00 0.88 0.70 md_orange_100 1.00 0.60 0.00 md_orange_500 0.90 0.32 0.00 md_orange_900 0.84 0.80 0.78 md_brown_100 0.47 0.33 0.28 md_brown_500 0.24 0.15 0.14 md_brown_900 0.96 0.96 0.96 md_grey_100 0.62 0.62 0.62 md_grey_500 0.13 0.13 0.13 md_grey_900"},{"location":"ros2halado/vizualizacio/#forrasok","title":"Forr\u00e1sok","text":"
  • docs.ros.org/en/humble/How-To-Guides/Visualizing-ROS-2-Data-With-Foxglove-Studio.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Creating-Launch-Files.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Tf2/Writing-A-Tf2-Broadcaster-Cpp.html
  • github.com/jkk-research/colors
"},{"location":"szabalyozas/","title":"Szab\u00e1lyoz\u00e1s","text":"

A szab\u00e1lyoz\u00e1s c\u00e9lja a megtervezett trajekt\u00f3ria kivitelez\u00e9se.

"},{"location":"szabalyozas/#1-motivacio-a-zarthurku-szabalyozas-mogott-bevezetes","title":"1. Motiv\u00e1ci\u00f3 a z\u00e1rthurk\u00fa szab\u00e1lyoz\u00e1s m\u00f6g\u00f6tt - bevezet\u00e9s","text":"

Egy rendszer tervezett c\u00e9l\u00e1llapot\u00e1t \u00fagy \u00e9rhetj\u00fck el, ha c\u00e9l\u00e9rt\u00e9k figyelembev\u00e9tel\u00e9vel a rendszerbe beavatkozunk. P\u00e9ld\u00e1ul egy j\u00e1rm\u0171 eset\u00e9n a c\u00e9lsebess\u00e9get a g\u00e1z \u00e9s f\u00e9kped\u00e1l mozgat\u00e1s\u00e1val, k\u00f6zvetetten a motor nyomat\u00e9k\u00e1nak \u00e9s a f\u00e9ker\u0151nek a v\u00e1ltoztat\u00e1s\u00e1val \u00e9rhetj\u00fck el. Kezdeti p\u00e9ld\u00e1nak tekints\u00fcnk egy j\u00e1rm\u0171vezet\u0151t: a vezet\u0151 \u00e1ltal\u00e1ban tiszt\u00e1ban van a megengedett legnagyobb sebess\u00e9ggel, ek\u00f6r\u00fcl alkalmaz egy sz\u00e1m\u00e1ra megfelel\u0151 t\u0171r\u00e9si s\u00e1vot. Ezen bel\u00fcl meghat\u00e1roz egy sz\u00e1m\u00e1ra biztons\u00e1gos \u00e9s k\u00e9nyelmes sebess\u00e9get, amit tartani szeretne. A vezet\u0151 addig gyors\u00edt, am\u00edg el nem \u00e9ri a k\u00edv\u00e1nt sebess\u00e9get, majd a g\u00e1zped\u00e1lt kicsit vissz\u00e1bbengedve tartja a sebess\u00e9get. Helyes az az \u00e1ll\u00edt\u00e1s, hogy amennyiben el\u00e9rt\u00fck a k\u00edv\u00e1nt sebess\u00e9get, a ped\u00e1lt elengedhetj\u00fck, nincs t\u00f6bb dolgunk? Term\u00e9szetesen nem. Mi\u00e9rt nem? Hisz a j\u00e1rm\u0171 a vesztes\u00e9gekb\u0151l ad\u00f3d\u00f3an lassulni fog, lejt\u0151 eset\u00e9n ak\u00e1r gyorsulhat is. Ahhoz, hogy tartani tudjuk a sebess\u00e9get a vezet\u0151nek folyamatosan figyelnie kell a j\u00e1rm\u0171 mozg\u00e1s\u00e1t illetve a k\u00f6rnyezetet, \u00e9s ez alapj\u00e1n beavatkoznia a ped\u00e1lokon kereszt\u00fcl. Ez az egyszer\u0171 p\u00e9lda legt\u00f6bb r\u00e9sz\u00e9t a tervez\u00e9si \u00e9s szab\u00e1lyz\u00e1si komponenseknek lefedi. A szab\u00e1lyz\u00e1s t\u00e9ren a k\u00f6vetkez\u0151 megfigyel\u00e9seket tehetj\u00fck meg: - a vezet\u0151 \u00e9rz\u00e9keli a j\u00e1rm\u0171 akut\u00e1lis \u00e1llapot\u00e1t (valamilyen pontoss\u00e1ggal) - a vezet\u0151 tudja, hogyha beavatkozik a g\u00e1z- vagy f\u00e9kped\u00e1llal, milyen hat\u00e1st fog el\u00e9rni, azaz mennyire lassul vagy gyorsul az aut\u00f3 (valamilyen pontoss\u00e1ggal) - a vezet\u0151 k\u00fcl\u00f6n\u00f6sebb \u00e9rz\u00e9kel\u00e9st\u0151l f\u00fcggetlen\u00fcl (teh\u00e1t an\u00e9lk\u00fcl, hogy tudn\u00e1, pl. milyen er\u0151 hat az aut\u00f3ra) nagyj\u00e1b\u00f3l (!) meg tudja hat\u00e1rozni a k\u00edv\u00e1nt g\u00e1zped\u00e1l \u00e1ll\u00e1st (nagy hib\u00e1val)

Az utols\u00f3 pontot szok\u00e1s \u00fan. el\u0151recsatolt \u00e1gnak is h\u00edvni (l\u00e1sd 3. alfejezet), avagy ny\u00edlthurk\u00fa szab\u00e1lyz\u00e1snak (amennyiben nincs semmilyen inf\u00f3nk az \u00e9rz\u00e9kel\u00e9sr\u0151l). Egy nagyon durva \u00f6sszehasonl\u00edt\u00e1st tartalmaz az 1. \u00c1bra. K\u00e9pzelj\u00fcnk el egy helyzetet, amikor nincs inform\u00e1ci\u00f3nk arr\u00f3l, milyen gyorsan megy a j\u00e1rm\u0171, csup\u00e1n a ped\u00e1lt tudjuk kezelni. A feladat hogy \u00e1ll\u00f3 helyb\u0151l gyors\u00edtva el\u00e9rj\u00fck a 90 km/h sebess\u00e9get, majd ezt a sebess\u00e9get tartsuk. Ha nem tudjuk, \u00e9pp mennyivel megy\u00fcnk, honnan tudjuk, hogy kell-e m\u00e9g nyomni a ped\u00e1lt avagy nem? Ilyenkor arra tudunk alapozni, hogy ismerj\u00fck az \u00fatviszonyokat (pl. s\u00edk talaj, aszfaltos \u00fat), ismerj\u00fck az aut\u00f3nkat (milyen motor, milyen nyomat\u00e9kviszonyok...stb.). \u00cdgy nagyj\u00e1b\u00f3l meg tudjuk hat\u00e1rozni, milyen hosszan kell nyomni a g\u00e1zped\u00e1lt, majd amikor nagyj\u00e1b\u00f3l el\u00e9rt\u00fck a sebess\u00e9get, mennyire kell ott tartani a ped\u00e1lon a l\u00e1bunkat, hogy ne lassuljunk, ne gyorsuljunk. Az eredm\u00e9ny val\u00f3sz\u00edn\u0171leg hasonl\u00edtani fog a k\u00edv\u00e1nt sebess\u00e9gg\u00f6rb\u00e9hez, de messze nem lesz pontos. Hiszen pontatlanul ismerj\u00fck az utat, a saj\u00e1t aut\u00f3nkat, befoly\u00e1solja a gyorsul\u00e1st a h\u0151m\u00e9rs\u00e9klet, emelked\u0151/lejt\u0151, szembesz\u00e9l...stb. Ez\u00e9rt \u00e1ltal\u00e1ban nem, vagy nem csak ezt a ny\u00edlthurk\u00fa megk\u00f6zel\u00edt\u00e9st haszn\u00e1ljuk, hanem min\u00e9l pontosabb \u00e9rz\u00e9kel\u0151k seg\u00edts\u00e9g\u00e9vel korrig\u00e1ljuk az \u00e1ltalunk el\u0151re meghat\u00e1rozott ped\u00e1l \u00e1ll\u00e1sokat, \u00e9s ezzel b\u00e1rmilyen zavar hat\u00e1s\u00e1t le tudjuk kezelni. Ez ut\u00f3bbi megk\u00f6zel\u00edt\u00e9st nevezz\u00fck z\u00e1rthurk\u00fa szab\u00e1lyz\u00e1snak, az \u00e9rz\u00e9kel\u00e9sb\u0151l kapott inform\u00e1ci\u00f3kat pedig visszacsatol\u00e1snak.

Note

A magyar terminol\u00f3gi\u00e1ban szok\u00e1s a ny\u00edlthurk\u00fa szab\u00e1lyz\u00e1st vez\u00e9rl\u00e9snek, a z\u00e1rthurk\u00fa szab\u00e1lyz\u00e1st r\u00f6viden csak szab\u00e1lyz\u00e1snak h\u00edvni. A kett\u0151t egy\u00fctt pedig ir\u00e1ny\u00edt\u00e1snak. Az angol terminol\u00f3gia ezzel szemben mindkett\u0151t controlnak, azon bel\u00fcl is closed loop controlnak illetve open loop controlnak h\u00edvja. A visszacsatol\u00e1st feedbacknek, az el\u0151recsatol\u00e1st feed-forwardnak szok\u00e1s h\u00edvni.

1. \u00c1bra: a z\u00e1rthurk\u00fa szab\u00e1lyoz\u00e1s m\u00f6g\u00f6tti motiv\u00e1ci\u00f3. Forr\u00e1s: Autonomous Driving Software Engineering - Lecture 08: Control

"},{"location":"szabalyozas/#2-architekturalis-attekintes-visszatekintes","title":"2. Architektur\u00e1lis \u00e1ttekint\u00e9s, visszatekint\u00e9s","text":"

Ahogyan azt a kor\u00e1bbi fejezetekben is l\u00e1ttuk, a teljes j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si l\u00e1nc modul\u00e1ris. A legf\u0151bb feladatok: - \u00e9rz\u00e9kel\u00e9s - \u00e9szlel\u00e9s - tervez\u00e9s - szab\u00e1lyz\u00e1s

Ez a fejezet a szab\u00e1lyz\u00e1sr\u00f3l sz\u00f3l. A szab\u00e1lyz\u00e1sok alapjair\u00f3l a 3. alfejezetben olvashatunk. A szab\u00e1lyz\u00f3 r\u00e9tegnek a tervez\u00e9s biztos\u00edtja a bemenetet. \u00cdgy - n\u00e9mileg kieg\u00e9sz\u00edtve - vess\u00fcnk egy pillant\u00e1st az architekt\u00far\u00e1ra! Ezt a 2. \u00c1bra mutatja.

flowchart LR\n\nGP1[Glob\u00e1lis tervez\u00e9s\n   Bemenetek:\n   - Sof\u0151rprofil\n   - T\u00e9rk\u00e9p\n   Kimenet:\n   - \u00datvonalterv\n   C\u00e9l: glob\u00e1lis terv megtervez\u00e9se\n   \u00fatvonalon, amely A-b\u00f3l vezet\n   B-be, figyelembe v\u00e9ve pl.\n   forgalmi adatok, \u00fczemanyag\n   fogyaszt\u00e1s\u2026 stb.]:::light\n\nGP2[Szeretn\u00e9k eljutni\n   A-b\u00f3l B-be\n   robotaxival]:::dark\n\nBP1[Magatart\u00e1s tervez\u00e9s\n     Bemenetek:\n     - \u00datvonalterv\n     -\u00c9rz\u00e9kel\u00e9si inform\u00e1ci\u00f3\n     a k\u00f6rnyezetr\u0151l\n     Kimenet:\n     - Viselked\u00e9si strat\u00e9gia\n     C\u00e9l: megtervezni, hogy\n     viselkedjen, \n     milyen mozg\u00e1si\n     karakterisztik\u00e1t\n     k\u00f6vessen a j\u00e1rm\u0171]:::light\n\nBP2[K\u00f6vetni szeretn\u00e9m\n  a k\u00f6z\u00e9ps\u0151 s\u00e1vot,\n  majd v\u00e1ltani a \n  bels\u0151 s\u00e1vra]:::dark\n\nLP1[Lok\u00e1lis tervez\u00e9s\n     Bemenetek:\n     - Viselked\u00e9si strat\u00e9gia\n     - T\u00e9rk\u00e9p\n     - Pose\n     - Predikt\u00e1lt objektumok\n     Kimenet:\n     - Lok\u00e1lis trajekt\u00f3ria\n     C\u00e9l: kinematikailag \n     megval\u00f3s\u00edthat\u00f3,\n     biztons\u00e1gos trajekt\u00f3ria\n     el\u0151\u00e1ll\u00edt\u00e1sa]:::light\nLP2[A s\u00e1von bel\u00fcl\n  biztons\u00e1gos \u00e9s\n  sima p\u00e1lya tervez\u00e9se]:::dark\n\n\nVC1[J\u00e1rm\u0171szint\u0171 szab\u00e1lyz\u00e1s\n     Magas szint\u0171 szab\u00e1lyoz\u00e1s\n     Bemenetek:\n     - Lok\u00e1lis trajekt\u00f3ria\n     - A j\u00e1rm\u0171 \u00e1llapot\u00e1nak v\u00e1ltoz\u00f3i\n     - Lokaliz\u00e1ci\u00f3s inform\u00e1ci\u00f3\n     Kimenetek:\n     - J\u00e1rm\u0171szint\u0171 c\u00e9l\n     mennyis\u00e9gek\n     - Ellen\u0151rz\u00e9si korl\u00e1tok\n     C\u00e9l: kisz\u00e1m\u00edtani a\n     j\u00e1rm\u0171 c\u00e9l\u00e1llapot\u00e1t, amit \n     az alacsony szint\u0171\n     szab\u00e1lyz\u00e1s megval\u00f3s\u00edt]:::light\nVC2[A j\u00e1rm\u0171vet a \n  tervezett trajekt\u00f3ri\u00e1n\n  v\u00e9gigvezesse a \n  megfelel\u0151 sebess\u00e9ggel]:::dark\n\n\nAC1[Aktu\u00e1tor szab\u00e1lyoz\u00e1s\n  Alacsony szint\u0171 szab\u00e1lyoz\u00e1s\n  Bemenetek:\n  - J\u00e1rm\u0171szint\u0171 c\u00e9l\n  mennyis\u00e9gek\n  - Ellen\u0151rz\u00e9si korl\u00e1tok\n  - Aktu\u00e1tor\n  \u00e1llapotv\u00e1ltoz\u00f3i\n  Kimenet:\n  - Aktu\u00e1tor c\u00e9l\u00e1llapotai\n  C\u00e9l: A j\u00e1rm\u0171szint\u0171 \n  mennyis\u00e9geket lebontsa\n  \u00e9s megval\u00f3s\u00edtsa \n  az aktu\u00e1torokon kereszt\u00fcl]:::light\n  AC2[Kisz\u00e1molni a\nsz\u00fcks\u00e9ges motor\nnyomat\u00e9k \u00e9s korm\u00e1nyz\u00e1si\nsz\u00f6g referenci\u00e1t]:::dark\n\n\n\n\nsubgraph Plan [Tervez\u00e9s]\n  GP1\n  BP1\n  LP1\nend\nsubgraph Control [Szab\u00e1lyoz\u00e1s]\n  VC1\n  AC1\nend\nGP1-->BP1-->LP1-->VC1-->AC1\nGP2-.-BP2-.-LP2-.-VC2-.-AC2\n\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
2. \u00c1bra: a legf\u0151bb tervez\u00e9si \u00e9s szab\u00e1lyz\u00e1si r\u00e9tegek az architekt\u00far\u00e1ban.

A szab\u00e1lyz\u00f3 r\u00e9teg \u00e1ltal\u00e1ban t\u00f6bb szinre bomlik. Minimum k\u00e9t ilyen szintet megk\u00fcl\u00f6nb\u00f6ztet\u00fcnk: - j\u00e1rm\u0171szint\u0171 szab\u00e1lyz\u00e1s - aktu\u00e1tor szab\u00e1lyz\u00e1s

Mindkett\u0151 r\u00e9tegnek meg van a feladata. A j\u00e1rm\u0171szint\u0171 szab\u00e1lyz\u00e1s feladata, hogy a j\u00e1rm\u0171vet a tervezett trajekt\u00f3ri\u00e1n v\u00e9gigvezesse a megfelel\u0151 sebess\u00e9ggel. Ehhez a j\u00e1rm\u0171 szintj\u00e9n megfogalmazott c\u00e9l\u00e9rt\u00e9keket hat\u00e1roz meg. \u00d6k\u00f6lszab\u00e1lyk\u00e9nt elfogadhatjuk, hogy azok a mennyis\u00e9gek a j\u00e1rm\u0171szint\u0171ek, amelyek m\u00e9g nem kapcsol\u00f3dnak egy kimondott aktu\u00e1torhoz. Azaz, pl. minden aut\u00f3ra jellemz\u0151 annak gyorsul\u00e1sa vagy sz\u00f6gsebess\u00e9ge, att\u00f3l f\u00fcggetlen\u00fcl, milyen hajt\u00e1ssal (elektromos, hibrid, bels\u0151\u00e9g\u00e9s\u0171) vagy korm\u00e1nyz\u00e1ssal (elektromos szerv\u00f3, hidraulikus szerv\u00f3, l\u00e1nctalpas...stb.) rendelkezik. \u00c1ltal\u00e1ban ez a szab\u00e1lyz\u00f3 r\u00e9teg a \"leglassabb\", be\u00e1gyazott k\u00f6rnyezetben a ciklus id\u0151 10-50ms. Az aktu\u00e1tot szab\u00e1lyz\u00e1s feladata, hogy a j\u00e1rm\u0171szint\u0171 mennyis\u00e9geket lebontsa \u00e9s megval\u00f3s\u00edtsa az aktu\u00e1torokon kereszt\u00fcl. Pl. a hosszir\u00e1ny\u00fa gyorsul\u00e1st befoly\u00e1solhatjuk a motoron \u00e9s a f\u00e9ken kereszt\u00fcl. A motor eset\u00e9ben a gyorsul\u00e1st a motor nyomat\u00e9k\u00e1nak szab\u00e1lyz\u00e1s\u00e1val \u00e9rj\u00fck el, amit pedig a fojt\u00f3szelep \u00e1ll\u00e1s\u00e1val \u00e9r\u00fcnk el. A fojt\u00f3szelep \u00e1ll\u00e1s\u00e1t pedig az azt mozgat\u00f3 pl. szerv\u00f3motor poz\u00edci\u00f3j\u00e1nak, voltak\u00e9pp a szerv\u00f3motor kapocsfesz\u00fclts\u00e9g\u00e9nek szab\u00e1lyz\u00e1s\u00e1val \u00e9r\u00fcnk el. A f\u00e9krendszer eset\u00e9n a f\u00e9ker\u0151t tudjuk befoly\u00e1solni, ami egyben a f\u00e9knyom\u00e1s szab\u00e1lyz\u00e1s\u00e1t jelenti (pl. az ESP szelepein kereszt\u00fcl), amit pedig a hidraulikus f\u00e9krendszer motor szivatty\u00faj\u00e1nak nyom\u00e1s\u00e1val \u00e9rhet\u00fcnk el. Ezt pedig a szivatty\u00fa motorj\u00e1nak fordulatsz\u00e1m\u00e1val tudjuk befoly\u00e1solni, ami megint a motor kapocsfesz\u00fclts\u00e9g\u00e9nek a szab\u00e1lyz\u00e1s\u00e1val \u00e9r\u00fcnk el...stb. L\u00e1thatjuk, hogy aktu\u00e1torokt\u00f3l f\u00fcgg\u0151en itt t\u00f6bb (ak\u00e1r 4-6) egym\u00e1sba \u00e1gyazott szab\u00e1lyz\u00f3 hurokr\u00f3l besz\u00e9l\u00fcnk. Bel\u00fclr\u0151l kifel\u00e9 \u00e9rdemes a probl\u00e9m\u00e1t megk\u00f6zel\u00edteni, ahogy a legbels\u0151 szab\u00e1lyz\u00e1s ciklusideje ak\u00e1r 1 ms (vagy az alatti) lehet, m\u00e9g ahogy kintebb l\u00e9p\u00fcnk ez n\u0151, 5-10-20ms tartom\u00e1nyban. Fontos, hogy automatiz\u00e1lt vezet\u00e9si rendszerek mozg\u00e1sszab\u00e1lyz\u00e1sa eset\u00e9n az aktu\u00e1tor szab\u00e1lyz\u00f3 r\u00e9tegeket sokszor nem vessz\u00fck figyelembe, hanem felt\u00e9telezz\u00fck, hogy azok teljes\u00edtm\u00e9nye, pontoss\u00e1ga, sebess\u00e9ge megfelel\u0151, \"k\u00f6zel ide\u00e1lis\". Persze a gyakorlatban ezt sokszor neh\u00e9z elv\u00e1lasztani, de arra t\u00f6reksz\u00fcnk, hogy csak a j\u00e1rm\u0171szint\u0171 szab\u00e1lyz\u00e1st kelljen megtervezni.

A legfels\u0151 szint\u0171 szab\u00e1lyz\u00e1s feladata teh\u00e1t az, hogy a j\u00e1rm\u0171 a trajekt\u00f3ri\u00e1t lek\u00f6vesse. \u00c1ltal\u00e1ban k\u00e9t dimenzi\u00f3t k\u00fcl\u00f6nb\u00f6ztet\u00fcnk meg: - hosszir\u00e1ny\u00fa mozg\u00e1s: a j\u00e1rm\u0171 hosszir\u00e1ny\u00fa gyorsul\u00e1s\u00e1nak, \u00e9s v\u00e9g\u00fcl a f\u00e9k \u00e9s motorer\u0151k meghat\u00e1roz\u00e1sa. - keresztir\u00e1ny\u00fa mozg\u00e1s: a j\u00e1rm\u0171 c\u00e9lsz\u00f6gesebess\u00e9g\u00e9nek, \u00e9s v\u00e9g\u00fcl a korm\u00e1nysz\u00f6gnek a meghat\u00e1roz\u00e1sa.

A trajekt\u00f3ria \u00e1ltal\u00e1ban egy id\u0151ben le\u00edrt sebess\u00e9gtarjekt\u00f3ria illetve egy t\u00e9rben megadott c\u00e9lpont halmaz, azaz egy g\u00f6rbe (vagy annak egy repreznt\u00e1ci\u00f3ja). A c\u00e9l, hogy a g\u00f6rb\u00e9t min\u00e9l kisebb poz\u00edci\u00f3hib\u00e1val lek\u00f6vess\u00fck, illetve a sebess\u00e9get min\u00e9l pontosabban tartsuk. Mindezt \u00fagy, hogy ne l\u00e9pj\u00fcnk \u00e1t semmilyen hat\u00e1r\u00e9rt\u00e9ket (pl. t\u00fal nagy gyorsul\u00e1s, p\u00e1lyaelhagy\u00e1s...stb).

Miel\u0151tt r\u00e1t\u00e9rn\u00e9nk a l\u00e9tez\u0151 j\u00e1rm\u0171szab\u00e1lyz\u00e1si megold\u00e1sokra, a 3. alfejezetben \u00e1ttekint\u00e9st adunk a szab\u00e1lyz\u00e1si alapokr\u00f3l.

"},{"location":"szabalyozas/#3-szabalyzasi-alapok","title":"3. Szab\u00e1lyz\u00e1si alapok","text":"

Ebben a fejezetben ismertetj\u00fck a szab\u00e1lyz\u00e1stechnik\u00e1hoz kapcsol\u00f3d\u00f3 alapfogalmakat, \u00e9s erre p\u00e9ld\u00e1kat is hozunk a j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1s ter\u00fclet\u00e9r\u0151l.

"},{"location":"szabalyozas/#31-definiciok","title":"3.1. Defin\u00edci\u00f3k","text":"

Val\u00f3s fizikai rendszer: egy olyan fizikai objektum, amely m\u00e9rhet\u0151 k\u00fcls\u0151 k\u00e9nyszer hat\u00e1s\u00e1ra m\u00e9rhet\u0151 m\u00f3don megv\u00e1ltozik.

Bemenetek: A val\u00f3s fizikai rendszerre hat\u00f3 \u00e9s id\u0151ben v\u00e1ltozni k\u00e9pes k\u00e9nyszereket nevezz\u00fck fizikai bemeneteknek. Kimenetek: A val\u00f3s fizikai rendszernek a fizikai k\u00e9nyszerek hat\u00e1s\u00e1ra bek\u00f6vetkez\u0151 b\u00e1rmely v\u00e1ltoz\u00e1sa lehet fizikai kimenet, ezek k\u00f6z\u00fcl azt tekintj\u00fck fizikai kimenetnek, amelyet az adott vizsg\u00e1latban k\u00f6zvetlen\u00fcl vagy k\u00f6zvetve m\u00e9r\u00fcnk. P\u00e9lda: ezt mindig a szab\u00e1lyz\u00e1si feladatnak megfelel\u0151en hat\u00e1rozzuk meg. P\u00e9ld\u00e1ul j\u00e1rm\u0171szint\u0171 ir\u00e1ny\u00edt\u00e1s: a rendszer a j\u00e1rm\u0171 maga, bemenete pl. a hosszir\u00e1ny\u00fa \u00e9s keresztir\u00e1ny\u00fa gyorsul\u00e1s. Kimenete pl. a poz\u00edci\u00f3, sebess\u00e9g...stb. P\u00e9lda: alacsonyszint\u0171 szab\u00e1lyz\u00e1s eset\u00e9n ez lehet pl. a f\u00e9kszab\u00e1lyz\u00e1s, ahol a bemenet a f\u0151f\u00e9khenger poz\u00edci\u00f3ja, a kimenet a f\u00e9kt\u00e1rcsa \u00e9s a f\u00e9kpofa k\u00f6z\u00f6tt fell\u00e9p\u0151 er\u0151, vagy a ker\u00e9kre hat\u00f3 nyomat\u00e9k...stb..

Az absztrakt rendszer: Az absztrakt rendszer egy val\u00f3s fizikai rendszer valamilyen pontoss\u00e1g\u00fa \u00e9s meghat\u00e1rozott m\u0171k\u00f6d\u00e9si tartom\u00e1nyra \u00e9rv\u00e9nyes absztrakt modellje, amely a bemen\u0151jelek \u00e9s a kimen\u0151jelek k\u00f6z\u00f6tt teremt matematikai kapcsolatot. Ez voltak\u00e9pp egy modellez\u00e9si elj\u00e1r\u00e1s eredm\u00e9nye, amely modell a val\u00f3s fizikai rendszer matematikai le\u00edr\u00e1sa, jellemz\u0151en differenci\u00e1legyenletek form\u00e1j\u00e1ban. P\u00e9lda: a j\u00e1rm\u0171 kinematikai bicikli modellje.

Rendszer param\u00e9terek: A val\u00f3s fizikai rendszert le\u00edr\u00f3 egyenletek egy\u00fctthat\u00f3it param\u00e9tereknek nevezz\u00fck. Id\u0151invariancia: Az id\u0151invari\u00e1ns rendszer eset\u00e9n, ha a rendszer egy U(t) gerjeszt\u00e9sre adott v\u00e1lasza Q(t), akkor az id\u0151ben eltolt U(t-tau) gerjeszt\u00e9sre adott Y(t-tau) v\u00e1lasz is egyszer\u0171 id\u0151beni eltol\u00e1ssal megkaphat\u00f3. Ez egy\u00fattal azt is jelenti, hogy a rendszer modellje id\u0151ben nem v\u00e1ltozik, azaz a rendszer param\u00e9terei \u00e1lland\u00f3ak. P\u00e9lda: a j\u00e1rm\u0171 kinematikai bicikli modellj\u00e9nek param\u00e9terei pl. a j\u00e1rm\u0171 tengelyt\u00e1vja, amely (rem\u00e9lhet\u0151leg) id\u0151ben nem v\u00e1ltozik, azaz ez a param\u00e9ter id\u0151invari\u00e1ns. Ha a rendszer modellj\u00e9nek \u00f6sszes param\u00e9tere id\u0151invari\u00e1ns, maga az absztrakt rendszer is invari\u00e1ns. P\u00e9lda: a j\u00e1rm\u0171 dinamikai bicikli modellj\u00e9nek egy param\u00e9tere a j\u00e1rm\u0171 t\u00f6mege. Ez v\u00e1ltozhat \"menet k\u00f6zben is\", hiszen pl. t\u00f6bben \u00fclnek az aut\u00f3ban, csomagokat pakolnak bele, az \u00fczemanyag szintje v\u00e1ltozik, azaz ez a param\u00e9ter nem id\u0151invari\u00e1ns, teh\u00e1t a fizikai rendszer sem id\u0151invari\u00e1ns. Ugyanakkor tekinthetj\u00fck bizonyos felt\u00e9telek mellett id\u0151invari\u00e1nsnak, ekkor a modell pontatlans\u00e1ga n\u0151.

\u00c1llapot: Az \u00e1llapot a mem\u00f3ria jelleggel rendelkez\u0151 dinamikai rendszerekben a m\u00falt \u00f6sszes\u00edtett hat\u00e1sa. A rendszer \u00e1llapot\u00e1nak a k\u00f6vetkez\u0151 k\u00e9t tulajdons\u00e1ggal kell rendelkeznie - B\u00e1rmely T id\u0151pillanatban a kimen\u0151jel az adott pillanatbeli \u00e1llapot \u00e9s bemen\u0151jel egy\u00fcttes ismeret\u00e9ben egy\u00e9rtelm\u0171en meghat\u00e1rozhat\u00f3 legyen. Kimeneti egyenletnek nevezz\u00fck azt az \u00f6sszef\u00fcgg\u00e9st, amely az \u00e1llapotb\u00f3l \u00e9s a bemen\u0151jelb\u0151l meghat\u00e1rozza a kimen\u0151jeleket. - Az \u00e1llapot egy adott T id\u0151pillanatban egy\u00e9rtelm\u0171en meghat\u00e1rozhat\u00f3 legyen a bemen\u0151jel a t\u2264T id\u0151tartom\u00e1nybeli \u00e9rt\u00e9k\u00e9nek ismeret\u00e9ben. Az \u00e1llapot v\u00e1ltoz\u00e1s\u00e1t le\u00edr\u00f3 egyenletet \u00e1llapotegyenletnek nevezz\u00fck.

\u00c1llapotv\u00e1ltoz\u00f3: Az \u00e1llapotv\u00e1ltoz\u00f3k az \u00e1llapot egy\u00e9rtelm\u0171 le\u00edr\u00e1s\u00e1ra szolg\u00e1lnak. Az \u00e1llapotv\u00e1ltoz\u00f3 lehet egy id\u0151f\u00fcggv\u00e9ny, az \u00e1llapot mennyis\u00e9gi v\u00e1ltoz\u00e1sainak le\u00edr\u00e1s\u00e1ra, illetve logikai v\u00e1ltoz\u00f3 az \u00e1llapot min\u0151s\u00e9gi v\u00e1lt\u00e1sainak le\u00edr\u00e1s\u00e1ra.

Rendszer dimenzi\u00f3: Egy rendszer \u00e1llapot\u00e1nak egy\u00e9rtelm\u0171 le\u00edr\u00e1s\u00e1hoz minim\u00e1lisan sz\u00fcks\u00e9ges \u00e1llapotv\u00e1ltoz\u00f3k sz\u00e1m\u00e1t a rendszer dimenzi\u00f3j\u00e1nak szok\u00e1s nevezni.

Kanonikus \u00e1llapotv\u00e1ltoz\u00f3k: Kanonikus \u00e1llapotv\u00e1ltoz\u00f3nak nevezz\u00fck az \u00e1llapotv\u00e1ltoz\u00f3k legkisebb olyan halmaz\u00e1nak elemeit, amelyek seg\u00edts\u00e9g\u00e9vel az \u00e1llapot egy\u00e9rtelm\u0171en le\u00edrhat\u00f3. A nem kanonikus \u00e1llapotv\u00e1ltoz\u00f3kat sz\u00e1rmaztatott \u00e1llapotv\u00e1ltoz\u00f3knak nevezz\u00fck.

Ljapunov-f\u00e9le stabilit\u00e1s: Egy nemline\u00e1ris auton\u00f3m m\u0171k\u00f6d\u00e9s\u0171 rendszert akkor mondunk Ljapunov \u00e9rtelemben stabilisnak, ha az egyens\u00falyi \u00e1llapot b\u00e1rmely k\u00f6rnyezet\u00e9hez tal\u00e1lunk egy olyan null\u00e1n\u00e1l nagyobb maxim\u00e1lis kit\u00e9r\u00edt\u00e9st, amelyn\u00e9l kisebb kit\u00e9r\u00edt\u00e9sek eset\u00e9n a rendszer garant\u00e1ltan visszat\u00e9r az eredetileg meghat\u00e1rozott k\u00f6rnyezetbe.

BIBO stabilit\u00e1s: Korl\u00e1tos bemen\u0151jelre minden esetben korl\u00e1tos kimen\u0151jel a v\u00e1lasz. Ezt a felt\u00e9telt teljes\u00edt\u0151 rendszert ism\u00e9telten az angol n\u00e9v ut\u00e1n BIBO (Bounded Input Bounded Output) stabilis rendszernek h\u00edvjuk.

Ezen fogalmak \u00f6sszess\u00e9ge elegend\u0151 a j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si alapok meg\u00e9rt\u00e9s\u00e9hez. A szab\u00e1lyz\u00e1si feladat sokszor k\u00e9t r\u00e9szre bonthat\u00f3: - modellez\u00e9s, az absztrakt matematikai modell elk\u00e9sz\u00edt\u00e9se - szab\u00e1lyz\u00e1s, azaz a szab\u00e1lyz\u00f3 megtervez\u00e9se.

"},{"location":"szabalyozas/#32-a-szabalyzasi-feladat-megfogalmazasa","title":"3.2. A szab\u00e1lyz\u00e1si feladat megfogalmaz\u00e1sa","text":"

A c\u00e9l mindig a val\u00f3s fizikai rendszer ir\u00e1ny\u00edt\u00e1sa \u00fagy, hogy az az el\u0151\u00edrt c\u00e9l\u00e9rt\u00e9knek megfelel\u0151en viselkedjen. Fontos, hogy minden c\u00e9lhoz meghat\u00e1rozzunk olyan m\u00e9rhet\u0151 mennyis\u00e9geket, amelyek alapj\u00e1n a szab\u00e1lyz\u00e1s j\u00f3s\u00e1g\u00e1t meg tudjuk hat\u00e1rozni. A legt\u00f6bbsz\u00f6r (de nem kiz\u00e1r\u00f3lagosan) haszn\u00e1lt ilyen mennyis\u00e9gek: - be\u00e1ll\u00e1si id\u0151 (gyorsas\u00e1g) - t\u00fallend\u00fcl\u00e9s m\u00e9rt\u00e9ke - \u00e1lland\u00f3sult \u00e1llapotbeli hiba - a szab\u00e1lyz\u00e1s energi\u00e1ja.

A szab\u00e1lyz\u00e1si l\u00e1ncot a 3. \u00c1br\u00e1n l\u00e1that\u00f3 m\u00f3don \u00edrhatjuk fel. A k\u00f6vetkez\u0151 jel\u00f6l\u00e9seket haszn\u00e1ljuk:

  • \\(r(t)\\): a c\u00e9l\u00e9rt\u00e9k, avagy referenciajel
  • \\(y(t)\\): a visszacsatolt \u00e9rt\u00e9k.
  • \\(m(t)\\): a val\u00f3s rendszeren m\u00e9rt \u00e9rt\u00e9k. Megjegyz\u00e9s: sokszor az \u00e9rz\u00e9kel\u0151t ide\u00e1lisnak tekintj\u00fck, \u00edgy \\(y(t)=m(t)\\), \u00e9s \u00edgy a visszacsatolt \u00e9rt\u00e9k egyben az absztrakt rendszer kimenete.
  • \\(e(t)\\): hibajel, a szab\u00e1lyz\u00f3 bemenete.
  • \\(i(t)\\): a szab\u00e1lyz\u00f3 \u00e1ltal meghat\u00e1rozott beavatkoz\u00f3 jel.
  • \\(f(t)\\): el\u0151recsatolt \u00e1g.
  • \\(u(t)\\): a rendszer bemenete
  • \\(d(t)\\): k\u00fcls\u0151 zavarok.

3. \u00c1bra: a szab\u00e1lyz\u00e1si l\u00e1nc blokkdiagramja.

A szab\u00e1lyz\u00f3 feladata, hogy a bemenet\u00e9n keletkez\u0151 hib\u00e1t minimaliz\u00e1lja. A teljes szab\u00e1lyz\u00e1si l\u00e1nc feladata, hogy a val\u00f3s fizikai rendszer kimenete a lehet\u0151 legnagyobb pontoss\u00e1ggal k\u00f6vesse le a referencia jelet. A k\u00f6vetkez\u0151kben egy egyszer\u0171 p\u00e9ld\u00e1n szeml\u00e9ltetj\u00fck egy rendszer modellez\u00e9s\u00e9t, a zavarok hat\u00e1s\u00e1t, tov\u00e1bb\u00e1 p\u00e9ld\u00e1t adunk egy szab\u00e1lyz\u00f3ra illetve az el\u0151recsatol\u00e1s lehet\u0151s\u00e9g\u00e9re. A p\u00e9ld\u00e1t MATLAB/Simulink k\u00f6rnyezetben k\u00e9sz\u00edtett\u00fck el.

"},{"location":"szabalyozas/#33-pelda-a-szabalyzasi-alapokra","title":"3.3. P\u00e9lda a szab\u00e1lyz\u00e1si alapokra","text":"

Ebben a p\u00e9ld\u00e1ban egy egyszer\u0171 modellt fogunk fel\u00e9p\u00edteni hogy szeml\u00e9ltess\u00fck a z\u00e1rthurk\u00fa szab\u00e1lyz\u00e1st. A feladat egy j\u00e1rm\u0171 sebess\u00e9gszab\u00e1lyz\u00e1sa. Ehhez a j\u00e1rm\u0171 egyszer\u0171 modellj\u00e9t fogjuk elk\u00e9sz\u00edteni. 1. Feladat: hat\u00e1rozzuk meg a rendszer be- \u00e9s kimeneteit! A rendszerre a j\u00e1rm\u0171re hat\u00f3 gyors\u00edt\u00f3 er\u0151vel szeretn\u00e9nk hatni, ez\u00e9rt ez a bemenet. A kimenet a j\u00e1rm\u0171 sebess\u00e9ge, hiszen ezt szeretn\u00e9nk egy adott c\u00e9l\u00e9rt\u00e9kre szab\u00e1lyozni. Mivel ennek a rendszernek 1 be- \u00e9s 1 kimenete van, ez\u00e9rt szok\u00e1s SISO (Single Input Single Output) rendszernek is h\u00edvni. Ennek anal\u00f3gi\u00e1j\u00e1n l\u00e9teznek MIMO (Multiple Inputs Multiple Outputs) rendszerek is. Megjegyz\u00e9s: a val\u00f3s\u00e1gban a j\u00e1rm\u0171re a g\u00e1zped\u00e1llal \u00e9s a f\u00e9kped\u00e1llal hatunk, de ezek voltak\u00e9pp a j\u00e1rm\u0171 gyorsul\u00e1s\u00e1t befoly\u00e1solj\u00e1k, \u00edgy az egyszer\u0171s\u00e9g kedv\u00e9\u00e9rt a szakasz ezen r\u00e9sz\u00e9t nem modellezz\u00fck. Ezzel term\u00e9szetesen hib\u00e1t visz\u00fcnk a modellbe, de n\u00f6velj\u00fck annak \u00e1ltal\u00e1noss\u00e1g\u00e1t.

  1. Feladat: k\u00e9sz\u00edts\u00fck el a j\u00e1rm\u0171 matematikai modellj\u00e9t / absztrakt modellj\u00e9t! Olyan egyenletrendszert keres\u00fcnk, amely \u00f6sszek\u00f6ti a be- \u00e9s kimenetet. Itt meg kell hat\u00e1roznunk, mennyire t\u00f6reksz\u00fcnk pontos modellre. Az egyszer\u0171s\u00e9g kedv\u00e9\u00e9rt \u00e9lj\u00fcnk a k\u00f6vetkez\u0151 megk\u00f6t\u00e9sekkel:
  2. eltekint\u00fcnk a hosszir\u00e1nyban fell\u00e9p\u0151 ker\u00e9kszlipt\u0151l
  3. eltekint\u00fcnk az aktu\u00e1torok dinamikai viselked\u00e9s\u00e9t\u0151l, azaz a k\u00e9rt gyorsul\u00e1s egyb\u0151l megval\u00f3sul
  4. eltekint\u00fcnk a m\u00e9rt mennyis\u00e9geket terhel\u0151 hib\u00e1kt\u00f3l, azaz a szenzorok pontatlans\u00e1g\u00e1t\u00f3l.
  5. eltekint\u00fcnk a fut\u00f3m\u0171 \u00e9s a felf\u00fcggeszt\u00e9s dinamikai tulajdons\u00e1gait\u00f3l.

Az egyenlet\u00fcnk \u00edgy egy koncentr\u00e1lt t\u00f6megpont line\u00e1ris mozg\u00e1s\u00e1v\u00e1 egyszer\u0171s\u00f6dik. A modellbe foglaljuk be a k\u00f6vetkez\u0151 mennyis\u00e9geket: - a j\u00e1rm\u0171 t\u00f6mege - a j\u00e1rm\u0171 l\u00e9gellen\u00e1ll\u00e1sa - a j\u00e1rm\u0171 sebess\u00e9gar\u00e1nyos s\u00farl\u00f3d\u00e1sa.

Newton II. t\u00e9tel\u00e9nek megfelel\u0151en \u00edrjuk fel a k\u00f6vetkez\u0151 dinamikai egyens\u00falyi egyenletet: $$ \\ddot I = \\sum F $$

Azaz:

\\[ m*\\ddot v(t) = F_{prop}(t) - F_{aero}(t) - F_{fric}(t) \\]

L\u00e1thatjuk, hogy mind a bemenet, mind a kimenet szerepel az egyenlet\u00fcnkben, \u00edgy val\u00f3ban megtal\u00e1ltuk a rendszer modellj\u00e9t. Alak\u00edtsuk tov\u00e1bb, hogy csak a ki- \u00e9s bemenet szerepeljen benne:

\\[ m*\\ddot v(t) = F_{prop}(t) - \\frac{1}{2}*v(t)^2*\\rho*c*A - v(t)*b \\]

Ebben a form\u00e1ban az id\u0151ben v\u00e1ltoz\u00f3 jelek a be- \u00e9s kimenet (a sebess\u00e9g illetve a hajt\u00f3er\u0151), \u00e9s vannak id\u0151ben \u00e1lland\u00f3 (id\u0151invari\u00e1ns) param\u00e9terek:

  • \\(\\rho\\): a leveg\u0151 s\u0171r\u0171s\u00e9ge
  • \\(A\\): homlokfel\u00fclet m\u00e9rete
  • \\(c\\): j\u00e1rm\u0171 l\u00e9gellen\u00e1ll\u00e1si egy\u00fctthat\u00f3ja
  • \\(b\\): Coloumb-f\u00e9le s\u00farl\u00f3d\u00e1si t\u00e9nyez\u0151

4. \u00c1bra: a j\u00e1rm\u0171 modellezett er\u0151egyens\u00falya

Ahhoz, hogy megkapjuk a sebess\u00e9get, mint v\u00e1lasztott kimenet, meg kell oldanunk a differenci\u00e1legyenletet. Ezt Simulinkben numerikusan v\u00e9gezz\u00fck el. A megold\u00e1st az 5. \u00c1bra mutatja.

5. \u00c1bra: a differenci\u00e1legyenlet numerikus megold\u00e1sa.

A teljes szab\u00e1lyz\u00e1si l\u00e1nc blokkdiagramj\u00e1t a 6. \u00c1bra mutatja. Ezen az \u00e1br\u00e1n nem haszn\u00e1ljuk a visszacsatolt \u00e1gat. A kezd\u0151 sebess\u00e9get 20 m/s-ra \u00e1ll\u00edtottuk. A hajt\u00f3er\u0151 ez esetben nulla, \u00edgy voltak\u00e9pp a j\u00e1rm\u0171 tehetetlens\u00e9g\u00e9n\u00e9l fogva gurul, \u00e9s folyamatosan lassul a terhel\u00e9ssel ar\u00e1nyosan.

6. \u00c1bra: a teljes szab\u00e1lyz\u00e1si l\u00e1nc blokkdiagramja.

A k\u00f6vetkez\u0151 param\u00e9ter \u00e9rt\u00e9keket v\u00e1lasztottuk a szimul\u00e1ci\u00f3hoz:

  • \\(A = 1.2m^2\\)
  • \\(b = 10 Ns/m\\)
  • \\(c = 0.4\\)
  • \\(\\rho = 1 kg/m^3\\)
  • \\(m = 1250 kg\\)

A 7. \u00c1br\u00e1n l\u00e1that\u00f3 a futtat\u00e1s eredm\u00e9nye. 100s-ig futott a szimul\u00e1ci\u00f3, ez id\u0151 alatt 20 m/s-r\u00f3l nagyj\u00e1b\u00f3l 7 m/s-ra lassul a j\u00e1rm\u0171.

7. \u00c1bra: a teljes szab\u00e1lyz\u00e1si l\u00e1nc blokkdiagramja.

A 8. \u00c1br\u00e1n a visszacsatolt szab\u00e1lyz\u00f3nak egy ar\u00e1nyos szab\u00e1lyz\u00f3t (P szab\u00e1lyz\u00f3t) v\u00e1lasztunk, amely a hib\u00e1val ar\u00e1nyosan hat\u00e1rozza meg a beavatkoz\u00f3 jelet. Az er\u0151s\u00edt\u00e9st 100-ra v\u00e1lasztjuk, azaz 1 m/s sebess\u00e9ghiba 100N hajt\u00f3er\u0151t eredm\u00e9nyez. A kezd\u0151 sebess\u00e9g 15 m/s, a c\u00e9lsebess\u00e9g 20 m/s, \u00edgy kezdetben 500N hajt\u00f3er\u0151nk lesz.

8. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3, 100-as er\u0151s\u00edt\u00e9ssel.*

A 9. \u00c1br\u00e1n l\u00e1that\u00f3 a szab\u00e1lyz\u00f3 karakterisztik\u00e1ja, P szab\u00e1lyz\u00f3val, 100-as er\u0151s\u00edt\u00e9ssel. A maradand\u00f3 hiba relat\u00edve nagy (t\u00f6bb mint 10%). Ennek oka, hogy az ar\u00e1nyos szab\u00e1lyz\u00f3 a hib\u00e1val ar\u00e1nyos bemeneti jelet \u00e1ll\u00edt el\u0151, \u00e9s mivel a j\u00e1rm\u0171re hat ellent\u00e9tes ir\u00e1ny\u00fa er\u0151, \u00edgy a szab\u00e1lyz\u00f3 ezzel fog egyens\u00falyt tartani. Amennyiben n\u00f6velj\u00fck az er\u0151s\u00edt\u00e9st, \u00fagy cs\u00f6kken az \u00e1lland\u00f3sult \u00e1llapotbeli hiba. Elm\u00e9letben v\u00e9gtelen nagy er\u0151s\u00edt\u00e9s null\u00e1ra cs\u00f6kkenti ezt a hib\u00e1t, viszont a v\u00e9gtelen er\u0151s\u00edt\u00e9s v\u00e9gtelen beavatkoz\u00f3 jelet jelent, ami nem megval\u00f3s\u00edthat\u00f3. A gyakorlatban enn\u00e9l sokkal hamarabb el\u00e9rj\u00fck a korl\u00e1tokat, hiszen az aktu\u00e1torok csak v\u00e9ges er\u0151 kifejt\u00e9s\u00e9re k\u00e9pesek. Ezt a szab\u00e1lyz\u00f3 megtervez\u00e9s\u00e9n\u00e9l figyelembe kell venni.

9. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3 karakterisztik\u00e1ja.

Az \u00e1lland\u00f3sult \u00e1llapotbeli hib\u00e1t \u00fagy is elimin\u00e1lhatjuk, ha az er\u0151s\u00edt\u00e9s mellett egy olyan szab\u00e1lyz\u00f3 tagot is hozz\u00e1adunk, ami \"\u00e9szre veszi\", ha sok\u00e1ig adott hiba \u00e1ll fent, \u00e9s n\u00f6veli ennek megfelel\u0151en a beavatkoz\u00f3 jelet. Min\u00e9l tov\u00e1bb \u00e1ll fent a hiba, ann\u00e1l jobban n\u00f6velj\u00fck a beavatkoz\u00f3 jelet. Ez gyakorlatilag a hiba id\u0151beli integr\u00e1lj\u00e1val ar\u00e1nyos bevatkoz\u00f3 tagot jelent. Ezt szok\u00e1s I tagnak nevezni. Az \u00edgy kialakul\u00f3 szab\u00e1lyz\u00f3t pedig PI szab\u00e1lyz\u00f3nak nevezni. A szab\u00e1lyz\u00f3 elrendez\u00e9s\u00e9t 10. \u00c1bra mutatja, a kimeneti karakterisztik\u00e1t a 11. \u00c1bra. L\u00e1thatjuk, hogy a hiba val\u00f3ban elt\u0171nt, ugyanakkor a kezdeti tranziens szakasz is megv\u00e1ltozott. Megjelent a t\u00fallend\u00fcl\u00e9s, ezzel egy\u00fctt a c\u00e9l\u00e9rt\u00e9k k\u00f6r\u00fcli oszcill\u00e1ci\u00f3, tov\u00e1bb\u00e1 a be\u00e1ll\u00e1s is lassabb lett.

10. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3 100-as er\u0151s\u00edt\u00e9ssel \u00e9s integr\u00e1tor, 10-es er\u0151s\u00edt\u00e9ssel.

11. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3 100-as er\u0151s\u00edt\u00e9ssel \u00e9s integr\u00e1tor, 10-es er\u0151s\u00edt\u00e9ssel.

A fenti be\u00e1ll\u00e1si oszcill\u00e1ci\u00f3t \u00e9s t\u00fallend\u00fcl\u00e9st jav\u00edthatjuk a param\u00e9terek megv\u00e1ltoztat\u00e1s\u00e1val, illetve egy olyan szab\u00e1lyz\u00f3 tag hozz\u00e1ad\u00e1s\u00e1val, amely a hiba v\u00e1ltoz\u00e1s\u00e1ra reag\u00e1l. Ez gyors\u00edtja a be\u00e1ll\u00e1st, \u00e9s a t\u00fallend\u00fcl\u00e9st is gyorsabban kompenz\u00e1lja. Ez gyakorlatilag a hiba v\u00e1ltoz\u00e1s\u00e1val ar\u00e1nyos tagot jelent, ami egyen\u00e9rt\u00e9k\u0171 a hiba deriv\u00e1ltj\u00e1nak figyelembev\u00e9tel\u00e9vel. Ezt a tagot szok\u00e1s D tagnak nevezni, a kialakul\u00f3 szab\u00e1lyz\u00f3t PID szab\u00e1lyz\u00f3nak nevezni. Ugyanakkor a D tag er\u0151s\u00edt\u00e9s\u00e9t \u00f3vatosan kell megv\u00e1lasztani, mert k\u00f6nnyen instabill\u00e1 teheti a rendszert. A szab\u00e1lyz\u00f3 fel\u00e9p\u00edt\u00e9s\u00e9t a 12. \u00c1bra mutatja, a karakterisztik\u00e1j\u00e1t a 13. \u00c1bra.

12. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3 100-as er\u0151s\u00edt\u00e9ssel \u00e9s integr\u00e1tor, 10-es er\u0151s\u00edt\u00e9ssel, D tag 10-es er\u0151s\u00edt\u00e9ssel.

13. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3 100-as er\u0151s\u00edt\u00e9ssel \u00e9s integr\u00e1tor 10-es er\u0151s\u00edt\u00e9ssel, D tag 10-es er\u0151s\u00edt\u00e9ssel.

Empirikus \u00faton, figyelembe v\u00e9ve a t\u00fallend\u00fcl\u00e9s m\u00e9rt\u00e9k\u00e9t, a be\u00e1ll\u00e1si id\u0151t \u00e9s az \u00e1lland\u00f3sult \u00e1llapotbeli hib\u00e1t, v\u00e1lasszuk a k\u00f6vetkez\u0151 param\u00e9ter \u00e9rt\u00e9keket:

\\[ P=175, I=10, D=50 \\]

Ezzel a be\u00e1ll\u00e1s m\u00e1r nagyon sz\u00e9p, az eredm\u00e9nyt a 14. \u00c1bra mutatja. 14. \u00c1bra: ar\u00e1nyos szab\u00e1lyz\u00f3, 170-es er\u0151s\u00edt\u00e9ssel, I tag 10-es er\u0151s\u00edt\u00e9ssel, D tag 50-es er\u0151s\u00edt\u00e9ssel.

A 15. \u00c1br\u00e1n l\u00e1that\u00f3, milyen hat\u00e1sa van, ha hozz\u00e1dunk egy 3\u00b0-os lejt\u0151 \u00e1ltal keltett extra gyors\u00edt\u00f3 er\u0151t. A t\u00fallend\u00fcl\u00e9s nagyobb lesz, hiszen a szab\u00e1lyz\u00f3t egy olyan modellel \u00e1ll\u00edtottuk be, amely s\u00edk talajon mozg\u00f3 aut\u00f3t felt\u00e9telez.

15. \u00c1bra: lejt\u0151 hat\u00e1sa a z\u00e1rt hurk\u00fa szab\u00e1lyz\u00f3ra.

Ezt kompenz\u00e1lhatjuk, ha a lejt\u0151vel ar\u00e1nyos el\u0151recsatolt \u00e1gat alkotunk meg. Azonban a lejt\u0151 becsl\u00e9se neh\u00e9z, \u00e1ltal\u00e1ban a j\u00e1rm\u0171 mozg\u00e1sa alapj\u00e1n k\u00f6vetkeztethet\u00fcnk r\u00e1, ami \u00edgy csak k\u00e9sve jelzi a lejt\u0151 m\u00e9rt\u00e9k\u00e9t. Adjunk hozz\u00e1 egy 1 s-mal eltolt, 5%-os hib\u00e1val rendelkez\u0151 lejt\u0151kompenz\u00e1ci\u00f3t. A blokkdiagramot a 16. \u00c1bra, az eredm\u00e9nyt a 17. \u00c1bra mutatja.

16. \u00c1bra: el\u0151recsatolt \u00e1ggal kieg\u00e9sz\u00edtett szab\u00e1lyz\u00f3 rendszer.

17. \u00c1bra: el\u0151recsatolt \u00e1g hat\u00e1sa a szab\u00e1lyz\u00f3ra.

"},{"location":"szabalyozas/#34-interaktiv-pid-hangolas","title":"3.4 Interakt\u00edv PID hangol\u00e1s","text":"

A k\u00f6vetkez\u0151kben a egy m\u00e1sik szab\u00e1lyoz\u00e1si p\u00e9lda (h\u0151m\u00e9rs\u00e9klet szab\u00e1lyoz\u00e1s) interakt\u00edv PID hangol\u00e1s\u00e1t lehet megtenni:

Ez az interakt\u00edv vizualiz\u00e1ci\u00f3 Mario Theers - CC BY 4.0 License megold\u00e1sa.

Hasonl\u00f3 interakt\u00edv vizualiz\u00e1ci\u00f3 \u00e9rhet\u0151 el a Viktor.ai oldalon, de itt m\u00e9g hangolni is van lehet\u0151s\u00e9g\u00fcnk: cloud.viktor.ai/public/control-application

"},{"location":"szabalyozas/#osszegzes","title":"\u00d6sszegz\u00e9s","text":"

Ebben a fejezetben \u00e1ttekintett\u00fck a szab\u00e1lyz\u00e1stechnikai alapfogalmakat, p\u00e9ld\u00e1kat hoztunk a j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1s ter\u00fclet\u00e9r\u0151l. Ezen k\u00edv\u00fcl a gyakorlatban megalkottunk egy egyszer\u0171 matematikai modellt, amely le\u00edrja egy j\u00e1rm\u0171, mint t\u00f6megpont hosszir\u00e1ny\u00fa mozg\u00e1s\u00e1t. Ezen kereszt\u00fcl MATLAB/Simulink seg\u00edts\u00e9g\u00e9vel sebess\u00e9gszab\u00e1lyz\u00e1ssal kapcsolatos szimul\u00e1ci\u00f3t v\u00e9gezt\u00fcnk. Az egyik legelterjedtebb szab\u00e1lyz\u00f3t, a PID szab\u00e1lyz\u00f3t mutattuk be. A k\u00f6vetkez\u0151 pontokat \u00e9rdemes megjegyezni: - egy z\u00e1rthurk\u00fa szab\u00e1lyz\u00e1s \u00e1ltal\u00e1ban \u00e1ll a szab\u00e1lyzott szakaszb\u00f3l (mely a val\u00f3s fizikai rendszer absztrakt matematikai modellje) \u00e9s a szab\u00e1lyz\u00f3b\u00f3l. - a val\u00f3s fizikai rendszert matematikai modellel \u00edrjuk le, amely alapj\u00e1n tervezhet\u0151 a szab\u00e1lyz\u00f3 is. A modell pontoss\u00e1ga befoly\u00e1solja a megtervezett szab\u00e1lyz\u00f3 min\u0151s\u00e9g\u00e9t is. - a matematikai modell \u00e1ltal\u00e1ban differenci\u00e1legyenletek form\u00e1j\u00e1ban \u00e1ll el\u0151. - a PID szab\u00e1lyz\u00f3k a hiba minimaliz\u00e1l\u00e1s\u00e1ra t\u00f6rekednek. A P tag gyors\u00edtja a rendszert, az I tag elt\u00fcnteti a maradand\u00f3 hib\u00e1t, a D tag szint\u00e9n gyors\u00edtja a szab\u00e1lyz\u00f3 reakci\u00f3j\u00e1t, de instabilit\u00e1st is okozhat. - a val\u00f3s\u00e1gban a j\u00e1rm\u0171szab\u00e1lyz\u00e1s \u00f6sszetett, a v\u00e1ltoz\u00f3 param\u00e9terek (pl. aut\u00f3 t\u00f6mege), az \u00fatviszonyok illetve az egym\u00e1sba \u00e1gyazott szab\u00e1lyz\u00f3 hurkok miatt.

"},{"location":"szabalyozas/#4-jarmuiranyitasi-megoldasok","title":"4. J\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si megold\u00e1sok","text":"

A j\u00e1rm\u0171szab\u00e1lyz\u00e1s ter\u00fclet\u00e9n - ahogy azt a 2. alfejezetben l\u00e1ttuk - t\u00f6bb, egym\u00e1sba \u00e1gyazott szab\u00e1lyz\u00f3 k\u00f6rt haszn\u00e1lunk. Mindegyik jellemz\u0151en tartalmaz egy el\u0151re csatolt \u00e9s egy visszcsatolt \u00e1gat. Automatiz\u00e1lt vezet\u00e9si rendszerek eset\u00e9n \u00e1ltal\u00e1ban a legfels\u0151, \u00fan. j\u00e1rm\u0171szint\u0171 ir\u00e1ny\u00edt\u00e1st szoktuk legel\u0151re venni. Az alacsonyabb szint\u0171 szab\u00e1lyz\u00f3kra most nem t\u00e9r\u00fcnk ki, csup\u00e1n egy lista erej\u00e9ig \u00f6sszegezz\u00fck \u0151ket. Meg kell jegyezni, hogy ezek az alacsonyszint\u0171 szab\u00e1lyz\u00f3k nagyban f\u00fcggnek a j\u00e1rm\u0171ben el\u00e9rhet\u0151 aktu\u00e1torokt\u00f3l, hiszen t\u00f6bbf\u00e9le f\u00e9krendszer, hajt\u00e1s \u00e9s korm\u00e1nyrendszer is el\u00e9rhet\u0151 lehet. Ez a feloszt\u00e1s nagyban t\u00e1mogatja modul\u00e1ris tervez\u00e9st, azaz a j\u00e1rm\u0171szint\u0171 szab\u00e1lyz\u00e1st f\u00fcggetlen\u00fcl tudjuk fejleszteni az alacsony szint\u0171 szab\u00e1lyz\u00e1sokt\u00f3l. Ez pl. sorozatgy\u00e1rtott szoftverek eset\u00e9n nagyban megk\u00f6nny\u00edti az \u00fajrahasznos\u00edthat\u00f3s\u00e1got. Az alacsony szint\u0171, aktu\u00e1tor szab\u00e1lyz\u00f3 hurkok a k\u00f6vetkez\u0151k lehetnek (a teljess\u00e9g ig\u00e9nye n\u00e9lk\u00fcl): - korm\u00e1ny szerv\u00f3 motor sz\u00f6gszab\u00e1lyz\u00e1s - korm\u00e1ny szerv\u00f3 motor nyomat\u00e9kszab\u00e1lyz\u00e1s - motor nyomat\u00e9k szab\u00e1lyz\u00e1s - f\u00e9k er\u0151 szab\u00e1lyz\u00e1s (f\u00e9k nyom\u00e1s szab\u00e1lyz\u00e1s).

Innent\u0151l minden meg\u00e1llap\u00edt\u00e1s a j\u00e1rm\u0171 szintj\u00e9re vonatkozik. Fontos megjegyezni, hogy mindig k\u00e9t dimenzi\u00f3ban gondolkodunk: hosszir\u00e1ny\u00fa \u00e9s keresztir\u00e1ny\u00fa szab\u00e1lyz\u00e1sban. A hosszir\u00e1ny\u00fa szab\u00e1lyz\u00e1sra l\u00e1ttunk p\u00e9ld\u00e1t a 3. alfejezetben. Ez \u00e1ltal\u00e1ban a sebess\u00e9g szab\u00e1lyz\u00e1s\u00e1t, esetleg a gyorsul\u00e1s szab\u00e1lyz\u00e1s\u00e1t jelenti. Hab\u00e1r a hosszir\u00e1ny\u00fa szab\u00e1lyz\u00e1s is rejt nem lev\u00e9s kih\u00edv\u00e1st (a motor tehetetlens\u00e9ge, a f\u00e9k- \u00e9s hajt\u00f3er\u0151k sz\u00e9tv\u00e1laszt\u00e1sa...stb.), a legt\u00f6bb j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si megold\u00e1s els\u0151sorban a keresztir\u00e1ny\u00fa szab\u00e1lyz\u00e1sra \u00f6sszpontos\u00edt. Mivel a j\u00e1rm\u0171 automatikus ir\u00e1ny\u00edt\u00e1si feladata nagyban hasonl\u00edt az emberek vezet\u00e9si feladat\u00e1hoz (teh\u00e1t a korm\u00e1ny \u00e9s a ped\u00e1lok seg\u00edts\u00e9g\u00e9vel a j\u00e1rm\u0171 mozg\u00e1s\u00e1nak befoly\u00e1sol\u00e1sa), ez\u00e9rt szok\u00e1s ezeket az ir\u00e1ny\u00edt\u00e1si megold\u00e1sokat vezet\u0151i modelleknek (angolul driver models) is h\u00edvni. Az egyes modellekr\u0151l r\u00f6vid \u00f6sszefoglal\u00f3kat tal\u00e1lunk az aj\u00e1nlott irodalom alatt. Ezek k\u00f6z\u00fcl [1] szerint 3 csoportra oszthatjuk a vezet\u0151i modelleket: - Inverz-modellek (inverse models) - Predikt\u00edv modellek (predictive/forward models) - Z\u00e1rhurk\u00fa modellek (closed loop models).

18. \u00c1bra: j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1si megold\u00e1sok szeml\u00e9ltet\u00e9se.

"},{"location":"szabalyozas/#inverz-modellek","title":"Inverz modellek","text":"

Az inverz modelleket angol terminol\u00f3gi\u00e1ban pursuit modelleknek is szok\u00e1s h\u00edvni, amely a legjobban tal\u00e1n el\u0151re tekint\u0151, el\u0151re tol\u00f3nak lehet ford\u00edtani. A l\u00e9nyege, hogy a korm\u00e1nyz\u00e1shoz sz\u00fcks\u00e9ges c\u00e9l\u00e9rt\u00e9ket az k\u00e9t inform\u00e1ci\u00f3 alapj\u00e1n hat\u00e1rozza meg: - egy el\u0151retekint\u00e9si pontban mi a j\u00e1rm\u0171 c\u00e9l\u00e1llapota? - a j\u00e1rm\u0171r\u0151l el\u0151zetesen fel\u00e1ll\u00edtott modell. Ezt felfoghatjuk \u00fagy is, mint egy el\u0151recsatolt szab\u00e1lyz\u00e1si \u00e1g, avagy egy ny\u00edlthurk\u00fa szab\u00e1lyz\u00e1s, azaz vez\u00e9rl\u00e9s. Amennyiben ez ut\u00f3bbi \u00e1ll fent (azaz nincs visszacsatolt \u00e1g), azt nevezz\u00fck tiszt\u00e1n el\u0151re tekint\u0151, ismertebb angol nev\u00e9n pure-pursuit ir\u00e1ny\u00edt\u00e1snak.

Warning

A pure-pursuit megold\u00e1s az egyik legr\u00e9gebbi ir\u00e1ny\u00edt\u00e1si megold\u00e1s a j\u00e1rm\u0171vek ter\u00e9n. M\u00e1r az 1980as \u00e9vekben a Robotics Institute of Pittsburgh fejlesztette ki [4]. A l\u00e9nyege, hogy egy megadott el\u0151retekint\u00e9si t\u00e1vols\u00e1gban (ami az ir\u00e1ny\u00edt\u00e1s legfontosabb param\u00e9tere) meghat\u00e1rozzuk a j\u00e1rm\u0171 k\u00edv\u00e1nt poz\u00edci\u00f3j\u00e1t (pl. a kor\u00e1bban tervezett trajekt\u00f3ria alapj\u00e1n).

Ennek a pontnak a koordin\u00e1t\u00e1i alapj\u00e1n meg tudjuk hat\u00e1rozni, milyen g\u00f6rb\u00fclet\u0171 k\u00f6r\u00edven kell haladnunk ahhoz, hogy az aktu\u00e1lis pontb\u00f3l a c\u00e9lpontba \u00e9rj\u00fcnk. Fontos, hogy a pure-pursuit megold\u00e1s mindig k\u00f6r\u00edveket haszn\u00e1l. A geometriai \u00f6sszef\u00fcgg\u00e9seket a 19. \u00c1bra szeml\u00e9lteti. Egyszer\u0171 trigonometriai megfontol\u00e1sok alapj\u00e1n a k\u00f6vetkez\u0151 \u00f6sszef\u00fcgg\u00e9st \u00edrhatjuk fel az el\u0151retekint\u00e9si pont \u00e9s a c\u00e9lg\u00f6rb\u00fclet k\u00f6z\u00f6tt:

\\[ \\kappa_{target}=\\frac{2x}{l^2} \\]

Mint l\u00e1tjuk, a j\u00e1rm\u0171 szintj\u00e9n megfogalmaztunk egy mennyis\u00e9get (g\u00f6rb\u00fclet) a bemeneti trajekt\u00f3ria alapj\u00e1n, \u00edgy elm\u00e9letben teljes\u00edtett\u00fck a j\u00e1rm\u0171ir\u00e1ny\u00edt\u00e1s f\u0151 feladat\u00e1t. Azonban a megval\u00f3s\u00edt\u00e1s sor\u00e1n \u00e1ltal\u00e1ban olyan mennyis\u00e9get \u00e1ll\u00edtunk el\u0151, amely m\u00e1r az aktu\u00e1torok szintj\u00e9n \u00e9rtelmezhet\u0151. Ehhez haszn\u00e1ljuk a j\u00e1rm\u0171 modellj\u00e9t: \u00f6sszef\u00fcgg\u00e9st adunk meg a c\u00e9lg\u00f6rb\u00fclet \u00e9s korm\u00e1nysz\u00f6g k\u00f6z\u00f6tt. A leggyakrabban a j\u00e1rm\u0171 kinematikai bicikli modellj\u00e9t haszn\u00e1ljuk, azonban ez nagyobb sebess\u00e9gek eset\u00e9n (>10 km/h) nagyon pontatlan. A kinematikai bicikli modell \u00f6sszef\u00fcgg\u00e9seit felhaszn\u00e1lva megkaphatjuk a korm\u00e1nysz\u00f6get:

\\[ \\delta_f=atan(L_w*\\kappa) \\]

Ahol \\(L_w\\) a j\u00e1rm\u0171 tengelyt\u00e1vja.

Felt\u00e9telezz\u00fck a modellben, hogy a j\u00e1rm\u0171 els\u0151ker\u00e9k-korm\u00e1nyz\u00e1s\u00fa. A kapott sz\u00f6g az \u00fat-ker\u00e9k sz\u00f6g, amely a korm\u00e1nym\u0171 geometri\u00e1j\u00e1nak f\u00fcggv\u00e9ny\u00e9ben \u00e1tsz\u00e1m\u00edthat\u00f3 pl. szerv\u00f3 motor sz\u00f6gg\u00e9, \u00e9s \u00edgy k\u00f6zvetlen\u00fcl megval\u00f3s\u00edthat\u00f3.

19. \u00c1bra: a pure pursuit szab\u00e1lyz\u00f3 geometriai \u00f6sszef\u00fcgg\u00e9sei.

A 20. \u00c1br\u00e1n l\u00e1thatjuk, milyen hat\u00e1ssal van az el\u0151retekint\u00e9si t\u00e1vols\u00e1g a j\u00e1rm\u0171 viselked\u00e9s\u00e9re. Amennyiben t\u00fal k\u00f6zeli pontot v\u00e1lasztunk, a j\u00e1rm\u0171 hajlamos oszcill\u00e1ci\u00f3ra (ez hasonl\u00f3 hat\u00e1s, mint egy PID szab\u00e1lyz\u00f3 t\u00fal nagy P er\u0151s\u00edt\u00e9ssel). A t\u00fal nagy el\u0151retekint\u00e9si t\u00e1vols\u00e1g eset\u00e9n a reakci\u00f3 lassul, de pl. \u00e9lesebb kanyarokban a j\u00e1rm\u0171 hajlamos lesz kanyarlev\u00e1g\u00e1sra. Szok\u00e1s az el\u0151retekint\u00e9si t\u00e1vot adapt\u00edvan, pl. a sebess\u00e9g f\u00fcggv\u00e9ny\u00e9ben megadni. Ilyenkor gyakorlatilag el\u0151retekint\u00e9si id\u0151r\u0151l besz\u00e9l\u00fcnk.

20. \u00c1bra: a pure pursuit el\u0151retekint\u00e9si t\u00e1vols\u00e1g\u00e1nak hat\u00e1sa a j\u00e1rm\u0171 viselked\u00e9s\u00e9re

A pure-pursuit modellek tov\u00e1bbfejlesztett v\u00e1ltozatair\u00f3l pl. a [2] \u00e9s [3] cikkben olvashatunk.

"},{"location":"szabalyozas/#prediktiv-modellek","title":"Predikt\u00edv modellek","text":"

A predikt\u00edv modellek, hasonl\u00f3an a az inverz modellekhez a j\u00e1rm\u0171 modellj\u00e9n alapszanak. Azonban egy\u00fattal el\u0151re is tekintenek egy meghat\u00e1rozott horizonton: a modell seg\u00edts\u00e9g\u00e9vel becs\u00fclj\u00fck a j\u00e1rm\u0171 viselked\u00e9s\u00e9t el\u0151re, majd ennek f\u00fcggv\u00e9ny\u00e9ben a lehet\u0151 legjobb megold\u00e1st v\u00e1lasztjuk a jelenben. Teh\u00e1t ez esetben a j\u00f6v\u0151 valamilyen pontoss\u00e1g\u00fa inform\u00e1ci\u00f3it felhaszn\u00e1lva hozunk d\u00f6nt\u00e9st. Itt k\u00e9t esetet k\u00fcl\u00f6nb\u00f6ztet\u00fcnk meg: - receding horizon: azaz a j\u00f6v\u0151beli horizont folyamatosan tol\u00f3dik el\u0151tt\u00fcnk, mivel a megtervezett j\u00f6v\u0151beli viselked\u00e9snek mindig az els\u0151 elem\u00e9t hajtjuk csak v\u00e9gre, ezek ut\u00e1n \u00fajratervez\u00fcnk - proceeding horizon: a horizont k\u00f6zeledik fel\u00e9nk, azaz a j\u00f6v\u0151beli megtervezett viselked\u00e9st teljes eg\u00e9sz\u00e9ben v\u00e9grehajtjuk, \u00e9s csak ez ut\u00e1n tervez\u00fcnk \u00fajra.

Mivel a szab\u00e1lyz\u00e1s itt egyben egy mozg\u00e1stervez\u00e9st is jelent, \u00edgy a tervez\u00e9s eszk\u00f6zt\u00e1r\u00e1t is haszn\u00e1lnunk kell. Ezeket a szab\u00e1lyz\u00f3kat szok\u00e1s Optim\u00e1lis szab\u00e1lyz\u00f3knak, angolul Optimum controlsnak is h\u00edvni. Hiszen ebben az esetben az el\u0151retekint\u00e9si horizonton a modell seg\u00edts\u00e9g\u00e9vel megtervezz\u00fck azt a mozg\u00e1st, amely a legkisebb k\u00f6lts\u00e9get eredm\u00e9nyezi a megadott szempontok szerint. Itt visszautalunk a 3.2. alfejezet elej\u00e9n bevezetett szempontokra: - be\u00e1ll\u00e1si id\u0151 (gyorsas\u00e1g) - t\u00fallend\u00fcl\u00e9s m\u00e9rt\u00e9ke - \u00e1lland\u00f3sult \u00e1llapotbeli hiba - a szab\u00e1lyz\u00e1s energi\u00e1ja.

Mivel itt egy v\u00e9ges hossz\u00fas\u00e1g\u00fa id\u0151horizonton szeretn\u00e9nk az optim\u00e1lis mozg\u00e1st megtervezni, a fenti szab\u00e1lyz\u00f3 szempontok k\u00f6z\u00fcl a be\u00e1ll\u00e1si id\u0151t, a t\u00fallend\u00fcl\u00e9s m\u00e9rt\u00e9k\u00e9t tov\u00e1bb\u00e1 az \u00e1lland\u00f3sult \u00e1llapotbeli hib\u00e1t egy vektorba vonjuk \u00f6ssze \u00e9s ezen vektor elemeinek \u00f6sszeg\u00e9t szeretn\u00e9nk minimaliz\u00e1lni (1. krit\u00e9rium). A szab\u00e1lyz\u00e1s energi\u00e1ja voltak\u00e9pp a beavatkoz\u00f3 jel vektor\u00e1nak amplit\u00fad\u00f3j\u00e1val van \u00f6sszef\u00fcgg\u00e9sben. Azaz \u00fagy szeretn\u00e9nk el\u00e9rni min\u00e9l jobb eredm\u00e9nyt, hogy k\u00f6zben alacsony jellel hatunk a rendszerre (pl. min\u00e9l kev\u00e9sb\u00e9 szeretn\u00e9nk gyorsulni, vagy a korm\u00e1nyra nyomat\u00e9kot kifejteni...stb.). Ez a 2. krit\u00e9rium, amely ellent\u00e9tes ig\u00e9nyt jelent a szab\u00e1lyz\u00e1sra n\u00e9zve, mint az 1. krit\u00e9rium.

Ezeket a szab\u00e1lyz\u00f3kat szok\u00e1s Modell Predikt\u00edv Szab\u00e1lyz\u00f3knak (Model Predictive Controls, MPC) is h\u00edvni. A k\u00f6vetkez\u0151 egyenlet egy p\u00e9lda arra, hogyan \u00edrhatjuk fel a megoldand\u00f3 k\u00f6lts\u00e9gf\u00fcggv\u00e9nyt:

\\[ J(k)=\\sum_{i=1}^{N_p}\\|y(k+i)-y_{ref}(k+i)\\|^2_M + \\sum_{i=1}^{N_c-1}\\|\\Delta U(k+i)\\|^2_N \\]

Ahol:

  • \\(N_p\\): a predikci\u00f3s horizont, sz\u00e1m\u00edt\u00e1si ciklusban kifejezve (a modell figyelembe v\u00e9tele)
  • \\(k\\): az akut\u00e1lis sz\u00e1m\u00edt\u00e1si ciklus
  • \\(y(k+i)\\): az \\(i.\\) ciklusban a modell \u00e1ltal becs\u00fclt j\u00e1rm\u0171 keresztir\u00e1ny\u00fa poz\u00edci\u00f3
  • \\(y_{ref}(k+i)\\): az \\(i.\\) ciklusban a referencia poz\u00edci\u00f3 (c\u00e9l poz\u00edci\u00f3)
  • \\(N_c\\): a szab\u00e1lyz\u00e1si horizont (a bemenet figyelembe v\u00e9tele)
  • \\(\\Delta U\\): a bemeneti vektor n\u00f6vekm\u00e9ny a szab\u00e1lyz\u00e1si horizonton
  • \\(M\\) \u00e9s \\(N\\): a s\u00falym\u00e1trixok a hib\u00e1ra \u00e9s a bemeneti energi\u00e1ra.

Ilyen szab\u00e1lyz\u00f3kra tal\u00e1lunk p\u00e9ld\u00e1t [1], [5-7] irodalmakban. Az MPC-k el\u0151nye, hogy nagyon nagy pontoss\u00e1ggal, stabil szab\u00e1lyz\u00e1st adnak, amennyiben az alkalmazott modell nagy pontoss\u00e1g\u00fa. Ugyanakkor ez is a h\u00e1tr\u00e1nya, hiszen ha a modell nem megfelel\u0151, akkor a hiba exponenci\u00e1lisan eln\u0151het. Erre l\u00e1tunk p\u00e9ld\u00e1t a 21-23. \u00c1br\u00e1n. Mindegyik szimul\u00e1ci\u00f3ban egy kinematikai bicikli modellt haszn\u00e1ltunk az MPC megtervez\u00e9s\u00e9hez. A PID szab\u00e1lyz\u00f3 a poz\u00edci\u00f3hib\u00e1t minimaliz\u00e1lja. A szimul\u00e1ci\u00f3ban a j\u00e1rm\u0171 dinamikai modellj\u00e9t alkalmaztuk, mint val\u00f3s fizikai rendszer. L\u00e1that\u00f3, hogy 5 m/s-on az MPC egy\u00e9rtelm\u0171en jobban teljes\u00edt, mint a PID szab\u00e1lyz\u00f3, sokkal pontosabb \u00e9s stabilabb is. Azonban 2 m/s-on az MPC sz\u00e9tesik, az alacsony sebess\u00e9g miatt a modell \u00f6sszef\u00fcgg\u00e9sek nem lesznek \u00e9rv\u00e9nyesek. Hasonl\u00f3 figyelhet\u0151 meg a 23. \u00c1br\u00e1n is. A 22. \u00c1br\u00e1n azt l\u00e1tjuk, hogy 10 m/s-ig az MPC \u00e9s a PID is j\u00f3l teljes\u00edt, az MPC tov\u00e1bbra is jobb, mint a PID. Azonban 10 m/s felett a dinamikai hat\u00e1sok feler\u0151sdnek, \u00e9s a kinematikai modell nem megfelel\u0151. \u00cdgy az MPC instabill\u00e1 v\u00e1lik, m\u00edg a PID - b\u00e1r jelent\u0151s hib\u00e1val - tov\u00e1bbra is stabil m\u0171k\u00f6d\u00e9sre k\u00e9pes.

21. \u00c1bra: MPC \u00e9s PID szab\u00e1lyz\u00f3 \u00f6sszevet\u00e9se, kinematikai modell eset\u00e9n, kanyarod\u00e1s, alacsony sebess\u00e9geken

22. \u00c1bra: MPC \u00e9s PID szab\u00e1lyz\u00f3 \u00f6sszevet\u00e9se, kinematikai modell eset\u00e9n, kanyarod\u00e1s, magasabb sebess\u00e9geken

23. \u00c1bra: MPC \u00e9s PID szab\u00e1lyz\u00f3 \u00f6sszevet\u00e9se, kinematikai modell eset\u00e9n, k\u00f6rp\u00e1lya, alacsony sebess\u00e9geken

"},{"location":"szabalyozas/#zarthurku-modellek","title":"Z\u00e1rthurk\u00fa modellek","text":"

Az ilyen t\u00edpus\u00fa modellek, ahogy a neve is sugallja, a PID szab\u00e1lyz\u00f3k logik\u00e1j\u00e1n alapszanak. Jellemz\u0151en egy vagy t\u00f6bb visszacsatolt mennyis\u00e9g hib\u00e1j\u00e1t minimaliz\u00e1lj\u00e1k. Ilyen modellekre tal\u00e1lunk p\u00e9ld\u00e1t a [3] \u00e9s [8] irodalomban. A 24. \u00c1br\u00e1n a [3]-ban bemutatott p\u00e9lda illusztr\u00e1ci\u00f3j\u00e1t l\u00e1tjuk. Eszerint kijel\u00f6l\u00fcnk kett\u0151 el\u0151retekint\u00e9si pontot: egy k\u00f6zelit (a j\u00e1rm\u0171 el\u0151tt) \u00e9s egy t\u00e1volit (a horizonton). Hasonl\u00f3an a pure-pursuit megold\u00e1sokhoz, itt is azt vizsg\u00e1ljuk, hogyan juthatunk el a jelenlegi poz\u00edci\u00f3b\u00f3l a t\u00e1voliba. Azonban nem egy egyszer\u0171 g\u00f6rb\u00fcletsz\u00e1mol\u00e1ssal, hanem a hiba minimaliz\u00e1l\u00e1s\u00e1val \u00e9rj\u00fck ezt el, a k\u00f6vetkez\u0151 egyenlet szerint:

\\[ \\phi=k_f\\dot\\Theta_f + k_n\\dot\\Theta_n + k_i\\Theta_n \\]

Ahol:

  • \\(\\dot\\Theta_f\\) \u00e9s \\(\\dot\\Theta_n\\) a t\u00e1voli \u00e9s a k\u00f6zeli pont hozz\u00e1nk viszony\u00edtott ir\u00e1ny\u00e1nak megv\u00e1ltoz\u00e1sa (sz\u00f6gsebess\u00e9ge)
  • \\(\\Theta_n\\) a k\u00f6zeli pont ir\u00e1nya hozz\u00e1nk k\u00e9pest (sz\u00f6ge)
  • \\(k\\) tagok: s\u00falyok.
  • \\(\\phi\\): az \u00fat ker\u00e9k sz\u00f6g.

Ez az egyenlet fel\u00edr\u00e1s voltak\u00e9pp egy minimaliz\u00e1l\u00e1sa a sz\u00f6g hib\u00e1knak, hiszen a c\u00e9l, hogy mindig ir\u00e1nyba \u00e1lljunk. A visszacsatol\u00e1s a k\u00f6rnyezet \u00e9rz\u00e9kel\u00e9sb\u0151l j\u00f6n. A kimenet az \u00fat ker\u00e9k sz\u00f6g.

24. \u00c1bra: a dual-point ir\u00e1ny\u00edt\u00e1si megold\u00e1s szeml\u00e9ltet\u00e9se

A 25. \u00c1br\u00e1n a [8]-ban ismertetett megold\u00e1st l\u00e1tjuk. A l\u00e9nyege, hogy t\u00f6bb egym\u00e1sba \u00e1gyazott PID szab\u00e1lyz\u00f3 seg\u00edts\u00e9g\u00e9vel a poz\u00edci\u00f3 hib\u00e1t minimaliz\u00e1lja. Ehhez a szab\u00e1lyz\u00e1si feladatot sz\u00e9tbontja egy alacsony frekvenci\u00e1s szab\u00e1lyz\u00e1sra (poz\u00edci\u00f3 hiba) \u00e9s egy magasfrekvenci\u00e1s szab\u00e1lyz\u00e1sra (korm\u00e1nysz\u00f6g hiba). Az \u00e1tviteli f\u00fcggv\u00e9nyek egy-egy szab\u00e1lyz\u00f3t testes\u00edtenek meg, sorban a k\u00f6vetkez\u0151ket jelentik:

  • \\(G_c\\): a poz\u00edci\u00f3 szab\u00e1lyz\u00e1sa egy PI szab\u00e1lyz\u00f3val
  • \\(G_L\\): az emberi szab\u00e1lyz\u00e1s k\u00e9s\u00e9se (reakci\u00f3ideje)
  • \\(G_NM\\): a neuromotoros szab\u00e1lyz\u00e1s, ahogyan az emberek a korm\u00e1nyt mozgatj\u00e1k. Ennek dinamik\u00e1ja nagyban f\u00fcgg az emberek izomszerkezet\u00e9t\u0151l.
  • \\(G_{P1}\\) \u00e9s \\(G_{P2}\\): a visszacsatol\u00e1sba illesztett \u00e9rz\u00e9kel\u0151 modellek. Ezek reprezent\u00e1lj\u00e1k az ember \u00e9rz\u00e9kel\u00e9si dinamik\u00e1j\u00e1t, sorban a korm\u00e1nyon l\u00e9v\u0151 nyomat\u00e9k \u00e9s a korm\u00e1ny sz\u00f6g tekint\u00e9tben.

26. \u00c1bra: egy teljes z\u00e1rthurk\u00fa szab\u00e1lyz\u00f3, egyes\u00edtve a korm\u00e1nysz\u00f6g szab\u00e1lyz\u00e1ssal

"},{"location":"szabalyozas/#osszefoglalas","title":"\u00d6sszefoglal\u00e1s","text":"

Mint l\u00e1ttuk a vezet\u0151i modellek minden esetben egy kor\u00e1bban megtervezett trajekt\u00f3ri\u00e1t ig\u00e9nyelnek. Ennek lek\u00f6vet\u00e9s\u00e9re haszn\u00e1ljuk a szab\u00e1lyz\u00f3kat, amelyek a k\u00f6vetkez\u0151 h\u00e1rom csoportba oszthat\u00f3k:

  • Inverz-modellek (inverse models)
  • Predikt\u00edv modellek (predictive/forward models)
  • Z\u00e1rhurk\u00fa modellek (closed loop models).

A legr\u00e9gebbi inverz-modellek a legegyszer\u0171bbek \u00e9s robosztusabbak, azonban a teljes\u00edtm\u00e9ny\u00fck jellemz\u0151en alacsony. A predikt\u00edv modellek nagyon pontosak, ugyanakkor nagyon \u00e9rz\u00e9kenyek a modell pontoss\u00e1g\u00e1ra. A z\u00e1rthurk\u00fa modellek nagy tartom\u00e1nyon stabilak, ugyanakkor \u00e1ltal\u00e1nos pontoss\u00e1guk alacsony. T\u00f6bb egym\u00e1sba \u00e1gyazott hurokb\u00f3l \u00e1llnak, melyek kalibr\u00e1ci\u00f3ja \u00e1ltal\u00e1ban bel\u00fclr\u0151l kifel\u00e9 t\u00f6rt\u00e9nik. Ezek a legelterjedtem a mai sorozatgy\u00e1rtott rendszerekben.

"},{"location":"szabalyozas/#ajanlott-irodalom","title":"Aj\u00e1nlott irodalom","text":"
  1. Introduction: System Modeling, University of Michigan
  2. Interactive Live Script Control Tutorials for MATLAB and Simulink
  3. Mario Theers - PID - CC BY 4.0 License
  4. Mario Theers - Pure pursuit - CC BY 4.0 License
  5. Youtube ControlLectures
  6. Bokor J\u00f3zsef & G\u00e1sp\u00e1r P\u00e9ter. Ir\u00e1ny\u00edt\u00e1stechnika
"},{"location":"szabalyozas/#vezetoi-modellek","title":"Vezet\u0151i modellek","text":"
  1. A. Y. Ungoren and H. Peng, \"An Adaptive Lateral Preview Driver Model,\" Vehicle System Dynamics, vol. 43, pp. 245-259, 2005.
  2. W. Rui, L. Ying, F. Jiahao, W. Tan and C. Xuetao, \"A Novel Pure Pursuit Algorithm for Autonomous Vehicles Based on Salp Swarm Algorithm and Velocity Controller,\" IEEE Access, vol. 8, pp. 166525-166540, 2020.
  3. D. Salvucci and R. Gray, \"A Two-Point Visual Control Model of Steering,\" Perception, vol. 33, pp. 1233-1248, 2004.
  4. C. R. Coulter, \"Implementation of the Pure Pursuit Path Tracking Algorithm,\" Vols. CMU-RI-TR-92-01, pp. 1-15, 1992.
  5. H. Jiang, H. Tian and Y. Hua, \"Model predictive driver model considering the steering characteristics of the skilled drivers,\" Advances in Mechanical Engineering, vol. 11, pp. 1-14, 2019.
  6. U. Kiencke, R. Majjad and S. Kramer, \"Modeling and performance analysis of a hybrid driver model,\" Control Engineering Practice, vol. 7, pp. 985-991, 1999.
  7. C. MacAdam, \"An Optimal Preview Control for Linear Systems,\" Journal of Dynamic Systems, Measurement and Control, vol. 102, pp. 188-190, 1980.
  8. R. Hess and A. Modjtahedzadeh, \"A Control Theoretic Model of Driver Steering Behavior,\" IEEE Control Systems Magazine, vol. 5, no. 8, pp. 3-8, 1990.
"},{"location":"szabalyozas/ros1practice/","title":"Gyakorlat","text":"

A gyakorlaton a robotverseny szimul\u00e1ci\u00f3t fogjuk haszn\u00e1lni. A szimul\u00e1tor linkenlt le\u00edr\u00e1s alapj\u00e1n telep\u00edthet\u0151.

Melodic

Noetic

"},{"location":"szabalyozas/ros1practice/#sebessegszabalyzo-pid-hangolasa","title":"Sebess\u00e9gszab\u00e1lyz\u00f3 PID hangol\u00e1sa","text":"

A k\u00f6vetkez\u0151 paranccsal egy \u00fcres (akad\u00e1lyok n\u00e9lk\u00fcli) szimul\u00e1ci\u00f3 indul. Ez a PID sebess\u00e9gszab\u00e1lyz\u00f3 hangol\u00e1s\u00e1ra alkalmas.

roslaunch racecar_gazebo racecar_empty.launch\n
roslaunch racecar_control cmd_vel_from_file.launch\n

Sz\u00fcks\u00e9g\u00fcnk lesz referencia jelek kiad\u00e1s\u00e1ra, megism\u00e9telhet\u0151 m\u00f3don. Ezt a p\u00e9ld\u00e1ban egy csv beolvas\u00e1sa, majd /cmd_vel topicon hirdet\u00e9se jelenti. Vizsg\u00e1ljuk meg a python f\u00e1jlt. A topic hirdet\u00e9se, a node ROS-ben t\u00f6rt\u00e9n\u0151 regisztr\u00e1l\u00e1sa, a csv f\u00e1jl beolvas\u00e1sa a f\u00e1jl elej\u00e9n tal\u00e1lhat\u00f3:

cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)\nrospy.init_node('cmd_vel_from_file', anonymous=True)\nrate = rospy.Rate(10) # 10hz\nmsg_twist = Twist()\ncsv_file = rospy.get_param('~csv')\nrospack = rospkg.RosPack()\npath = rospack.get_path('racecar_control')\nrospy.loginfo('csv file is: %s/config/%s' % (path, csv_file))\narray = pd.read_csv(path + '/config/' + csv_file, header = None).to_numpy()\nstart_time = rospy.Time.now()\n

A folyamatosan fut\u00f3 loop /cmd_vel.linear.x jeleket hirdet, a csv-ben tal\u00e1lhat\u00f3 id\u0151 szerint. A np.where visszaadja, hogy az aktu\u00e1lis id\u0151 szerint (current_time) milyen sebess\u00e9g indexn\u00e9l (itemindex) tartunk. Ez egy 2D array, ami minden, a felt\u00e9telnek megfelel\u0151 indexet tartalmaz, de sz\u00e1munkra persze csak ennek az els\u0151 eleme a fontos, ezt fogjuk hirdetni.

while not rospy.is_shutdown():\n    current_time = (rospy.Time.now() - start_time).to_sec()\n    itemindex = np.where(array[:,0] >= current_time)\n    try:\n        msg_twist.linear.x = array[itemindex[0][0],1]\n    except:\n        msg_twist.linear.x = 0.0\n    cmd_pub.publish(msg_twist)\n    rate.sleep()\n

A roscd parancs seg\u00edts\u00e9g\u00e9vel l\u00e9pj\u00fcnk a racecar_control package config mapp\u00e1j\u00e1ba.

roscd racecar_control/config/\n

Ez val\u00f3sz\u00edn\u0171leg a ~/sim_ws/src/racecar_gazebo/f1tenth/virtual/dependencies/racecar_control/config helyen tal\u00e1lhat\u00f3, de elk\u00e9pzelht\u0151, hogy valaki m\u00e1shova telep\u00edtette.

Innen bet\u00f6lthet\u00fcnk k\u00fcl\u00f6nb\u00f6z\u0151 PID be\u00e1ll\u00edt\u00e1sokat, pl:

rosparam load racecar_control01.yaml\nrosparam load racecar_control02.yaml\nrosparam load racecar_control03.yaml\n

Ellen\u0151rizz\u00fck a get paranccsal, a k\u00f6vetkez\u0151h\u00f6z hasnonl\u00f3 eredm\u00e9nyt fogunk kapni:

rosparam get /racecar/left_rear_wheel_velocity_controller/pid/\n{antiwindup: false, d: 0.0, i: 0.0, i_clamp: 0.0, i_clamp_max: 0.0, i_clamp_min: -0.0,\n  p: 5.0}\n

Note

Alternat\u00edvak\u00e9nt haszn\u00e1lhatjuk a rosrun rqt_reconfigure rqt_reconfigure parancsot is.

Futtassuk a k\u00f6vetkez\u0151 parancsot a sebess\u00e9g referencia kiad\u00e1s\u00e1ra:

roslaunch racecar_control cmd_vel_from_file.launch\n
A launch f\u00e1jlba megadhatjuk, hogy pl a 01.csv, 02.csv stb f\u00e1jlt t\u00f6ltse-e be. T\u00f6bbsz\u00f6r futtathatjuk, ak\u00e1r m\u00e1s PID be\u00e1ll\u00edt\u00e1sok mellett is.

Figyelj\u00fcnk meg k\u00e9t topicot pl Foxglove seg\u00edts\u00e9g\u00e9vel, k\u00fcl\u00f6nb\u00f6z\u0151 PID be\u00e1ll\u00edt\u00e1sok mellett: - /racecar/left_rear_wheel_velocity_controller/state.process_value - /racecar/left_rear_wheel_velocity_controller/command.data

"},{"location":"szabalyozas/ros1practice/#kormanyzas-pid-hangolasa","title":"Korm\u00e1nyz\u00e1s PID hangol\u00e1sa","text":"

A k\u00f6vetkez\u0151 parancsra, m\u00e1r nem \u00fcres, hanem egy k\u00f6rbeker\u00edtett versenyp\u00e1lya ny\u00edlik meg.

roslaunch racecar_gazebo racecar.launch\n

A p\u00e1lya a k\u00f6vetkez\u0151k\u00e9pp n\u00e9z ki:

"},{"location":"szabalyozas/ros2practice/","title":"Gyakorlat","text":"

A gyakorlat els\u0151 r\u00e9sz\u00e9ben egy p\u00e9lda els\u0151 illetve m\u00e1sodrend\u0171 rendszert fogunk haszn\u00e1lni, erre fogunk PID szab\u00e1lyz\u00f3t alkalmazni, majd hangolni. A gyakorlat m\u00e1sodik r\u00e9sz\u00e9ben egy szimul\u00e1lt trajekt\u00f3riak\u00f6vet\u0151 robot / j\u00e1rm\u0171 m\u0171k\u00f6d\u00e9s\u00e9t n\u00e9zz\u00fck \u00e1t \u00e9s hangoljuk.

  • 1. feladat: Trajekt\u00f3riak\u00f6vet\u00e9s szimul\u00e1ci\u00f3val
  • 2. feladat: Saj\u00e1t fejleszt\u00e9s\u0171 szab\u00e1lyz\u00f3 \u00e9s j\u00e1rm\u0171 modell
  • 3. feladat: PID hangol\u00e1s
"},{"location":"szabalyozas/ros2practice/#1-feladat-trajektoriakovetes-szimulacioval","title":"1. feladat: Trajekt\u00f3riak\u00f6vet\u00e9s szimul\u00e1ci\u00f3val","text":"

github.com/jkk-research/sim_wayp_plan_tools

"},{"location":"szabalyozas/ros2practice/#kovetelmenyek","title":"K\u00f6vetelm\u00e9nyek","text":"

A gyakorlat hibamentes lefut\u00e1s\u00e1hoz a k\u00f6vetkez\u0151 programok telep\u00edt\u00e9se sz\u00fcks\u00e9ges: - ROS 2 Humble: docs.ros.org/en/humble/Installation.html - Gazebo Fortress: gazebosim.org/docs/fortress/install_ubuntu, T\u00f6bb inform\u00e1ci\u00f3 az integr\u00e1l\u00e1sr\u00f3l: gazebosim.org/docs/fortress/ros2_integration - ros-gz-bridge Egy parancsal install\u00e1lhat\u00f3: sudo apt install ros-humble-ros-gz-bridge - Ellen\u0151riz\u00fck, hogy a colcon_cd megfelel\u0151en van telep\u00edtve. A csv f\u00e1jlok a colcon_cd-vel t\u00f6lt\u0151dnek be.

"},{"location":"szabalyozas/ros2practice/#package-ek-es-build","title":"Package-ek \u00e9s build","text":"

Az alap\u00e9rtelmezett workspace a k\u00f6vetkez\u0151 legyen:~/ros2_ws/.

"},{"location":"szabalyozas/ros2practice/#klonozuk-le-a-package-eket","title":"Kl\u00f3nozuk le a package-eket","text":"
cd ~/ros2_ws/src\n
git clone https://github.com/jkk-research/wayp_plan_tools\n
git clone https://github.com/jkk-research/sim_wayp_plan_tools\n
"},{"location":"szabalyozas/ros2practice/#ros-2-es-package-ek-buildelese","title":"ROS 2 -es package-ek buildel\u00e9se","text":"

cd ~/ros2_ws\n
colcon build --packages-select wayp_plan_tools sim_wayp_plan_tools\n

"},{"location":"szabalyozas/ros2practice/#wayp_plan_tools-hasznalata-szimulatorkent","title":"wayp_plan_tools haszn\u00e1lata szimul\u00e1tork\u00e9nt","text":""},{"location":"szabalyozas/ros2practice/#11-a-gazebo-inditasa","title":"1.1. A gazebo ind\u00edt\u00e1sa","text":"
ign gazebo -v 4 -r ackermann_steering.sdf\n
"},{"location":"szabalyozas/ros2practice/#12-a-gazebo-bridge-inditasa","title":"1.2. A Gazebo bridge ind\u00edt\u00e1sa","text":"

Ha esetleg nem lenne telep\u00edtve a bridge, a k\u00f6vetkez\u0151 parancsok seg\u00edtenek:

sudo apt update\n

sudo apt install ros-humble-ros-gz -y\n

Tanteremben pedig:

cd /mnt/kozos/script\n
./gz_bridge.sh\n

Ne felejts\u00fcnk el source-olni az ROS-es parancsok el\u0151tt.

source ~/ros2_ws/install/local_setup.bash\n
ros2 launch sim_wayp_plan_tools gazebo_bridge.launch.py\n

Ez a launch f\u00e1jl a k\u00f6vetkez\u0151 node-okat ind\u00edtja el egyben:

ros2 run ros_gz_bridge parameter_bridge /world/ackermann_steering/pose/info@geometry_msgs/msg/PoseArray[ignition.msgs.Pose_V\n
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist\n
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry --ros-args -r /model/vehicle_blue/odometry:=/odom\n
T\u00f6bb inform\u00e1ci\u00f3 a bridge-r\u0151l: github.com/gazebosim/ros_gz/blob/ros2/ros_gz_bridge/README.md

Ez a launch a PoseArray-b\u0151l egy /tf-et is k\u00e9sz\u00edt a pose_arr_to_tf.

"},{"location":"szabalyozas/ros2practice/#opcionalis-a-gazebo-ban-levo-robot-iranyitasa-billentyuzettel","title":"Opcion\u00e1lis: A gazebo-ban l\u00e9v\u0151 robot ir\u00e1ny\u00edt\u00e1sa billenty\u0171zettel:","text":"
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/model/vehicle_blue/cmd_vel\n
"},{"location":"szabalyozas/ros2practice/#13-waypointok-betoltese","title":"1.3. Waypointok bet\u00f6lt\u00e9se","text":"

Megjegyz\u00e9s: A waypointok egy ponthalmaz, amely az \u00fatvonal poz\u00edci\u00f3, orient\u00e1ci\u00f3 \u00e9s sebess\u00e9g adatait tartalmazza diszkr\u00e9t pontokra osztva. Ezeket az adatokat jellemz\u0151en \u00fagy nyerj\u00fck ki hogy az \u00fatunk sor\u00e1n ROS-ben r\u00f6gz\u00edtj\u00fck a gps-t\u0151l vagy az odometri\u00e1t\u00f3l az x,y esetleg z koordin\u00e1t\u00e1kat, az aktu\u00e1lishoz k\u00e9pest a k\u00f6vetkez\u0151 pontra mutat\u00f3 orient\u00e1ci\u00f3t \u00e9s az \u00e9ppen aktu\u00e1lis sebess\u00e9g adatot. V\u00e9g\u00fcl az im\u00e9nt felsoroltakat csv f\u00e1jlokban r\u00f6gz\u00edtj\u00fck.

Haszn\u00e1ljuk a ROS 2-es workspacet file_dir-k\u00e9nt:

ros2 run wayp_plan_tools waypoint_loader --ros-args -p file_name:=sim_waypoints1.csv -p file_dir:=$HOME/ros2_ws/src/sim_wayp_plan_tools/csv -r __ns:=/sim1\n
Vagy az alapparam\u00e9terekel:

ros2 launch sim_wayp_plan_tools waypoint_loader.launch.py\n
"},{"location":"szabalyozas/ros2practice/#14-waypoint-goal-pose-kent","title":"1.4. Waypoint goal pose-k\u00e9nt","text":"

Ahogy az elm\u00e9leti r\u00e9sz 4. fejezetben az \u00e1br\u00e1kon l\u00e1that\u00f3, minden szab\u00e1lyoz\u00e1si algoritmushoz tartozik egy vagy t\u00f6bb goal pose amire az \u00e9ppen m\u0171k\u00f6d\u0151 szab\u00e1lz\u00f3 szab\u00e1lyoz.

ros2 run wayp_plan_tools waypoint_to_target --ros-args -p lookahead_min:=2.5 -p lookahead_max:=4.5 -p mps_alpha:=1.5 -p mps_beta:=3.5 -p waypoint_topic:=waypointarray -p tf_frame_id:=base_link -p tf_child_frame_id:=map -r __ns:=/sim1\n
Vagy az alapparam\u00e9terekel:

ros2 launch sim_wayp_plan_tools waypoint_to_target.launch.py\n
"},{"location":"szabalyozas/ros2practice/#15-a-szabalyzas-inditasa","title":"1.5. A szab\u00e1lyz\u00e1s ind\u00edt\u00e1sa:","text":"

T\u00f6bb lehet\u0151s\u00e9g van: - single_goal_pursuit: Pure pursuit (for vehicles / robots), a simple cross-track error method - multiple_goal_pursuit: Multiple goal pursuit for vehicles / robots an implementation of our paper - stanley_control: Stanley controller, a heading error + cross-track error method - follow_the_carrot: Follow-the-carrot, the simplest controller

Egy p\u00e9lda a pure pursuit-ra :

ros2 run wayp_plan_tools single_goal_pursuit --ros-args -p cmd_topic:=/model/vehicle_blue/cmd_vel -p wheelbase:=1.0 -p waypoint_topic:=targetpoints -r __ns:=/sim1\n
Vagy az alapparam\u00e9terekel:

ros2 launch sim_wayp_plan_tools single_goal_pursuit.launch.py\n
"},{"location":"szabalyozas/ros2practice/#16-az-eredmenyek-vizualizalasa-rviz2-ben","title":"1.6. Az eredm\u00e9nyek vizualiz\u00e1l\u00e1sa RViz2-ben:","text":"

ros2 launch sim_wayp_plan_tools rviz1.launch.py\n
Vagy futtasunk mindent egy\u00fctt egyetlen parancsal:

After ign gazebo -v 4 -r ackermann_steering.sdf (terminal 1) and source ~/ros2_ws/install/local_setup.bash (terminal 2), run this command (also in terminal 2):

ros2 launch sim_wayp_plan_tools all_in_once.launch.py\n

"},{"location":"szabalyozas/ros2practice/#hibaelharitas","title":"Hibaelh\u00e1r\u00edt\u00e1s","text":"

A ign gazebo server le\u00e1ll\u00edt\u00e1sa:

ps aux | grep ign\n
ab  12345 49.9  1.2 2412624 101608 ?      Sl   08:26  27:20 ign gazebo server\nab  12346  518  6.6 10583664 528352 ?     Sl   08:26 283:45 ign gazebo gui\nab  12347  0.0  0.0   9396  2400 pts/2    S+   09:21   0:00 grep --color=auto ign\n

Ha azonos\u00edtva van a PID a folyamat le\u00e1ll\u00edt\u00e1s\u00e1hoz haszn\u00e1ld a kill parancsot. P\u00e9ld\u00e1ul a gazebo szerver le\u00e1ll\u00edt\u00e1s\u00e1hoz:

kill 12345\n
"},{"location":"szabalyozas/ros2practice/#2-feladat-sajat-fejlesztesu-szabalyzo-es-jarmu-modell","title":"2. feladat: Saj\u00e1t fejleszt\u00e9s\u0171 szab\u00e1lyz\u00f3 \u00e9s j\u00e1rm\u0171 modell","text":"

Ebben a feladatban elk\u00e9sz\u00edtj\u00fck az elm\u00e9leten bemutatott sebess\u00e9g szab\u00e1lyz\u00f3t, \u00e9s az ahhoz kapcsol\u00f3d\u00f3 egyszer\u0171 j\u00e1rm\u0171modellt.

Ha ezt eddig nem tett\u00fck meg, friss\u00edts\u00fck az arj_packages repository-t:

git pull\n

Navig\u00e1ljunk a workspace src mapp\u00e1j\u00e1ban a repo gy\u00f6k\u00e9rmapp\u00e1j\u00e1ba:

cd ~ros2_ws/src/arj_packages\n

Vizsg\u00e1ljuk meg a repository tartalm\u00e1t:

dir\n
L\u00e1tjuk, hogy megjelent egy speed_control_loop nev\u0171 almappa. Ez a mappa tartalmazza a szab\u00e1lyz\u00e1shoz haszn\u00e1lt j\u00e1rm\u0171modellt \u00e9s a szab\u00e1lyz\u00f3t. Nyissuk meg a forr\u00e1sk\u00f3dot VS Code seg\u00edts\u00e9g\u00e9vel.

A mappa tartalmazza a szok\u00e1sos package xml-t \u00e9s a CMakeList-et, tov\u00e1bb\u00e1 k\u00e9t cpp forr\u00e1sf\u00e1jlt. A vehicle_model.cpp \u00e9rtelemszer\u0171en a j\u00e1rm\u0171modellt, a speed_controller.cpp a szab\u00e1lyz\u00f3t tartalmazza. Vizsg\u00e1ljuk el\u0151sz\u00f6r a j\u00e1rm\u0171 modell forr\u00e1sk\u00f3dj\u00e1t!

"},{"location":"szabalyozas/ros2practice/#jarmumodell","title":"J\u00e1rm\u0171modell","text":"
class VehicleModel : public rclcpp::Node\n{\npublic:\n    VehicleModel() : Node(\"vehicle_model\")\n    {\n        timer_ = this->create_wall_timer(std::chrono::milliseconds(200), std::bind(&VehicleModel::loop, this));  \n        state_pub_ = this->create_publisher<std_msgs::msg::Float32MultiArray>(\"/vehicle/state\", 10);\n        cmd_sub_ = this->create_subscription<std_msgs::msg::Float32>(\"/vehicle/propulsion\", 10,  std::bind(&VehicleModel::propulsion_callback, this, std::placeholders::_1));\n        RCLCPP_INFO(this->get_logger(), \"vehicle_model has been started\");\n    }\n

A szok\u00e1sos #include-ok \u00e9s n\u00e9vdefin\u00edci\u00f3k ut\u00e1n a j\u00e1rm\u0171modell oszt\u00e1ly konstruktora l\u00e1that\u00f3. A node neve \"vehicle_model\". Egy topic-ra iratkozunk fel, a /vehicle/propulsion nev\u0171re, amely a nev\u00e9b\u0151l is ad\u00f3d\u00f3dan a j\u00e1rm\u0171re hat\u00f3 hajt\u00f3er\u0151t adja meg. Ezen k\u00edv\u00fcl hirdetj\u00fck a /vehicle/state nev\u0171 topicot, mely megadja a j\u00e1rm\u0171 mozg\u00e1s\u00e1llapot\u00e1t.

Ezt k\u00f6vet\u0151en defini\u00e1lunk n\u00e9h\u00e1ny v\u00e1ltoz\u00f3t. 1. El\u0151sz\u00f6r egy lok\u00e1lis v\u00e1ltoz\u00f3t, melyben a bemeneti er\u0151t t\u00e1roljuk el. 2. Ezt k\u00f6veti egy t\u00f6mb, mely tartalmazni fogja a j\u00e1rm\u0171 sebess\u00e9g\u00e9t \u00e9s gyorsul\u00e1s\u00e1t, a k\u00e9t \u00e1llapotv\u00e1ltoz\u00f3t, melyekkel a j\u00e1rm\u0171 \u00e1llapot\u00e1t le\u00edrjuk. 3. Defini\u00e1lunk egy Fload nev\u0171 v\u00e1ltoz\u00f3t, amelyben megadhatjuk, milyen extra terhel\u00e9sek hassanak a j\u00e1rm\u0171re. 4. V\u00e9g\u00fcl defini\u00e1lunk n\u00e9h\u00e1ny nem v\u00e1ltoztathat\u00f3 param\u00e9tert, pl. a j\u00e1rm\u0171 s\u00faly\u00e1t, homlokfel\u00fclet\u00e9nek nagys\u00e1g\u00e1t...stb.

private:\n    // input command\n    float Fprop {0.0f};\n\n    // vehicle state array\n    std::vector<float> state; //speed, acceleration\n    float vx{0.0f};\n    float ax{0.0f};\n\n    // load\n    float Fload{0.0f};\n\n    // params\n    float m {1350.0}; // kg\n    float A {1.5f}; // m^2\n    float rho {1.0f}; // kg/m^3\n    float c {0.33f}; // aerodynamic factor\n    float b {0.1f}; // rolling friction, viscosous\n

A topic callback f\u00fcggv\u00e9ny kiz\u00e1r\u00f3lag a bej\u00f6v\u0151 adatot m\u00e1solja a lok\u00e1lis v\u00e1ltoz\u00f3nkba.

void propulsion_callback(const std_msgs::msg::Float32 input_msg)\n{\n    Fprop = input_msg.data;\n}\n

V\u00e9gezet\u00fcl a loop() f\u00fcggv\u00e9ny, melyben el\u0151sz\u00f6r sz\u00e1m\u00edtjuk az ellen\u00e1ll\u00e1si er\u0151ket (l\u00e9gellen\u00e1ll\u00e1s \u00e9s viszk\u00f3zus s\u00farl\u00f3d\u00e1s), majd sz\u00e1m\u00edtjuk az ered\u0151 er\u0151t \u00e9s ebb\u0151l a j\u00e1rm\u0171 gyorsul\u00e1s\u00e1t. A j\u00e1rm\u0171 gyorsul\u00e1s\u00e1t integr\u00e1lva kapjuk a j\u00e1rm\u0171 sebess\u00e9g\u00e9t.

void loop()\n{\n    // calculate new state based on load, prop force, mass and aerodynamic drag\n    float Faero = 0.5*A*rho*c*pow(vx,2);\n    float Ffric = b*vx;\n    ax = (Fprop - Ffric - Fload - Faero)/m;\n    vx = std::max(0.0f, vx + ax*0.1f); // 0.1s is the time step of the model\n\n    // Publish state\n    state.clear();\n    std_msgs::msg::Float32MultiArray state_msg;\n    state.push_back(vx); // m/s\n    state.push_back(ax); // m/s^2\n\n    state_msg.data = state;\n    state_pub_->publish(state_msg);\n}\n
"},{"location":"szabalyozas/ros2practice/#szabalyzo","title":"Szab\u00e1lyz\u00f3","text":"

A speed_control.cpp-ben a j\u00e1rm\u0171 sebess\u00e9g\u00e9nek PID szab\u00e1lyz\u00e1s\u00e1t l\u00e1thatjuk. A node neve \"speed_control\", feliratkozik a /vehicle/state topicra, melyet a j\u00e1rm\u0171 modell hirdet. Ezen k\u00edv\u00fcl hirdetj\u00fck a /vehicle/propulsion command topicot, egy\u00fattal feliratkozunk a /vehicle/cmd c\u00e9lsebess\u00e9get megad\u00f3 topicra. A szab\u00e1lyz\u00f3 l\u00e9nyege, hogy a user \u00e1ltal megadott sebess\u00e9get szab\u00e1lyozza \u00fagy, hogy el\u0151\u00e1ll\u00edtja a j\u00e1rm\u0171hajt\u00e1s sz\u00e1m\u00e1ra a c\u00e9ler\u0151t. A modell \u00e1llapot\u00e1t\u00f3l f\u00fcgg\u0151en n\u00f6velj\u00fck vagy cs\u00f6kkentj\u00fck a c\u00e9ler\u0151t.

class SpeedControl : public rclcpp::Node\n{\npublic:\n    SpeedControl() : Node(\"speed_control\")\n    {\n        timer_ = this->create_wall_timer(std::chrono::milliseconds(200), std::bind(&SpeedControl::loop, this));  \n\n        cmd_pub_ = this->create_publisher<std_msgs::msg::Float32>(\"/vehicle/propulsion\", 10);\n        state_sub_ = this->create_subscription<std_msgs::msg::Float32MultiArray>(\"/vehicle/state\", 10, std::bind(&SpeedControl::state_callback, this, std::placeholders::_1));\n        cmd_sub_ = this->create_subscription<std_msgs::msg::Float32>(\"/vehicle/cmd\", 10, std::bind(&SpeedControl::cmd_callback, this, std::placeholders::_1));\n\n        this->declare_parameter(\"/control/P\", 100.0f);\n        this->declare_parameter(\"/control/I\", 5.0f);\n        this->declare_parameter(\"/control/D\", 10.0f);\n\n        RCLCPP_INFO(this->get_logger(), \"speed_control has been started\");\n    }\n

A szab\u00e1lyz\u00e1st a loop() f\u00fcggv\u00e9nyben l\u00e1thatjuk. A P, I \u00e9s D param\u00e9terek ROS param\u00e9terk\u00e9nt \u00e1ll\u00edthat\u00f3k. A hajt\u00f3 er\u0151 3 t\u00e9nyez\u0151b\u0151l tev\u0151dik \u00f6ssze: a derivat\u00edv tagb\u00f3l (Fprop_D), az ar\u00e1nyos tagb\u00f3l (Fprop_P) \u00e9s az integr\u00e1lt tagb\u00f3l (Fprop_I). Ez egy p\u00e1rhuzamos PID strukt\u00fara, teh\u00e1t a h\u00e1rom tag \u00f6sszege adja ki a c\u00e9ler\u0151t.

void loop()\n    {\n        P = (float)this->get_parameter(\"/control/P\").as_double();\n        I = (float)this->get_parameter(\"/control/I\").as_double();\n        D = (float)this->get_parameter(\"/control/D\").as_double();\n        // calculate new state based on load, prop force, mass and aerodynamic drag\n        float Fprop_D = D*((vSet-vx)-error)/0.1;\n\n        float error = vSet-vx;\n        float Fprop_P = P*error;\n        float Fprop_I = I*integrated_error;\n\n        Fprop = Fprop_P+Fprop_I+Fprop_D;\n\n        Fprop = std::min(std::max(-Fprop_max, Fprop), Fprop_max);\n\n        // Publish cmd\n        std_msgs::msg::Float32 cmd_msg;\n        cmd_msg.data = Fprop;\n\n        cmd_pub_->publish(cmd_msg);\n\n        integrated_error+= error*0.1f;\n    }\n
"},{"location":"szabalyozas/ros2practice/#teszt","title":"Teszt","text":"

A teszthez el\u0151sz\u00f6r buildelj\u00fck a speed_control_loop packaget!

colcon build --packages-select speed_control_loop\n

Egy m\u00e1sik termin\u00e1lban, source-ol\u00e1s ut\u00e1n ind\u00edtsuk el el\u0151sz\u00f6r a vehicle_model node-ot, majd a speed_control node-ot! Ezt megtehetj\u00fck egyszer\u0171en az el\u0151re elk\u00e9sz\u00edtett run_all.launch.py launch f\u00e1jl seg\u00edts\u00e9g\u00e9vel is!

cd ~/ros2_ws/src/arj_packages/speed_control_loop\n
ros2 launch launch/run_all.launch.py\n

Nyissuk meg a Foxglove studiot. \u00c9s kapcsol\u00f3djunk a local host-hoz. Ahhoz, hogy a kapcsolat l\u00e9trej\u00f6jj\u00f6n, ind\u00edtsuk el a megfelel\u0151 bridge-et! Tegy\u00fck ezt egy \u00fajabb termin\u00e1lb\u00f3l!

cd ~/ros2_ws/\n
ros2 launch foxglove_bridge foxglove_bridge_launch.xml\n

Adjunk hozz\u00e1 3 plot panelt, majd v\u00e1lasszuk ki a k\u00e9pen l\u00e1that\u00f3 topicokat. Mivel m\u00e9g nem hat\u00e1roztuk meg a c\u00e9lsebess\u00e9get, \u00edgy az alap\u00e9rt\u00e9ken z\u00e9rus. A j\u00e1rm\u0171 gyakorlatilag \u00e1ll, a szab\u00e1lyz\u00f3 kimenete is z\u00e9rus.

Hirdess\u00fcnk k\u00e9zzel egy topicot, amely megadja a k\u00edv\u00e1nt sebess\u00e9get (pl. tempomat eset\u00e9n a korm\u00e1nyon be\u00e1ll\u00edtott c\u00e9lsebess\u00e9g)!

ros2 topic pub /vehicle/cmd std_msgs/msg/Float32 \"data: 30.0\"\n

Mit l\u00e1tunk? A szab\u00e1lyz\u00f3 egy ideig a megengedett legnagyobb gyorsul\u00e1ssal (kb. 9 m/s^2-el) gyors\u00edtja a j\u00e1rm\u0171vet, am\u00edg az el nem \u00e9ri a k\u00edv\u00e1nt 30 m/s-os sebess\u00e9get. Tov\u00e1bbi sebess\u00e9gekkel, illetve param\u00e9ter be\u00e1ll\u00edt\u00e1sokkal k\u00eds\u00e9rletezhet\u00fcnk.

P\u00e9ld\u00e1ul

rosparam set /speed_control /control/I 200.0\n

eset\u00e9n a sebess\u00e9g felfut\u00e1sa kev\u00e9sb\u00e9 lesz egyenletes, tov\u00e1bb\u00e1 t\u00fallend\u00fcl\u00e9s is megfigyelhet\u0151.

"},{"location":"szabalyozas/ros2practice/#3-feladat-pid-hangolas","title":"3. feladat: PID hangol\u00e1s","text":""},{"location":"szabalyozas/ros2practice/#video","title":"Vide\u00f3","text":"

A vide\u00f3hoz hasonl\u00f3 m\u00f3don szeretn\u00e9nk szeml\u00e9ltetni a szab\u00e1lyoz\u00e1s k\u00e9rd\u00e9sk\u00f6r\u00e9t, azonban mi Plotjuggler helyett Foxglove Studio-t haszn\u00e1lunk.

A k\u00f6vetkez\u0151 le\u00edr\u00e1s azzal a felt\u00e9telez\u00e9ssel \u00e9l, hogy a ROS 2 workspace a ~/ros2_ws/ helyen tal\u00e1lhat\u00f3.

"},{"location":"szabalyozas/ros2practice/#terminal-1-clone","title":"Terminal 1 clone","text":"

Kl\u00f3nozzuk a repositoryt:

cd ~/ros2_ws/src\n
git clone https://github.com/dottantgal/ros2_pid_library\n
"},{"location":"szabalyozas/ros2practice/#terminal-1-build","title":"Terminal 1 build","text":"

L\u00e9pj\u00fcnk vissza a workspace gy\u00f6ker\u00e9be \u00e9s build:

cd ~/ros2_ws\n
colcon build --packages-select use_library pid_library example_system\n
"},{"location":"szabalyozas/ros2practice/#terminal-2-run","title":"Terminal 2 run","text":"

\u00daj termin\u00e1lt nyissunk \u00e9s futtassuk a k\u00f6vetkez\u0151 parancsokat:

source ~/ros2_ws/install/local_setup.bash && source ~/ros2_ws/install/setup.bash\n
ros2 launch example_system example_sys_launch.py\n
"},{"location":"szabalyozas/ros2practice/#terminal-3-set-point","title":"Terminal 3 set point","text":"
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 \"data: 0.0\"\n
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 \"data: 1.0\"\n
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 \"data: 1.4\"\n
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 \"data: 0.6\"\n
"},{"location":"szabalyozas/ros2practice/#terminal-4-foxglove","title":"Terminal 4 foxglove","text":"

Ha esetleg eddig nem lett volna telep\u00edtve:

sudo apt install ros-humble-foxglove-bridge\n
Maga bridge \u00edgy ind\u00edthat\u00f3:
source ~/ros2_ws/install/local_setup.bash && source ~/ros2_ws/install/setup.bash\n
ros2 launch foxglove_bridge foxglove_bridge_launch.xml\n
Ezut\u00e1n Foxglove Studi\u00f3 seg\u00edts\u00e9g\u00e9vel ws://localhost:8765 c\u00edmen el\u00e9rhet\u0151 minden adat.

"},{"location":"szabalyozas/ros2practice/#vs-code","title":"VS code","text":"

Szerkessz\u00fck a example_sys_launch.py f\u00e1jlt, majd colcon build (terminal 1) source \u00e9s futtat\u00e1s.

code ~/ros2_ws/src/ros2_pid_library/\n

Futtassuk \u00e9s figyelj\u00fck meg az eredm\u00e9nyeket a beavatkoz\u00f3 jel (control_value) enyh\u00e9n m\u00e1s jelleget mutat:

"},{"location":"szabalyozas/ros2practice/#forrasok-sources","title":"Forr\u00e1sok / Sources","text":"
  • github.com/dottantgal/ros2_pid_library - MIT license
"},{"location":"szimulacio/","title":"Szimul\u00e1ci\u00f3","text":"

A szimul\u00e1ci\u00f3 sor\u00e1n sz\u00e1m\u00edt\u00f3g\u00e9pes modellen tanulm\u00e1nyozzuk a rendszer v\u00e1rhat\u00f3 viselked\u00e9s\u00e9s\u00e9t.

A szimul\u00e1ci\u00f3 l\u00e9nyege teh\u00e1t, hogy a kezdeti, ak\u00e1r komoly tesztel\u00e9s n\u00e9lk\u00fcli programk\u00f3dunkat ne a val\u00f3 vil\u00e1gban az \u00f6nvezet\u0151 aut\u00f3nkon / robotunkon kezdj\u00fck el kipr\u00f3b\u00e1lni. Ennek ugyanis \u00e9rtelemszer\u0171 h\u00e1tr\u00e1nyai lehetnek. Fontos azonban megjegyezni, hogy a szimul\u00e1tor mindig a val\u00f3s\u00e1g egyszer\u0171s\u00edtett modellj\u00e9t szimul\u00e1lja csup\u00e1n, \u00edgy a szimul\u00e1torban j\u00f3l m\u0171k\u00f6d\u0151 k\u00f3d nem mindig fog teljesen m\u0171k\u00f6dni a val\u00f3 \u00e9letben is.

Eddig egyed\u00fcl a Turtlesim nev\u0171 2D szimul\u00e1tort haszn\u00e1ltuk. Egyszer\u0171s\u00e9ge, oktat\u00e1si jellege miatt k\u00f6zkedvelt, de a 3D vil\u00e1g term\u00e9sztesen ennn\u00e9l sokkal \u00f6sszetettebb. C\u00e9lszer\u0171 lehet teh\u00e1t 3D szimul\u00e1torokat haszn\u00e1lni.

2D 3D Turtlesim Gazebo, Carla, SVL, AWSIM, MVsim

Az ROS-\u00e1ltal legink\u00e1bb t\u00e1mogatott szimul\u00e1tor a Gazebo, de \u00e9rdemes megeml\u00edteni az SVL-t, ebb\u0151l saj\u00e1t verzi\u00f3nk is van a Nissan-ra optimaliz\u00e1va, a Carla-t vagy a CoppeliaSim-et.

"},{"location":"szimulacio/#attekinto-video-a-szimulatorokrol","title":"\u00c1ttekint\u0151 vide\u00f3 a szimul\u00e1torokr\u00f3l","text":"

Simulate robots like never before with Open 3D Engine from Open Robotics on Vimeo.

"},{"location":"szimulacio/#tovabbi-szimulatorok","title":"Tov\u00e1bbi szimul\u00e1torok","text":"
  • OSRF Gazebo - ROS-\u00e1ltal legink\u00e1bb t\u00e1mogatott szimul\u00e1tor, OGRE-alap\u00fa, ROS/ROS 2 kompatibilis.
  • GitHub organization
  • CARLA - Unreal Engine alap\u00fa automotive szimul\u00e1tor. Autoware, Baidu Apollo, ROS/ROS 2 kompatibilt\u00e1ssal
  • GitHub repository
  • YouTube channel
  • LGSVL / SVL - Unity Enginealap\u00fa automotive szimul\u00e1tor, Autoware, Baidu Apollo, ROS/ROS 2 kompatibilt\u00e1ssal. Fontos: az LG felf\u00fcggesztette az SVL Simulator akt\u00edv fejleszt\u00e9s\u00e9t.
  • GitHub repository
  • YouTube channel
  • OSSDC SIM - Unity Engine alap\u00fa szimul\u00e1tor aut\u00f3ipari alkalmaz\u00e1sokhoz, a felf\u00fcggesztett LGSVL szimul\u00e1toron alapul, de akt\u00edv fejleszt\u00e9s. Kompatibilis az Autoware, a Baidu Apollo \u00e9s a ROS/ROS 2 szoftverekkel.
  • GitHub repository
  • YouTube video
  • AirSim - Unreal Engine alap\u00fa szimul\u00e1tor dr\u00f3nokhoz \u00e9s aut\u00f3khoz. ROS kompatibilis.
  • GitHub repository
  • YouTube video
  • AWSIM - Unity Engine alap\u00fa szimul\u00e1tor aut\u00f3ipari alkalmaz\u00e1sokhoz. Kompatibilis az Autoware-rel \u00e9s a ROS 2-vel.
  • GitHub repository
  • YouTube video \u2013 CoppeliaSim \u2013 T\u00f6bbplatformos, \u00e1ltal\u00e1nos c\u00e9l\u00fa robotszimul\u00e1tor (kor\u00e1bbi nev\u00e9n V-REP).
  • YouTube channel
  • MVSim
  • GitHub repository
  • YouTube video
  • AutoDRIVE
  • GitHub repository
  • YouTube channel
"},{"location":"szimulacio/#gazebo-es-ros-kompatibilitas","title":"Gazebo \u00e9s ROS kompatibilit\u00e1s","text":"

Az ROS \u00e9s Gazebo kiv\u00e1laszt\u00e1s a Picking the \"Correct\" Versions of ROS & Gazebo link alapj\u00e1n \u00edrjuk le. Megjegyz\u00e9s: a Gazebo 11 \u00e9s el\u0151tt el\u00e9v\u0151 verzi\u00f3it Gazebo Classic n\u00e9ven, m\u00edg az ut\u00e1na l\u00e9v\u0151ket Ignition Gazebo vagy r\u00f6viden Ignition-k\u00e9nt eml\u00edtik.

GZ Citadel (LTS) GZ Fortress (LTS) GZ Garden ROS 2 Rolling \ud83d\udd34 \ud83d\udfe2 \ud83d\udfe1 ROS 2 Humble (LTS) \ud83d\udd34 \ud83d\udfe2 \ud83d\udfe1 ROS 2 Foxy (LTS) \ud83d\udfe2 \ud83d\udd34 \ud83d\udd34 ROS 1 Noetic (LTS) \ud83d\udfe2 \ud83d\udfe1 \ud83d\udd34
  • \ud83d\udfe2 - Aj\u00e1nlott kombin\u00e1ci\u00f3
  • \ud83d\udfe1 - Lehets\u00e9ges, de nem aj\u00e1nott. Plusz munk\u00e1val m\u0171k\u00f6d\u00e9sre lehet b\u00edrni egy\u00fctt a k\u00e9t szoftvert.
  • \ud83d\udd34 - Nem kompatibils / nem lehets\u00e9ges.
"},{"location":"szimulacio/f1tenth_sim_a/","title":"ROS 2 F1/10 Wheeltec Roboworks Gazebo simulation workshop","text":"

The workshop is ROS 2 compatible

"},{"location":"szimulacio/f1tenth_sim_a/#video","title":"Video","text":""},{"location":"szimulacio/f1tenth_sim_a/#requirements-high-level","title":"Requirements (high-level)","text":"
  1. ROS 2 Humble: \ud83d\udfe0 see previous workshops or docs.ros.org/en/humble/Installation.html
  2. Gazebo Fortress: \u2705 current workshop gazebosim.org/docs/fortress/install_ubuntu
  3. ROS gz bridge: \u2705 current workshop, ROS integration. Install with a single command: sudo apt install ros-humble-ros-gz-bridge, gazebosim.org/docs/fortress/ros2_integration
  4. Build and run custom worlds and models \u2705 current workshop (e.g. F1/10 / Wheeltec, Roboworks)
Official F1/10 vehicle vs Wheeltec Roboworks Ackermann Rosbot mini vehicle"},{"location":"szimulacio/f1tenth_sim_a/#binary-installation-on-ubuntu","title":"Binary Installation on Ubuntu","text":"

Fortress binaries are provided for Ubuntu Bionic, Focal and Jammy. All of the Fortress binaries are hosted in the osrfoundation repository. To install all of them, the metapackage ignition-fortress can be installed. The following is based on gazebosim.org/docs/fortress/install_ubuntu.

First install some necessary tools:

sudo apt-get update\n
sudo apt-get install lsb-release wget gnupg\n

Then install Ignition Fortress:

sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg\n
echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null\n
sudo apt-get update\n
sudo apt-get install ignition-fortress\n

All libraries should be ready to use and the ign gazebo app ready to be executed.

"},{"location":"szimulacio/f1tenth_sim_a/#gazebo-fortress-ros-2-integration","title":"Gazebo Fortress ROS 2 integration","text":"

Issue the following command:

sudo apt install ros-humble-ros-gz-bridge\n
"},{"location":"szimulacio/f1tenth_sim_a/#additional-settings-to-wsl2","title":"Additional settings to WSL2","text":"

Warning - WSL2

There is an issue, which can be set even in ~/.bashrc:

export LIBGL_ALWAYS_SOFTWARE=1\n

Set it in ~/.bashrc:

echo \"export LIBGL_ALWAYS_SOFTWARE=1\" >> ~/.bashrc\n

Don't forget to source bashrc.
source ~/.bashrc\n

After new terminal or source:

echo $LIBGL_ALWAYS_SOFTWARE\n

should print 1. Alternatively

cat ~/.bashrc | grep LIBGL\n
should print the line.

"},{"location":"szimulacio/f1tenth_sim_a/#check-the-installation","title":"Check the installation","text":"

Success

Now the ign gazebo should work and the ros2 commands should be available.

Try at least one of the following commands:

ign gazebo\n
ign gazebo -v 4 -r ackermann_steering.sdf\n
ign gazebo shapes.sdf\n

ign param --versions\n
"},{"location":"szimulacio/f1tenth_sim_a/#packages-and-build","title":"Packages and build","text":"

Detailed description of the packages and build process.

It is assumed that the workspace is ~/ros2_ws/.

cd ~/ros2_ws/src\n
git clone https://github.com/robotverseny/robotverseny_gazebo24\n
"},{"location":"szimulacio/f1tenth_sim_a/#build","title":"Build","text":"
cd ~/ros2_ws\n
colcon build --symlink-install --packages-select robotverseny_application robotverseny_description robotverseny_bringup robotverseny_gazebo \n

Opcion\u00e1lis, de \u00e9rdemes feltenni az RViz 2D Overlay csomagot, amivel a debug sz\u00f6vegeket lehet megjelen\u00edteni a RViz2-ben:

sudo apt install ros-humble-rviz-2d-overlay*\n
"},{"location":"szimulacio/f1tenth_sim_a/#run","title":"Run","text":"Don't forget to source before ROS commands.
source ~/ros2_ws/install/setup.bash\n
ros2 launch robotverseny_bringup roboworks.launch.py\n
"},{"location":"szimulacio/f1tenth_sim_a/#useful-commands","title":"Useful commands","text":"

Publish command topic:

ros2 topic pub --once /roboworks/cmd_vel geometry_msgs/msg/Twist \"{linear: {x: 2.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.01}}\"\n

Teleop twist keyboard:

ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/roboworks/cmd_vel\n

Ignition info topic:

ign topic -i --topic /model/roboworks/cmd_vel\n
Ignition echo topic:

ign topic -et /model/roboworks/cmd_vel\n

Topics:

ros2 topic list\n
Here are the topics.
/clicked_point\n/clock\n/goal_pose\n/initialpose\n/joint_states\n/parameter_events\n/robot_description\n/roboworks/cmd_vel\n/roboworks/odometry\n/roboworks/scan\n/rosout\n/tf\n/tf_static\n
"},{"location":"szimulacio/f1tenth_sim_a/#linkek","title":"Linkek","text":"
  • Angol nyelv\u0171 le\u00edr\u00e1s
  • robotverseny.github.io
  • Gazebo Fortress
"},{"location":"szimulacio/gazebo_fortress/","title":"Ignition Gazebo Fortress","text":"

Az Ignition Gazebo Fortress egy long-term support (LTS) release 2026 szeptember\u00e9ig t\u00e1mogatva. ROS 2 Humble kiad\u00e1ssal kompatibilis, l\u00e1sd a kompatibilt\u00e1si m\u00e1trixot.

"},{"location":"szimulacio/gazebo_fortress/#telepites","title":"Telep\u00edt\u00e9s","text":"

Aj\u00e1nlott az Ubuntu \u00e9s a binary telep\u00edt\u00e9s: gazebosim.org/docs/fortress/install_ubuntu. Term\u00e9szetesen az el\u0151z\u0151 linken tov\u00e1bbkattintva el\u00e9rhet\u0151ek a Windowsos illetve a forr\u00e1sk\u00f3db\u00f3l ford\u00edtott verzi\u00f3k is.

"},{"location":"szimulacio/gazebo_fortress/#ros-2-integracio","title":"ROS 2 integr\u00e1ci\u00f3","text":"
  • gazebosim.org/docs/fortress/ros2_integration
  • github.com/gazebosim/ros_gz/blob/ros2/ros_gz_bridge/README.md
"},{"location":"szimulacio/gazebo_fortress/#megjegyzes-wsl-eseten","title":"Megjegyz\u00e9s WSL eset\u00e9n","text":"

Gazebo szimul\u00e1tort \u00e9s Windows Subsystem for Linux-ot haszn\u00e1lva el\u0151fordulhat egy issue, ami egy egyszer\u0171 k\u00f6rnyezeti v\u00e1ltoz\u00f3 be\u00e1ll\u00edt\u00e1s\u00e1val jav\u00edthat\u00f3. A ~/.bashrc f\u00e1jlba a k\u00f6vetkez\u0151t kell be\u00e1ll\u00edtani:

export LIBGL_ALWAYS_SOFTWARE=1 ### GAZEBO IGNITION \n

\u00daj termin\u00e1l vagy source ut\u00e1n a echo $LIBGL_ALWAYS_SOFTWARE parancsra 1-et fog ki\u00edni.

"},{"location":"szimulacio/gazebo_fortress/#pelda-gazebo-fortress-beepitett-vilagok-world","title":"P\u00e9lda: Gazebo Fortress be\u00e9p\u00edtett vil\u00e1gok (world)","text":"

WSL elset\u00e9n els\u0151 l\u00e9p\u00e9sk\u00e9nt ellen\u0151rizz\u00fck a be\u00e1ll\u00edt\u00e1sok helyess\u00e9g\u00e9t:

echo $LIBGL_ALWAYS_SOFTWARE \n

Amennyiben a parancsra 1-et \u00edr v\u00e1laszk\u00e9nt, akkor helyes a be\u00e1ll\u00edt\u00e1sunk.

N\u00e9zz\u00fck meg a telep\u00edtett verzi\u00f3t:

ign param --versions\n

A v\u00e1lasz pl 11.4.1 lehet.

Ind\u00edtsuk el a Gazebo-t:

ign gazebo\n

Nyissuk meg a shapes.sdf vil\u00e1got. Az SDF (Simulation Description Format) egy be\u00e9p\u00edtett XML le\u00edr\u00e1s. Ak\u00e1r egy parancsk\u00e9nt is ind\u00edthat\u00f3: ign gazebo shapes.sdf.

"},{"location":"szimulacio/gazebo_fortress/#pelda-ackermann-robot","title":"P\u00e9lda: Ackermann robot","text":"

Ackermann robotnak a \u201eszem\u00e9lyaut\u00f3-szer\u0171\u201d, hagyom\u00e1nyos, el\u0151l k\u00e9t korm\u00e1nyzott, h\u00e1tul pedig k\u00e9t nem korm\u00e1nyzott ker\u00e9kkel rendelkez\u0151 j\u00e1rm\u0171vet / robotot nevezz\u00fck. Ebben a p\u00e9ld\u00e1ban egy ilyen robotot szeretn\u00e9nk mozgatni ROS 2-b\u0151l. Az ign gazebo parancsra a szimul\u00e1ci\u00f3-v\u00e1laszt\u00f3 fel\u00fclet indul. Egy paranccsal ind\u00edthat\u00f3 az Ackermann robotot tartalmaz\u00f3 szimul\u00e1ci\u00f3:

ign gazebo -v 4 -r ackermann_steering.sdf\n

Az Ignition Gazebo ROS 2-t\u0151l f\u00fcggetlen, de j\u00f3l t\u00e1mogatott, \u00edgy ros_gz_bridge package seg\u00edts\u00e9g\u00e9vel ind\u00edthat\u00f3 az a bridge, amin a szimmul\u00e1ci\u00f3s topic-ok ROS 2 topic-k\u00e9nt l\u00e1tszanak, pl:

sudo apt update\n
sudo apt install ros-humble-ros-gz -y\n

Tanteremben pedig:

cd /mnt/kozos/script\n
./gz_bridge.sh\n
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist\n
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry --ros-args -r /model/vehicle_blue/odometry:=/odom\n
ros2 run ros_gz_bridge parameter_bridge /world/ackermann_steering/pose/info@tf2_msgs/msg/TFMessage[ignition.msgs.Pose_V  --ros-args -r /world/ackermann_steering/pose/info:=/tf\n

Ez a 3 parancs egy hossz\u00fa parancsk\u00e9nt is kiadhat\u00f3:

ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry   /world/ackermann_steering/pose/info@tf2_msgs/msg/TFMessage[ignition.msgs.Pose_V  --ros-args -r /world/ackermann_steering/pose/info:=/tf -r /model/vehicle_blue/odometry:=/odom\n

Hogy pontosan milyen szimul\u00e1ci\u00f3s topicok vannak, az ezekkel a parancsokkal ellen\u0151rizhet\u0151:

ign topic -l\n
ign topic -et /model/vehicle_blue/tf\n
ign topic -i --topic /model/vehicle_blue/tf\n

Billenty\u0171zetr\u0151l teleoper\u00e1lhatjuk a j\u00e1rm\u0171vet:

ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/model/vehicle_blue/cmd_vel\n
"},{"location":"szimulacio/gazebo_fortress/#linkek","title":"Linkek","text":"
  • gazebosim.org/docs/fortress
  • gazebosim.org/docs/fortress/manipulating_models
"},{"location":"szimulacio/gyakorlat/","title":"Ignition Gazebo gyakorlat","text":""},{"location":"szimulacio/gyakorlat/#sajat-robotszimulacio-letrehozasa","title":"Saj\u00e1t robotszimul\u00e1ci\u00f3 l\u00e9trehoz\u00e1sa","text":"

A k\u00f6vetkez\u0151kben l\u00e9tre fogunk hozni egy egyszer\u0171 k\u00f6rnyezetet (world), valamint egy robot modellt. Ennek \u00e9rdek\u00e9ben hozzunk l\u00e9tre egy simulation mapp\u00e1t, majd ezen bel\u00fcl a building_robot.sdf nev\u0171 f\u00e1jlt. A mappa b\u00e1rhol l\u00e9trehozhat\u00f3, illetve a f\u00e1jl neve is szabadon v\u00e1laszthat\u00f3, a k\u00f6vethet\u0151s\u00e9g \u00e9rdek\u00e9ben \u00e9rdemes a megadott m\u00f3don elj\u00e1rni.

mkdir simulation\n
cd simulation\n
touch building_robot.sdf\n

"},{"location":"szimulacio/gyakorlat/#kornyezet-letrehozasa","title":"K\u00f6rnyezet l\u00e9trehoz\u00e1sa","text":"

Nyissuk meg a l\u00e9trehozott f\u00e1jlt Visual Studio Code seg\u00edts\u00e9g\u00e9vel, majd m\u00e1soljuk be az al\u00e1bbi k\u00f3dr\u00e9szletet:

<?xml version=\"1.0\" ?>\n<sdf version=\"1.9\">\n    <world name=\"car_world\">\n        <physics name=\"1ms\" type=\"ignored\">\n            <max_step_size>0.001</max_step_size>\n            <real_time_factor>1.0</real_time_factor>\n        </physics>\n        <plugin\n            filename=\"gz-sim-physics-system\"\n            name=\"gz::sim::systems::Physics\">\n        </plugin>\n        <plugin\n            filename=\"gz-sim-user-commands-system\"\n            name=\"gz::sim::systems::UserCommands\">\n        </plugin>\n        <plugin\n            filename=\"gz-sim-scene-broadcaster-system\"\n            name=\"gz::sim::systems::SceneBroadcaster\">\n        </plugin>\n\n        <light type=\"directional\" name=\"sun\">\n            <cast_shadows>true</cast_shadows>\n            <pose>0 0 10 0 0 0</pose>\n            <diffuse>0.8 0.8 0.8 1</diffuse>\n            <specular>0.2 0.2 0.2 1</specular>\n            <attenuation>\n                <range>1000</range>\n                <constant>0.9</constant>\n                <linear>0.01</linear>\n                <quadratic>0.001</quadratic>\n            </attenuation>\n            <direction>-0.5 0.1 -0.9</direction>\n        </light>\n\n        <model name=\"ground_plane\">\n            <static>true</static>\n            <link name=\"link\">\n                <collision name=\"collision\">\n                <geometry>\n                    <plane>\n                    <normal>0 0 1</normal>\n                    </plane>\n                </geometry>\n                </collision>\n                <visual name=\"visual\">\n                <geometry>\n                    <plane>\n                    <normal>0 0 1</normal>\n                    <size>100 100</size>\n                    </plane>\n                </geometry>\n                <material>\n                    <ambient>0.8 0.8 0.8 1</ambient>\n                    <diffuse>0.8 0.8 0.8 1</diffuse>\n                    <specular>0.8 0.8 0.8 1</specular>\n                </material>\n                </visual>\n            </link>\n        </model>\n    </world>\n</sdf>\n
A fenti k\u00f3dr\u00e9szlet \u00fcres k\u00f6rnyezetet defini\u00e1l, mind\u00f6ssze egy s\u00edk (talaj), valamint alap\u00e9rtelmezett vil\u00e1g\u00edt\u00e1s (napf\u00e9ny) tal\u00e1lhat\u00f3 meg benne. Ments\u00fck el a k\u00f3dot, majd ind\u00edtsuk el a szimul\u00e1ci\u00f3t az al\u00e1bbi m\u00f3don, a simulation mapp\u00e1b\u00f3l:

cd ~/simulation\n
ign gazebo building_robot.sdf\n

Ind\u00edt\u00e1st k\u00f6vet\u0151en a le\u00edrtaknak megfelel\u0151 \u00fcres k\u00f6rnyezetet kell l\u00e1tnunk:

"},{"location":"szimulacio/gyakorlat/#robot-modell-letrehozasa","title":"Robot modell l\u00e9trehoz\u00e1sa","text":"

Folytassuk a building_robot.sdf szerkeszt\u00e9s\u00e9t, a </model> c\u00edmk\u00e9t k\u00f6vet\u0151en. \u00c9szrevehet\u0151, hogy a talajt, vagyis a ground_plane elemet is modellk\u00e9nt adtuk meg, hasonl\u00f3 m\u00f3don adjuk hozz\u00e1 a j\u00e1rm\u0171vet is.

<model name='vehicle_blue' canonical_link='chassis'>\n    <pose relative_to='world'>0 0 0 0 0 0</pose>\n</model>\n
A robot modell megnevez\u00e9se ebben az esetben vehicle_blue . A megnevez\u00e9s szabadon megv\u00e1laszthat\u00f3, viszont fontos figyelni arra, hogy a n\u00e9v egyedi legyen az azonos k\u00f6rnyezeten bel\u00fcl haszn\u00e1lt modellek k\u00f6z\u00f6tt.

A modellt fel\u00e9p\u00edt\u0151 elemeket (pl. karossz\u00e9ria, kerekek stb.) a tov\u00e1bbiakban linkeknek nevezz\u00fck.

Minden modellnek lehet egyetlen \u00fan. canonical_link eleme. Minden tov\u00e1bbi modellen bel\u00fcl alkalmazott link ehhez fog csatlakozni. Amennyiben nem defini\u00e1lunk egyetlen canonical_link elemet sem, az els\u0151 link alap\u00e9rtelmezetten canonical t\u00edpus\u00fa lesz.

A <pose> c\u00edmke haszn\u00e1lat\u00e1val megadhat\u00f3 egy link poz\u00edci\u00f3ja \u00e9s orient\u00e1ci\u00f3ja. A c\u00edmke ut\u00e1n megadott relative_to attrib\u00fatummal megadhat\u00f3, hogy mihez k\u00e9pest szeretn\u00e9nk a link poz\u00edci\u00f3j\u00e1t \u00e9s orient\u00e1ci\u00f3j\u00e1t defini\u00e1lni. Az attrib\u00fatum megad\u00e1sa n\u00e9lk\u00fcl a poz\u00edci\u00f3 megad\u00e1sa a k\u00f6rnyezethez k\u00e9pest t\u00f6rt\u00e9nik. A poz\u00edci\u00f3 \u00e9s orient\u00e1ci\u00f3 megad\u00e1s\u00e1nak form\u00e1tuma <pose>X Y Z R P Y</pose>, ahol X, Y \u00e9s Z a frame-en bel\u00fcli poz\u00edci\u00f3 koordin\u00e1t\u00e1i, R, P \u00e9s Y pedig az orient\u00e1ci\u00f3t adja meg radi\u00e1nban. A robot defini\u00e1l\u00e1sa sor\u00e1n minden param\u00e9ternek z\u00e9rus \u00e9rt\u00e9ket adtunk, teh\u00e1t a robot \u00e9s a k\u00f6rnyezet frame-je egybeesik.

Minden modell (robot) jointok (csukl\u00f3k / \u00edz\u00fcletek) \u00e1ltal \u00f6sszekapcsolt linkekb\u0151l \u00e1ll.

"},{"location":"szimulacio/gyakorlat/#a-robotot-alkoto-linkek-definialasa","title":"A robotot alkot\u00f3 linkek defini\u00e1l\u00e1sa","text":"

A k\u00f6vetkez\u0151kben az \u00e9rthet\u0151s\u00e9g kedv\u00e9\u00e9rt az SDF f\u00e1jl magyar\u00e1zata elemenk\u00e9nt t\u00f6rt\u00e9nik. Neh\u00e9z lehet k\u00f6vetni az egyes r\u00e9szletek teljes k\u00f3don bel\u00fcli hely\u00e9t, ehhez a magyar\u00e1zat v\u00e9g\u00e9n tal\u00e1lhat\u00f3 teljes SDF ad seg\u00edts\u00e9get.

Minden link l\u00e9trehoz\u00e1sa sor\u00e1n meg kell adnunk a k\u00f6vetkez\u0151ket: 1. link neve, poz\u00edci\u00f3ja 2. link inerci\u00e1lis tulajdons\u00e1gai (t\u00f6meg \u00e9s inerciam\u00e1trix) 3. vizu\u00e1lis \u00e9s egyszer\u0171s\u00edtett (collision) geometria

  • Karossz\u00e9ria

Link l\u00e9trehoz\u00e1sa:

<model name='vehicle_blue' canonical_link='chassis'>\n    <pose relative_to='world'>0 0 0 0 0 0</pose>\n    <link name='chassis'>\n        <pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>\n    </link>\n</model>\n

Inerci\u00e1lis tulajdons\u00e1gok (a m\u00e9rt\u00e9kegys\u00e9gek ebben az esetben is SI-ben \u00e9rtend\u0151ek):

<inertial>\n    <mass>1.14395</mass>\n    <inertia>\n        <ixx>0.095329</ixx>\n        <ixy>0</ixy>\n        <ixz>0</ixz>\n        <iyy>0.381317</iyy>\n        <iyz>0</iyz>\n        <izz>0.476646</izz>\n    </inertia>\n</inertial>\n

Vizu\u00e1lis \u00e9s egyszer\u0171s\u00edtett (\u00fctk\u00f6z\u00e9si/collision) geometria megad\u00e1sa:

<visual name='visual'>\n    <geometry>\n        <box>\n            <size>2.0 1.0 0.5</size>\n        </box>\n    </geometry>\n    <material>\n        <ambient>0.0 0.0 1.0 1</ambient>\n        <diffuse>0.0 0.0 1.0 1</diffuse>\n        <specular>0.0 0.0 1.0 1</specular>\n    </material>\n</visual>\n
<collision name='collision'>\n    <geometry>\n        <box>\n            <size>2.0 1.0 0.5</size>\n        </box>\n    </geometry>\n</collision>\n

Ind\u00edtsuk el a szimul\u00e1ci\u00f3t ism\u00e9t:

cd ~/simulation\n
ign gazebo building_robot.sdf\n

Ezt k\u00f6vet\u0151en a szimul\u00e1torban a robot karossz\u00e9ri\u00e1j\u00e1t kell l\u00e1tnunk:

  • Jobb \u00e9s bal ker\u00e9k

Hozzuk l\u00e9tre a robot jobb \u00e9s bal (hajtott) kerek\u00e9t k\u00e9pez\u0151 linkeket. Ezt a robotot defini\u00e1l\u00f3 <model> c\u00edmk\u00e9k k\u00f6z\u00f6tt kell megtenn\u00fcnk, ugyanis ide ker\u00fcl minden olyan link defin\u00edci\u00f3ja, amely azonos modellen (a roboton) bel\u00fcl \u00e9rtend\u0151.

A kerekeket hengerek (sphere) seg\u00edts\u00e9g\u00e9vel fogjuk l\u00e9trehozni. A kerekeknek az Y tengely ment\u00e9n kell elfordulniuk, ez\u00e9rt meg kell adnunk a helyes orient\u00e1ci\u00f3jukat.

<link name='left_wheel'>\n    <pose relative_to=\"chassis\">-0.5 0.6 0 -1.5707 0 0</pose>\n    <inertial>\n        <mass>1</mass>\n        <inertia>\n            <ixx>0.043333</ixx>\n            <ixy>0</ixy>\n            <ixz>0</ixz>\n            <iyy>0.043333</iyy>\n            <iyz>0</iyz>\n            <izz>0.08</izz>\n        </inertia>\n    </inertial>\n

Vizu\u00e1lis \u00e9s egyszer\u0171s\u00edtett (\u00fctk\u00f6z\u00e9si/collision) geometria megad\u00e1sa:

<visual name='visual'>\n        <geometry>\n            <cylinder>\n                <radius>0.4</radius>\n                <length>0.2</length>\n            </cylinder>\n        </geometry>\n        <material>\n            <ambient>1.0 0.0 0.0 1</ambient>\n            <diffuse>1.0 0.0 0.0 1</diffuse>\n            <specular>1.0 0.0 0.0 1</specular>\n        </material>\n    </visual>\n    <collision name='collision'>\n        <geometry>\n            <cylinder>\n                <radius>0.4</radius>\n                <length>0.2</length>\n            </cylinder>\n        </geometry>\n    </collision>\n</link>\n

A bal ker\u00e9k megad\u00e1sa anal\u00f3g m\u00f3don t\u00f6rt\u00e9nik, csak a poz\u00edci\u00f3 tekintet\u00e9ben (\u00e9s term\u00e9szetesen a link nev\u00e9ben) t\u00e9r el a jobb ker\u00e9k megad\u00e1s\u00e1t\u00f3l:

<link name='right_wheel'>\n    <pose relative_to=\"chassis\">-0.5 -0.6 0 -1.5707 0 0</pose> <!--sz\u00f6gek radi\u00e1nban-->\n    <inertial>\n        <mass>1</mass>\n        <inertia>\n            <ixx>0.043333</ixx>\n            <ixy>0</ixy>\n            <ixz>0</ixz>\n            <iyy>0.043333</iyy>\n            <iyz>0</iyz>\n            <izz>0.08</izz>\n        </inertia>\n    </inertial>\n    <visual name='visual'>\n        <geometry>\n            <cylinder>\n                <radius>0.4</radius>\n                <length>0.2</length>\n            </cylinder>\n        </geometry>\n        <material>\n            <ambient>1.0 0.0 0.0 1</ambient>\n            <diffuse>1.0 0.0 0.0 1</diffuse>\n            <specular>1.0 0.0 0.0 1</specular>\n        </material>\n    </visual>\n    <collision name='collision'>\n        <geometry>\n            <cylinder>\n                <radius>0.4</radius>\n                <length>0.2</length>\n            </cylinder>\n        </geometry>\n    </collision>\n</link>\n
  • T\u00e1maszt\u00f3g\u00f6rg\u0151 hozz\u00e1ad\u00e1sa

Van lehet\u0151s\u00e9g eny\u00e9ni frame-ek l\u00e9trehoz\u00e1s\u00e1ra is, a t\u00e1maszt\u00f3g\u00f6rg\u0151 fel\u00e9p\u00edt\u00e9se sor\u00e1n ezt fogjuk tenni:

<frame name=\"caster_frame\" attached_to='chassis'>\n    <pose>0.8 0 -0.2 0 0 0</pose>\n</frame>\n
A l\u00e9trehozott frame neve caster_frame, amely a chassis linkhez csatlakozik. A <pose> c\u00edmke megadja a poz\u00edci\u00f3j\u00e1t \u00e9s orient\u00e1ci\u00f3j\u00e1t ehhez a linkhez k\u00e9pest, viszont a relative_to attrib\u00fatumra az egy\u00e9ni frame eset\u00e9ben nem volt sz\u00fcks\u00e9g.

Folytat\u00f3dhad a t\u00e1maszt\u00f3g\u00f6rg\u0151 defini\u00e1l\u00e1sa:

<link name='caster'>\n    <pose relative_to='caster_frame'/>\n    <inertial>\n        <mass>1</mass>\n        <inertia>\n            <ixx>0.016</ixx>\n            <ixy>0</ixy>\n            <ixz>0</ixz>\n            <iyy>0.016</iyy>\n            <iyz>0</iyz>\n            <izz>0.016</izz>\n        </inertia>\n    </inertial>\n    <visual name='visual'>\n        <geometry>\n            <sphere>\n                <radius>0.2</radius>\n            </sphere>\n        </geometry>\n        <material>\n            <ambient>0.0 1 0.0 1</ambient>\n            <diffuse>0.0 1 0.0 1</diffuse>\n            <specular>0.0 1 0.0 1</specular>\n        </material>\n    </visual>\n    <collision name='collision'>\n        <geometry>\n            <sphere>\n                <radius>0.2</radius>\n            </sphere>\n        </geometry>\n    </collision>\n</link>\n
"},{"location":"szimulacio/gyakorlat/#csuklok-izuletek-joints-definialasa","title":"Csukl\u00f3k / \u00edz\u00fcletek (joints) defini\u00e1l\u00e1sa","text":"

A kor\u00e1bban defini\u00e1lt linkek k\u00f6z\u00f6tt \u00f6sszef\u00fcgg\u00e9seket kell defini\u00e1lnunk. Ezek az \u00f6sszef\u00fcgg\u00e9sek fogj\u00e1k megadni, hogy a linkek milyen m\u00f3don mozdulhatnak el egym\u00e1shoz k\u00e9pest. Ebb\u0151l ered a defin\u00edci\u00f3 m\u00f3dj\u00e1nak neve is.

  • Bal ker\u00e9k joint

Megadjuk a joint nev\u00e9t \u00e9s t\u00edpus\u00e1t. A ker\u00e9knek el kell fordulnia, ez\u00e9rt a revolute t\u00edpust v\u00e1lasztjuk.

<joint name='left_wheel_joint' type='revolute'>\n    <pose relative_to='left_wheel'/>\n
Ezt k\u00f6vet\u0151en megadjuk az al\u00e1-f\u00f6l\u00e9 rendel\u0151 viszonyt:
    <parent>chassis</parent>\n    <child>left_wheel</child>\n
V\u00e9g\u00fcl meg kell adnunk a linkek k\u00f6z\u00f6tti k\u00e9nyszerek defin\u00edci\u00f3j\u00e1t. Ezek a defin\u00edci\u00f3k b\u00e1rmely frame-re vonatkoz\u00f3an megadhat\u00f3ak, nem csak a sz\u00fcl\u0151-gyerek frame-ek k\u00f6z\u00f6tt.

Jelen esetben a ker\u00e9knek az Y tengely k\u00f6r\u00fcl kell elfordulnia. Teljesen, t\u00f6bbsz\u00f6r is k\u00f6rbefordulhat, ez\u00e9rt a mozg\u00e1s korl\u00e1tjai pozit\u00edv \u00e9s negat\u00edv v\u00e9gtelen lesz.

 <axis>\n        <xyz expressed_in='__model__'>0 1 0</xyz>\n        <limit>\n            <lower>-1.79769e+308</lower>    <!--negat\u00edv v\u00e9gtelen-->\n            <upper>1.79769e+308</upper>     <!--pozit\u00edv v\u00e9gtelen-->\n        </limit>\n    </axis>\n</joint>\n
  • Jobb ker\u00e9k joint

A jobb ker\u00e9k joint defini\u00e1l\u00e1sa a bal ker\u00e9k\u00e9hez hasonl\u00f3 m\u00f3don t\u00f6rt\u00e9nik:

<joint name='right_wheel_joint' type='revolute'>\n    <pose relative_to='right_wheel'/>\n    <parent>chassis</parent>\n    <child>right_wheel</child>\n    <axis>\n        <xyz expressed_in='__model__'>0 1 0</xyz>\n        <limit>\n            <lower>-1.79769e+308</lower>    <!--negat\u00edv v\u00e9gtelen-->\n            <upper>1.79769e+308</upper>     <!--pozit\u00edv v\u00e9gtelen-->\n        </limit>\n    </axis>\n</joint>\n
  • T\u00e1maszt\u00f3ker\u00e9k joint

Mivel a t\u00e1maszt\u00f3ker\u00e9k g\u00f6mb, minden tengely ment\u00e9n elfordulhat. Ebb\u0151l ad\u00f3d\u00f3an eset\u00e9ben elt\u00e9r\u0151 t\u00edpus\u00fa joint ker\u00fcl alkalmaz\u00e1sra:

<joint name='caster_wheel' type='ball'>\n    <parent>chassis</parent>\n    <child>caster</child>\n</joint>\n

Ind\u00edtsuk el a szimul\u00e1ci\u00f3t ism\u00e9t:

cd ~/simulation\n
ign gazebo building_robot.sdf\n

Ezt k\u00f6vet\u0151en a szimul\u00e1torban a robotot kell l\u00e1tnunk:

Az eddig bemutatottakat tartalmaz\u00f3 XML le\u00edr\u00f3 f\u00e1jl tartalma:

<?xml version=\"1.0\" ?>\n<sdf version=\"1.8\">\n    <world name=\"car_world\">\n        <physics name=\"1ms\" type=\"ignored\">\n            <max_step_size>0.001</max_step_size>\n            <real_time_factor>1.0</real_time_factor>\n        </physics>\n        <plugin\n            filename=\"gz-sim-physics-system\"\n            name=\"gz::sim::systems::Physics\">\n        </plugin>\n        <plugin\n            filename=\"gz-sim-user-commands-system\"\n            name=\"gz::sim::systems::UserCommands\">\n        </plugin>\n        <plugin\n            filename=\"gz-sim-scene-broadcaster-system\"\n            name=\"gz::sim::systems::SceneBroadcaster\">\n        </plugin>\n\n        <light type=\"directional\" name=\"sun\">\n            <cast_shadows>true</cast_shadows>\n            <pose>0 0 10 0 0 0</pose>\n            <diffuse>0.8 0.8 0.8 1</diffuse>\n            <specular>0.2 0.2 0.2 1</specular>\n            <attenuation>\n                <range>1000</range>\n                <constant>0.9</constant>\n                <linear>0.01</linear>\n                <quadratic>0.001</quadratic>\n            </attenuation>\n            <direction>-0.5 0.1 -0.9</direction>\n        </light>\n\n        <model name=\"ground_plane\">\n            <static>true</static>\n            <link name=\"link\">\n                <collision name=\"collision\">\n                <geometry>\n                    <plane>\n                    <normal>0 0 1</normal>\n                    </plane>\n                </geometry>\n                </collision>\n                <visual name=\"visual\">\n                <geometry>\n                    <plane>\n                    <normal>0 0 1</normal>\n                    <size>100 100</size>\n                    </plane>\n                </geometry>\n                <material>\n                    <ambient>0.8 0.8 0.8 1</ambient>\n                    <diffuse>0.8 0.8 0.8 1</diffuse>\n                    <specular>0.8 0.8 0.8 1</specular>\n                </material>\n                </visual>\n            </link>\n        </model>\n\n        <model name='vehicle_blue' canonical_link='chassis'>\n            <pose relative_to='world'>0 0 0 0 0 0</pose>   <!--alapbe\u00e1ll\u00edt\u00e1s szerint a megadott p\u00f3z a vil\u00e1g koordin\u00e1t\u00e1ihoz k\u00e9pest \u00e9rtend\u0151-->\n\n            <!--karossz\u00e9ria-->\n            <link name='chassis'>\n                <pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>\n                <inertial>\n                    <mass>1.14395</mass>\n                    <inertia>\n                        <ixx>0.095329</ixx>\n                        <ixy>0</ixy>\n                        <ixz>0</ixz>\n                        <iyy>0.381317</iyy>\n                        <iyz>0</iyz>\n                        <izz>0.476646</izz>\n                    </inertia>\n                </inertial>\n                <visual name='visual'>\n                    <geometry>\n                        <box>\n                            <size>2.0 1.0 0.5</size>\n                        </box>\n                    </geometry>\n                    <!--Az \u00f6sszetev\u0151 anyagjellemz\u0151i (sz\u00edne)-->\n                    <material>\n                        <ambient>0.0 0.0 1.0 1</ambient>\n                        <diffuse>0.0 0.0 1.0 1</diffuse>\n                        <specular>0.0 0.0 1.0 1</specular>\n                    </material>\n                </visual>\n                <collision name='collision'>\n                    <geometry>\n                        <box>\n                            <size>2.0 1.0 0.5</size>\n                        </box>\n                    </geometry>\n                </collision>\n            </link>\n\n            <!--Bal ker\u00e9k-->\n            <link name='left_wheel'>\n                <pose relative_to=\"chassis\">-0.5 0.6 0 -1.5707 0 0</pose>\n                <inertial>\n                    <mass>1</mass>\n                    <inertia>\n                        <ixx>0.043333</ixx>\n                        <ixy>0</ixy>\n                        <ixz>0</ixz>\n                        <iyy>0.043333</iyy>\n                        <iyz>0</iyz>\n                        <izz>0.08</izz>\n                    </inertia>\n                </inertial>\n                <visual name='visual'>\n                    <geometry>\n                        <cylinder>\n                            <radius>0.4</radius>\n                            <length>0.2</length>\n                        </cylinder>\n                    </geometry>\n                    <material>\n                        <ambient>1.0 0.0 0.0 1</ambient>\n                        <diffuse>1.0 0.0 0.0 1</diffuse>\n                        <specular>1.0 0.0 0.0 1</specular>\n                    </material>\n                </visual>\n                <collision name='collision'>\n                    <geometry>\n                        <cylinder>\n                            <radius>0.4</radius>\n                            <length>0.2</length>\n                        </cylinder>\n                    </geometry>\n                </collision>\n            </link>\n\n            <!--Jobb ker\u00e9k (ugyanaz, mint a bal ker\u00e9k, a poz\u00edci\u00f3 t\u00fckr\u00f6z\u00e9s\u00e9vel)-->\n            <link name='right_wheel'>\n                <pose relative_to=\"chassis\">-0.5 -0.6 0 -1.5707 0 0</pose>\n                <inertial>\n                    <mass>1</mass>\n                    <inertia>\n                        <ixx>0.043333</ixx>\n                        <ixy>0</ixy>\n                        <ixz>0</ixz>\n                        <iyy>0.043333</iyy>\n                        <iyz>0</iyz>\n                        <izz>0.08</izz>\n                    </inertia>\n                </inertial>\n                <visual name='visual'>\n                    <geometry>\n                        <cylinder>\n                            <radius>0.4</radius>\n                            <length>0.2</length>\n                        </cylinder>\n                    </geometry>\n                    <material>\n                        <ambient>1.0 0.0 0.0 1</ambient>\n                        <diffuse>1.0 0.0 0.0 1</diffuse>\n                        <specular>1.0 0.0 0.0 1</specular>\n                    </material>\n                </visual>\n                <collision name='collision'>\n                    <geometry>\n                        <cylinder>\n                            <radius>0.4</radius>\n                            <length>0.2</length>\n                        </cylinder>\n                    </geometry>\n                </collision>\n            </link>\n\n            <!--Tetsz\u0151leges frame-->\n            <frame name=\"caster_frame\" attached_to='chassis'>\n                <pose>0.8 0 -0.2 0 0 0</pose>\n            </frame>\n\n            <!--T\u00e1maszt\u00f3g\u00f6rg\u0151-->\n            <link name='caster'>\n                <pose relative_to='caster_frame'/>\n                <inertial>\n                    <mass>1</mass>\n                    <inertia>\n                        <ixx>0.016</ixx>\n                        <ixy>0</ixy>\n                        <ixz>0</ixz>\n                        <iyy>0.016</iyy>\n                        <iyz>0</iyz>\n                        <izz>0.016</izz>\n                    </inertia>\n                </inertial>\n                <visual name='visual'>\n                    <geometry>\n                        <sphere>\n                            <radius>0.2</radius>\n                        </sphere>\n                    </geometry>\n                    <material>\n                        <ambient>0.0 1 0.0 1</ambient>\n                        <diffuse>0.0 1 0.0 1</diffuse>\n                        <specular>0.0 1 0.0 1</specular>\n                    </material>\n                </visual>\n                <collision name='collision'>\n                    <geometry>\n                        <sphere>\n                            <radius>0.2</radius>\n                        </sphere>\n                    </geometry>\n                </collision>\n            </link>\n\n            <!--Bal ker\u00e9k joint-->\n            <joint name='left_wheel_joint' type='revolute'>\n                <pose relative_to='left_wheel'/>\n                <parent>chassis</parent>\n                <child>left_wheel</child>\n                <axis>\n                    <xyz expressed_in='__model__'>0 1 0</xyz> \n                    <limit>\n                        <lower>-1.79769e+308</lower>    <!--negat\u00edv v\u00e9gtelen-->\n                        <upper>1.79769e+308</upper>     <!--pozit\u00edv v\u00e9gtelen-->\n                    </limit>\n                </axis>\n            </joint>\n\n            <!--Jobb ker\u00e9k joint-->\n            <joint name='right_wheel_joint' type='revolute'>\n                <pose relative_to='right_wheel'/>\n                <parent>chassis</parent>\n                <child>right_wheel</child>\n                <axis>\n                    <xyz expressed_in='__model__'>0 1 0</xyz>\n                    <limit>\n                        <lower>-1.79769e+308</lower>    <!--negat\u00edv v\u00e9gtelen-->\n                        <upper>1.79769e+308</upper>     <!--pozit\u00edv v\u00e9gtelen-->\n                    </limit>\n                </axis>\n            </joint>\n\n            <!--T\u00e1maszt\u00f3g\u00f6rg\u0151 joint-->\n            <joint name='caster_wheel' type='ball'>\n                <parent>chassis</parent>\n                <child>caster</child>\n            </joint>\n        </model>\n    </world>\n</sdf>\n
"},{"location":"szimulacio/gyakorlat/#a-robotplatform-mozgatasa","title":"A robotplatform mozgat\u00e1sa","text":"

A kor\u00e1bbiakban \u00f6ssze\u00e1ll\u00edtott robot mozgat\u00e1s\u00e1hoz egy plugint, pontosabban a diff_drive plugint fogunk alkalmazni.

Nyissuk meg a kor\u00e1bban l\u00e9trehozott building_robot.sdf f\u00e1jlt, \u00e9s a vehicle_blue <model> c\u00edmk\u00e9in bel\u00fcl h\u00edvjuk meg a plugint, valamint defini\u00e1ljuk a haszn\u00e1lat\u00e1hoz sz\u00fcks\u00e9ges alapvet\u0151 param\u00e9tereket:

<plugin\n    filename=\"libignition-gazebo-diff-drive-system.so\"\n    name=\"ignition::gazebo::systems::DiffDrive\">\n    <left_joint>left_wheel_joint</left_joint>\n    <right_joint>right_wheel_joint</right_joint>\n    <wheel_separation>1.2</wheel_separation>\n    <wheel_radius>0.4</wheel_radius>\n    <odom_publish_frequency>1</odom_publish_frequency>\n    <topic>cmd_vel</topic>\n</plugin>\n

A <plugin> c\u00edmk\u00e9nek k\u00e9t attrib\u00fatuma van. Az egyik a k\u00f6nyvt\u00e1r megnevez\u00e9se, amelyb\u0151l a plugin sz\u00e1rmazik (filename), a m\u00e1sik a plugin neve (name). A tov\u00e1bbi c\u00edmk\u00e9k a differenci\u00e1lhajt\u00e1s\u00fa robot jellemz\u0151i: - <left_joint> \u00e9s <right_joint>: azok a jointok, amelyek kapcsolatot defini\u00e1lnak a robot bal- illetve jobboldali kereke, \u00e9s a robot karossz\u00e9ri\u00e1ja k\u00f6z\u00f6tt. - <wheel_separation>: a hajtott kerekek k\u00f6z\u00f6tti t\u00e1vols\u00e1g, vagyis a nyomt\u00e1v. Mivel kor\u00e1bban \u00fagy adtuk meg, hogy a jobb \u00e9s bal ker\u00e9k poz\u00edci\u00f3ja az Y tengely ment\u00e9n -0,6m \u00e9s 0,6m, a kerekek t\u00e1vols\u00e1ga 1,2m. - <wheel_radius>: a hajtott kerekek sugara. - <odom_publish_frequency>: az a frekvencia, amellyel a plugin \u00e1ltal sz\u00e1molt odometri\u00e1t publish-olni szeretn\u00e9nk.

A param\u00e9terek be\u00e1ll\u00edt\u00e1s\u00e1val a modell\u00fcnk k\u00e9sz a mozgat\u00e1sra. A k\u00f6vetkez\u0151 l\u00e9p\u00e9s az, hogy utas\u00edt\u00e1sokat k\u00fcldj\u00fcnk neki, ami a cmd_vel topic seg\u00edts\u00e9g\u00e9vel hajthat\u00f3 v\u00e9gre.

  1. Ind\u00edtsuk el a robotot k\u00e9zi parancsmegad\u00e1ssal

  2. Az egyik termin\u00e1lban ind\u00edtsuk el a szimul\u00e1ci\u00f3t:

    ign gazebo building_robot.sdf\n

  3. Egy m\u00e1sik termin\u00e1lb\u00f3l k\u00fcldj\u00fcnk utas\u00edt\u00e1st a robotnak:

    ign topic -t \"/cmd_vel\" -m ignition.msgs.Twist -p \"linear: {x: 0.5}, angular: {z: 0.05}\"\n

  4. Nyomjuk meg a lej\u00e1tsz\u00e1s gombot a szimul\u00e1torban.

A fenti l\u00e9p\u00e9seket k\u00f6vet\u0151en a robotmodellnek mozognia kell.

  1. Mozgassuk a robotot a billenty\u0171zet seg\u00edts\u00e9g\u00e9vel

Most a billenty\u0171zet olvas\u00e1s\u00e1val, szint\u00e9n ROS2 topic \u00e1ltal fogjuk ir\u00e1ny\u00edtani a robotot. Ehhez tov\u00e1bbi k\u00e9t plugin alkalmaz\u00e1sa lesz sz\u00fcks\u00e9ges: KeyPublisher \u00e9s TriggeredPublisher.

A KeyPublisher egy ign-gui plugin, amely beolvassa a billenty\u0171zet billenty\u0171inek lenyom\u00e1s\u00e1t, \u00e9s a /keyboard/keypress topic-ra k\u00fcldi. Pr\u00f3b\u00e1ljuk ki ezt a plugint:

  • Egyik termin\u00e1lban ism\u00e9t ind\u00edtsuk el a szimul\u00e1tort:
ign gazebo building_robot.sdf\n
  • A szimul\u00e1tor ablak\u00e1nak jobb fels\u0151 sark\u00e1ban klikkelj\u00fcnk a plugins leg\u00f6rd\u00fcl\u0151 list\u00e1ra, majd a Key Publisher opci\u00f3ra.

  • Egy m\u00e1sik termin\u00e1lban adjuk meg a k\u00f6vetkez\u0151t, ezzel ki\u00edrva az \u00f6sszes billenty\u0171zet-lenyom\u00e1st:

ign topic -e -t /keyboard/keypress\n

A k\u00f6vetkez\u0151 l\u00e9p\u00e9s az, hogy a billenty\u0171zet le\u00fct\u00e9seit megfeleltess\u00fck a robot ir\u00e1ny\u00edt\u00e1s\u00e1ra alkalmas parancsoknak. Erre fogjuk haszn\u00e1lni a TriggeredPublisher plugint.

A TriggeredPublisher plugin \u00e1ltalunk defini\u00e1lt m\u00f3don hoz l\u00e9tre kimenetet egy adott bemenetnek megfelel\u0151en. A building_robot.sdf f\u00e1jlban a <world> c\u00edmk\u00e9ken bel\u00fcl adjuk meg a k\u00f6vetkez\u0151 megfeleltet\u00e9st:

<plugin filename=\"libignition-gazebo-triggered-publisher-system.so\"\n        name=\"ignition::gazebo::systems::TriggeredPublisher\">\n    <input type=\"ignition.msgs.Int32\" topic=\"/keyboard/keypress\">\n        <match field=\"data\">16777235</match>\n    </input>\n    <output type=\"ignition.msgs.Twist\" topic=\"/cmd_vel\">\n        linear: {x: 0.5}, angular: {z: 0.0}\n    </output>\n</plugin>\n

Pr\u00f3b\u00e1ljuk ki a robot ir\u00e1ny\u00edt\u00e1s\u00e1t:

  • Ind\u00edtsuk el a szimul\u00e1tort ism\u00e9t:
ign gazebo building_robot.sdf\n
  • V\u00e1lasszuk ki a Key Publisher plugint.

  • Gy\u0151z\u0151dj\u00fcnk meg r\u00f3la, hogy fut a szimul\u00e1ci\u00f3, sz\u00fcks\u00e9g eset\u00e9n nyomjuk le a Lej\u00e1tsz\u00e1s gombot.

  • Nyomjuk le a Fel (\u2191) ny\u00edlbillenty\u0171t. A robotnak el kell indulnia el\u0151re.

"},{"location":"szimulacio/gyakorlat/#onallo-feladat","title":"\u00d6n\u00e1ll\u00f3 feladat","text":"

K\u00e9sz\u00edts\u00fck el az \u00f6sszes ny\u00edlbillenty\u0171 funkci\u00f3j\u00e1t a kor\u00e1bbi k\u00f3dr\u00e9szlet kib\u0151v\u00edt\u00e9s\u00e9vel. A feladat anal\u00f3g m\u00f3don, csak a param\u00e9terek m\u00f3dos\u00edt\u00e1s\u00e1val megoldhat\u00f3, az al\u00e1bbi megfeleltet\u00e9sek seg\u00edts\u00e9g\u00e9vel:

  • Balra ny\u00edl, \u00e9rt\u00e9ke: 16777234, param\u00e9terek: linear: {x: 0.0}, angular: {z: 0.5}
  • Fel ny\u00edl, \u00e9rt\u00e9ke: 16777235, param\u00e9terek: linear: {x: 0.5}, angular: {z: 0.0}
  • Jobbra ny\u00edl, \u00e9rt\u00e9ke: 16777236, param\u00e9terek: linear: {x: 0.0}, angular: {z: -0.5}
  • Le ny\u00edl, \u00e9rt\u00e9ke: 16777237, param\u00e9terek: linear: {x: 0.5}, angular: {z: 0.0}
"},{"location":"szimulacio/gyakorlat/#kornyezet-kibovitese","title":"K\u00f6rnyezet kib\u0151v\u00edt\u00e9se","text":"

Az eddig l\u00e9trehozott szimul\u00e1lt k\u00f6rnyezet csak egy talajs\u00edkot \u00e9s napf\u00e9nyt tartalmaz. Hozzunk l\u00e9tre tov\u00e1bbi k\u00f6rnyezeti elemeket primit\u00edv statikus elemek hozz\u00e1ad\u00e1s\u00e1val. Kezdj\u00fck egyetlen t\u00e9glatest, \"fal\" l\u00e9trehoz\u00e1s\u00e1val:

<model name='wall'>\n    <static>true</static>\n    <pose>5 0 0 0 0 0</pose><!--p\u00f3z a vil\u00e1ghoz k\u00e9pest-->\n    <link name='box'>\n        <pose/>\n        <visual name='visual'>\n            <geometry>\n                <box>\n                    <size>0.5 10.0 2.0</size>\n                </box>\n            </geometry>\n            <!--adjunk hozz\u00e1 anyagot (sz\u00ednt)-->\n            <material>\n                <ambient>0.0 0.0 1.0 1</ambient>\n                <diffuse>0.0 0.0 1.0 1</diffuse>\n                <specular>0.0 0.0 1.0 1</specular>\n            </material>\n        </visual>\n        <collision name='collision'>\n            <geometry>\n                <box>\n                    <size>0.5 10.0 2.0</size>\n                </box>\n            </geometry>\n        </collision>\n    </link>\n</model>\n
"},{"location":"szimulacio/gyakorlat/#onallo-feladat_1","title":"\u00d6n\u00e1ll\u00f3 feladat","text":"

Adjunk hozz\u00e1 a k\u00f6rnyezethez tov\u00e1bbi k\u00e9t elemet az al\u00e1bbi param\u00e9terekkel: 1. elem - neve (name): wall1 - helyzete (pose): (0 12 0 0 0 1.5707) - m\u00e9rete: (0.5 10.0 2.0) - anyaga, sz\u00edne tetsz\u0151leges

  1. elem
    • neve (name): wall2
    • helyzete (pose): (0 -12 0 0 0 1.5707)
    • m\u00e9rete: (0.5 10.0 2.0)
    • anyaga, sz\u00edne tetsz\u0151leges
"},{"location":"szimulacio/gyakorlat/#szenzor-hozzaadasa","title":"Szenzor hozz\u00e1ad\u00e1sa","text":"

Az el\u0151z\u0151 r\u00e9szekben kialak\u00edtottunk egy mozgathat\u00f3 robotszimul\u00e1ci\u00f3t, viszont az auton\u00f3m m\u0171k\u00f6dtet\u00e9s\u00e9hez mindenk\u00e9pp sz\u00fcks\u00e9ges valamilyen szenzor(ok) szimul\u00e1ci\u00f3ja is. A k\u00f6vetkez\u0151 l\u00e9p\u00e9sekben IMU (Inertial Measurement Unit) szenzort, valamint LiDAR szenzort fogunk hozz\u00e1adni a kor\u00e1bban kialak\u00edtott robothoz.

  • IMU szenzor

Az IMU szenzor h\u00e1rom elk\u00fcl\u00f6n\u00edthet\u0151 inform\u00e1ci\u00f3t ad: - A szenzor orient\u00e1ci\u00f3ja kvaternion form\u00e1tumban. - A szenzor sz\u00f6gsebess\u00e9ge (X, Y, Z) tengelyek k\u00f6r\u00fcl. - A szenzor line\u00e1ris gyorsul\u00e1sa (X, Y, Z) tengelyek ment\u00e9n.

Az IMU szenzor szint\u00e9n plugin seg\u00edts\u00e9g\u00e9vel adhat\u00f3 hozz\u00e1. Defini\u00e1ljuk az IMU szenzort a kor\u00e1bban l\u00e9trehozott f\u00e1jl szerkeszt\u00e9s\u00e9vel, a <world> c\u00edmk\u00e9k k\u00f6z\u00f6tt:

<plugin filename=\"libignition-gazebo-imu-system.so\"\n        name=\"ignition::gazebo::systems::Imu\">\n</plugin>\n

A plugin defini\u00e1l\u00e1s\u00e1t k\u00f6vet\u0151en defini\u00e1ljuk a szenzorra vonatkoz\u00f3 param\u00e9tereket. A szenzor azon link param\u00e9tereit adja vissza, amelyhez hozz\u00e1rendelj\u00fck. Mivel a robotra, vagyis a robot karossz\u00e9ri\u00e1j\u00e1ra vonatkoz\u00f3 m\u00e9r\u00e9seket szeretn\u00e9nk v\u00e9gezni, ezt a linket adjuk meg:

<sensor name=\"imu_sensor\" type=\"imu\">\n    <always_on>1</always_on>\n    <update_rate>1</update_rate>\n    <visualize>true</visualize>\n    <topic>imu</topic>\n</sensor>\n

Az alkalmazott param\u00e9terek a k\u00f6vetkez\u0151ek: - <always_on>: ha az \u00e9rt\u00e9ke 1, a szenzor mindig friss\u00edteni fogja a kimen\u0151 adat\u00e1t a friss\u00edt\u00e9si r\u00e1t\u00e1nak megfelel\u0151en. - <update_rate>: a kimen\u0151 adat friss\u00edt\u00e9si frekvenci\u00e1ja. - <vizualize>: ha az \u00e9rt\u00e9ke 1, a szenzor reprezent\u00e1ci\u00f3ja vizu\u00e1lisan megjelen\u00edt\u00e9sre ker\u00fcl. - <topic>: a kimen\u0151 adatokat tartalmaz\u00f3 topic neve.

Pr\u00f3b\u00e1ljuk ki a l\u00e9trehozott szenzort.

  • Ment\u00e9s ut\u00e1n ind\u00edtsuk el a szimul\u00e1tort:
ign gazebo building_robot.sdf\n
  • Egy m\u00e1sik termin\u00e1lban \u00edrjuk ki az IMU adatait. Ha a billenty\u0171zettel mozgatjuk a robotot, v\u00e1ltoz\u00e1s lesz megfigyelhet\u0151 a szenzoradatokban:
ign topic -e -t /imu\n
"},{"location":"szimulacio/gyakorlat/#forrasok","title":"Forr\u00e1sok","text":"
  • gazebosim.org/docs/fortress/sdf_worlds
  • gazebosim.org/docs/fortress/building_robot
  • gazebosim.org/docs/fortress/moving_robot
"},{"location":"szimulacio/lgsvl_nissan/","title":"LGSVL Nissan","text":"

Link: github.com/szenergy/nissanleaf-lgsvl

"},{"location":"szimulacio/lgsvl_nissan/#telepites","title":"Telep\u00edt\u00e9s","text":""},{"location":"telepites/","title":"Telep\u00edt\u00e9s","text":"

ROS 2

ROS 1 verzi\u00f3kat csak t\u00f6rt\u00e9nelmi okokb\u00f3l t\u00e1rgyalunk, a jelenlegi fejleszt\u00e9sekhez a ROS 2-t aj\u00e1nljuk.

ROS 1 alapvet\u0151en Linux rendszereken t\u00e1mogatott, b\u00e1r voltak pr\u00f3b\u00e1lkoz\u00e1sok m\u00e1s oper\u00e1ci\u00f3s rendszerekre is. Ezzel szemben az ROS 2 m\u00e1r t\u00e1mogatja a nat\u00edv Windows, Mac OS vagy egy\u00e9b Real-Time oper\u00e1ci\u00f3s rendszen t\u00f6rt\u00e9n\u0151 futtat\u00e1st. Teh\u00e1t alapvet\u0151en n\u00e9gy lehet\u0151s\u00e9g adott:

  1. Dual boot, Windows mell\u00e9 telep\u00edtett nat\u00edv Linux (legink\u00e1bb Ubuntu) \u2705 le\u00edr\u00e1s
  2. Windows WSL2, k\u00f6nny\u0171s\u00faly\u00fa Linux virtu\u00e1lis g\u00e9p \u2705 le\u00edr\u00e1s
  3. Virtu\u00e1lis g\u00e9p Windowsra \ud83d\udfe0
  4. Windows build \ud83d\udfe0

Ebb\u0151l a 4 lehet\u0151s\u00e9gb\u0151l az els\u0151 kett\u0151t aj\u00e1nljuk, de telm\u00e9szetesen a t\u00f6bbi sem tiltott. A dual boot betekint\u00e9st ny\u00fajt a Linux vil\u00e1gba, ami egy m\u00e9rn\u00f6kn\u00e9l hasznos tud\u00e1st jelent manaps\u00e1g. Telep\u00edt\u00e9sn\u00e9l k\u00f6r\u00fcltekint\u0151en kell elj\u00e1rni, hiszen egy rossz be\u00e1ll\u00edt\u00e1s adatveszt\u00e9st okoz, \u00edgy a biztons\u00e1gi ment\u00e9s is aj\u00e1nlott. A WSL (Windows Subsystem for Linux) egy k\u00f6nny\u0171s\u00faly\u00fa kompatibilit\u00e1si r\u00e9teg Linux-alap\u00fa elemek futtat\u00e1s\u00e1hoz Windows 10, vagy Windows 11 alap\u00fa rendszereken. Ahogy a k\u00f6vetkez\u0151 \u00e1br\u00e1n is l\u00e1tszik, a Linux kernel ugyanolyan egyszer\u0171en \u00e9rheti el a hardverelemeket (CPU, mem\u00f3ria, GPU), mint a Windows kernel. Ehhez k\u00e9pest a virtu\u00e1lis g\u00e9p (3. lehet\u0151s\u00e9g) egy j\u00f3val lassabb , t\u00f6bb absztrakci\u00f3s r\u00e9teget haszn\u00e1l\u00f3 megold\u00e1s, annak aj\u00e1nlott, akinek vagy nagyon modern, gyors g\u00e9pe van, vagy m\u00e1r eleve telep\u00edtett ilyen rendszereket. A nat\u00edv Windows build (4. lehet\u0151s\u00e9g) elvileg adott, de mivel a dokumen\u00e1ti\u00f3 t\u00falnyom\u00f3 r\u00e9sze Linuxra \u00e9rhet\u0151 el, \u00edgy nagyon sok extra munk\u00e1t fog jelenteni.

Az els\u0151 h\u00e1rom opci\u00f3 szeml\u00e9ltet\u00e9se:

"},{"location":"telepites/#tamogatott-operacios-rendszerek-es-ros-disztibuciok","title":"T\u00e1mogatott oper\u00e1ci\u00f3s rendszerek \u00e9s ROS disztib\u00faci\u00f3k","text":"Oper\u00e1ci\u00f3s rendszer t\u00e1mogatott t\u00e1mogatott t\u00e1mogatott Ubuntu 18.04 ROS melodic Ubuntu 20.04 ROS noetic ROS2 humble Ubuntu 22.04 ROS2 humble Windows 10 (nat\u00edv) ROS2 humble Windows 11 (nat\u00edv) ROS2 humble Windows 10 (WSL2) ROS melodic ROS noetic ROS2 humble Windows 11 (WSL2) ROS melodic ROS noetic ROS2 humble

Tip

Az ROS 1 melodic python 2.7-et t\u00e1mogat, ez nem aj\u00e1nlott.

"},{"location":"telepites/#ubuntu-es-python","title":"Ubuntu \u00e9s Python","text":"
  • Ubuntu 18.04.6 LTS Python 2.7.17
  • Ubuntu 20.04.4 LTS Python 3.8.10
  • Ubuntu 22.04.1 LTS Python 3.10.6
"},{"location":"telepites/ros_humble/","title":"ROS 2 humble","text":"

Egyszer\u0171 telep\u00edt\u00e9s

A telep\u00edt\u00e9s l\u00e9p\u00e9sr\u0151l-l\u00e9p\u00e9sre is v\u00e9grehajthat\u00f3, de k\u00e9sz\u00edtett\u00fcnk egy egyszer\u0171 shell script alap\u00fa telep\u00edt\u00e9st is.

Ahogy abevezet\u0151ben \u00edrtuk, alapvet\u0151en n\u00e9gy lehet\u0151s\u00e9g adott ROS 2 Humble telep\u00edt\u00e9s\u00e9re:

  1. Dual boot, Windows mell\u00e9 telep\u00edtett nat\u00edv Linux (legink\u00e1bb Ubuntu) \u2705 le\u00edr\u00e1s
  2. Windows WSL2, k\u00f6nny\u0171s\u00faly\u00fa Linux virtu\u00e1lis g\u00e9p \u2705 le\u00edr\u00e1s
  3. Virtu\u00e1lis g\u00e9p Windowsra \ud83d\udfe0
  4. Windows build \ud83d\udfe0

Ebb\u0151l a 4 lehet\u0151s\u00e9gb\u0151l az els\u0151 kett\u0151t aj\u00e1nljuk, de telm\u00e9szetesen a t\u00f6bbi sem tiltott. A dual boot betekint\u00e9st ny\u00fajt a Linux vil\u00e1gba, ami egy m\u00e9rn\u00f6kn\u00e9l hasznos tud\u00e1st jelent manaps\u00e1g. Telep\u00edt\u00e9sn\u00e9l k\u00f6r\u00fcltekint\u0151en kell elj\u00e1rni, hiszen egy rossz be\u00e1ll\u00edt\u00e1s adatveszt\u00e9st okoz, \u00edgy a biztons\u00e1gi ment\u00e9s is aj\u00e1nlott. A WSL (Windows Subsystem for Linux) egy k\u00f6nny\u0171s\u00faly\u00fa kompatibilit\u00e1si r\u00e9teg Linux-alap\u00fa elemek futtat\u00e1s\u00e1hoz Windows 10, vagy Windows 11 alap\u00fa rendszereken. Ahogy a k\u00f6vetkez\u0151 \u00e1br\u00e1n is l\u00e1tszik, a Linux kernel ugyanolyan egyszer\u0171en \u00e9rheti el a hardverelemeket (CPU, mem\u00f3ria, GPU stb), mint a Windows kernel. Ehhez k\u00e9pest a virtu\u00e1lis g\u00e9p (3. lehet\u0151s\u00e9g) egy j\u00f3val lassabb, t\u00f6bb absztrakci\u00f3s r\u00e9teget haszn\u00e1l\u00f3 megold\u00e1s, annak aj\u00e1nlott, akinek vagy nagyon modern, gyors g\u00e9pe van, vagy m\u00e1r eleve telep\u00edtett ilyen rendszereket. A nat\u00edv Windows build (4. lehet\u0151s\u00e9g) elvileg adott, de mivel a dokumen\u00e1ti\u00f3 t\u00falnyom\u00f3 r\u00e9sze Linuxra \u00e9rhet\u0151 el, \u00edgy nagyon sok extra munk\u00e1t fog jelenteni.

Az els\u0151 h\u00e1rom opci\u00f3 szeml\u00e9ltet\u00e9se:

"},{"location":"telepites/ros_humble/#telepites","title":"Telep\u00edt\u00e9s","text":"

A k\u00f6vetkez\u0151 le\u00edr\u00e1s Ubuntu 22.04 Jammyre vonatkozik. Megjegyz\u00e9s, hogy m\u00e1s verzi\u00f3k is t\u00e1mogatottak, ezekre vonatkoz\u00f3 telep\u00edt\u00e9s \u00e9s le\u00edr\u00e1sok el\u00e9rhet\u0151ek itt: docs.ros.org/en/humble/Installation/Alternatives.html

A k\u00f6vetkez\u0151 le\u00edr\u00e1s a docs.ros.org/en/humble/Installation.html alapszik.

"},{"location":"telepites/ros_humble/#nyelv-beallitasa","title":"Nyelv be\u00e1ll\u00edt\u00e1sa","text":"

Note

Ez a l\u00e9p\u00e9s \u00e1ltal\u00e1ban kihagyhat\u00f3

Gy\u0151z\u0151dj\u00f6n meg arr\u00f3l, hogy olyan ter\u00fcleti be\u00e1ll\u00edt\u00e1ssal rendelkezik, amely t\u00e1mogatja az UTF-8 szabv\u00e1nyt.

locale # UTF-8 ellen\u0151rz\u00e9se\n\nsudo apt update && sudo apt install locales\nsudo locale-gen en_US en_US.UTF-8\nsudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8\nexport LANG=en_US.UTF-8\n\nlocale # be\u00e1ll\u00edt\u00e1sok ellen\u0151rz\u00e9se\n
"},{"location":"telepites/ros_humble/#forrasok-beallitasa","title":"Forr\u00e1sok be\u00e1ll\u00edt\u00e1sa","text":"

Hozz\u00e1 kell adnia a ROS 2 apt t\u00e1rol\u00f3t a rendszer\u00e9hez.

El\u0151sz\u00f6r gy\u0151z\u0151dj\u00f6n meg arr\u00f3l, hogy az Ubuntu Universe adatt\u00e1r enged\u00e9lyezve van.

sudo apt install software-properties-common\nsudo add-apt-repository universe\n

ROS 2 GPG kulcs hozz\u00e1ad\u00e1sa, apt-vel.

sudo apt update && sudo apt install curl -y\nsudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg\n

Ezut\u00e1n k\u00f6vetkezik a t\u00e1rol\u00f3 hozz\u00e1ad\u00e1sa a forr\u00e1slist\u00e1hoz.

echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main\" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null\n
"},{"location":"telepites/ros_humble/#ros-2-csomagok-telepitese","title":"ROS 2 csomagok telep\u00edt\u00e9se","text":"

Friss\u00edt\u00e9s:

sudo apt update\n

A ROS 2 csomagok gyakran friss\u00edtett Ubuntu rendszerekre \u00e9p\u00fclnek. Mindig aj\u00e1nlott, hogy \u00faj csomagok telep\u00edt\u00e9se el\u0151tt meggy\u0151z\u0151dni arr\u00f3l, hogy rendszere naprak\u00e9sz-e.

sudo apt upgrade\n

Desktop telep\u00edt\u00e9s: ROS, RViz, dem\u00f3k, oktat\u00f3anyagok telep\u00edt\u00e9se:

sudo apt install ros-humble-desktop\n

Fejleszt\u0151eszk\u00f6z\u00f6k, ford\u00edt\u00f3k \u00e9s egy\u00e9b eszk\u00f6z\u00f6k ROS-csomagok k\u00e9sz\u00edt\u00e9s\u00e9hez:

sudo apt install ros-dev-tools\n

"},{"location":"telepites/ros_humble/#source","title":"Source","text":"

\u00c1ll\u00edtsa be k\u00f6rnyezet\u00e9t a k\u00f6vetkez\u0151 f\u00e1jl source-ol\u00e1s\u00e1val:

source /opt/ros/humble/setup.bash\n

Tipp: ezt meg lehet tenni a .bashrc f\u00e1jlban is echo \"source /opt/ros/humble/setup.bash\" >> ~/.bashrc.

"},{"location":"telepites/ros_humble/#telepites-ellenorzese","title":"Telep\u00edt\u00e9s ellen\u0151rz\u00e9se","text":"

Ellen\u0151rizz\u00fck a telep\u00edt\u00e9s helyess\u00e9g\u00e9t, a ros2 topic list paranccsal.

$ ros2 topic list\n\n/parameter_events\n/rosout \n

Ha minden rendben, akkor a fenti k\u00e9t topicnak kell megjelennie. Ezut\u00e1n lehet megismerni az egyszer\u0171 p\u00e9lda node-ok haszn\u00e1lat\u00e1t: docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools.html

"},{"location":"telepites/ros_humble/#telepites-utani-ajanlott-beallitasok","title":"Telep\u00edt\u00e9s ut\u00e1ni aj\u00e1nlott be\u00e1ll\u00edt\u00e1sok","text":""},{"location":"telepites/ros_humble/#konzol-szinek","title":"Konzol sz\u00ednek","text":"

Alap\u00e9rtelmez\u00e9s szerint a konzol kimenet nem sz\u00ednezett, de ezt c\u00e9lszer\u0171 be\u00e1ll\u00edtani az RCUTILS_COLORIZED_OUTPUT k\u00f6rnyezeti v\u00e1ltoz\u00f3val (ak\u00e1r bashrc-be \u00edrva). P\u00e9ld\u00e1ul:

export RCUTILS_COLORIZED_OUTPUT=1 \n

R\u00e9szletek: docs.ros.org/en/humble/Tutorials/Demos/Logging-and-logger-configuration.html#id14

"},{"location":"telepites/ros_humble/#colcon_cd","title":"colcon_cd","text":"

Szint\u00e9n c\u00e9lszer\u0171 be\u00e1ll\u00edtani a colcon_cd paranccsot, \u00edgy gyorsan v\u00e1lthatunk munkak\u00f6nyvt\u00e1r\u00e1t egy csomag k\u00f6nyvt\u00e1r\u00e1ra. P\u00e9ldak\u00e9nt a colcon_cd some_ros_package parancsra gyorsan a ~/ros2_ws/src/some_ros_package k\u00f6nyvt\u00e1rba ugorhatunk.

R\u00e9szletek: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html#setup-colcon-cd

"},{"location":"telepites/ros_humble/#otthoni-geptermi-telepites","title":"Otthoni / g\u00e9ptermi telep\u00edt\u00e9s","text":"

G\u00e9pteremben a k\u00f6vetkez\u0151 install_humble.sh f\u00e1jlt (shell scriptet) futtatuk minden g\u00e9pen.

wget https://raw.githubusercontent.com/sze-info/arj/main/docs/telepites/install_humble.sh\n
sudo chmod +x install_humble.sh\n

Otthon:

./install_humble.sh\n
G\u00e9pteremben:
./install_humble.sh campus\n

"},{"location":"telepites/ros_humble/#workspace-reset","title":"Workspace reset","text":"

Ha szeretn\u00e9nk a teljes ros2_ws-t t\u00f6r\u00f6lni, majd \u00fajra kl\u00f3nozni \u00e9s buildelni (~5 percig eltart), akkor a k\u00f6vetkez\u0151 egyetlen hosz\u00fa paranccsal megtehetj\u00fck:

cd ~ ; rm ws_reset.sh; wget https://raw.githubusercontent.com/sze-info/arj/main/docs/telepites/ws_reset.sh; sudo chmod +x ws_reset.sh; ./ws_reset.sh\n
"},{"location":"telepites/ubuntu/","title":"Ubuntu dual boot","text":""},{"location":"telepites/win10/","title":"Windows WSL2","text":"

A Windows Subsystem for Linux egy kompatibilit\u00e1si r\u00e9teg Linux-alap\u00fa elemek nat\u00edv futtat\u00e1s\u00e1hoz Windows 10, vagy Windows 11 alap\u00fa rendszereken. Akkor \u00e9rdemes v\u00e1lasztani a WSL haszn\u00e1lat\u00e1t, ha nem szeretn\u00e9tek nat\u00edv Ubuntu-t (pl 18.04 / 22.04) telep\u00edteni a sz\u00e1m\u00edt\u00f3g\u00e9peitekre. A tant\u00e1rgyban haszn\u00e1lhat\u00f3 rendszer t\u00f6bbf\u00e9le m\u00f3don is l\u00e9trehozhat\u00f3:

  • WSL telep\u00edt\u00e9se \u00e9s Snapshot import\u00e1l\u00e1sa link
  • WSL telep\u00edt\u00e9se \u00e9s ROS install\u00e1l\u00e1sa Script seg\u00edts\u00e9g\u00e9vel link
"},{"location":"telepites/win10/#wsl-telepitese-es-snapshot-importalasa","title":"WSL telep\u00edt\u00e9se \u00e9s Snapshot import\u00e1l\u00e1sa","text":"

A telep\u00edt\u00e9st bemutat\u00f3 vide\u00f3:

A vide\u00f3 l\u00e9p\u00e9sei sz\u00f6vegesen:

  1. WSL snapshot (backup f\u00e1jl) let\u00f6lt\u00e9se: WSL snapshot let\u00f6lt\u00e9se ~2.5 GB
  2. Snapshot kicsomagol\u00e1sa .zip >> .tar
  3. Powershell (Admin) WSL feature bekapcsol\u00e1sa, majd WSL telep\u00edt\u00e9se:
    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux\n
    wsl --install --no-distribution\n
  4. Powershell, WSL Snapshot f\u00e1jl (tar) import\u00e1l\u00e1s:
    wsl --import ajr1 .\\ajr1\\ .\\ajr24a.tar\n
  5. VS code \u00e9s WSL kieg\u00e9sz\u00edt\u0151 telep\u00edt\u00e9se:

Danger

A wsl -l -v parancs list\u00e1zza a telep\u00edtett WSL verzi\u00f3kat. A VERSION oszlopnak 2-nek kell lennie, k\u00fcl\u00f6nben a WSL elavult verzi\u00f3j\u00e1t telep\u00edtett\u00fck. P\u00e9lda helyes kimenetre:

NAME            STATE           VERSION\nUbuntu          Stopped         2\nUbuntu-22.04    Stopped         2\nUbuntu-24.04    Running         2\najr1            Stopped         2\n
Amennyiben a VERSION oszlopban 1-es szerepel wsl --update paranccsal lehet a verzi\u00f3t friss\u00edteni.

"},{"location":"telepites/win10/#tovabbi-ajanlott-beallitasok","title":"Tov\u00e1bbi aj\u00e1nlott be\u00e1ll\u00edt\u00e1sok","text":"

A Windows Terminal programban aj\u00e1nlott be\u00e1ll\u00edtani a Deafault Profile-t az ajr1-re, hogy mindig ezzel induljon a program. Tov\u00e1bb\u00e1 az Open windows from previous session be\u00e1ll\u00edt\u00e1s is hasznos lehet, hogy a legut\u00f3bbi \u00e1llapotban induljon a program (pl. t\u00f6bb panellel).s

A paneleket ezut\u00e1n a Alt+Shift+minus vagy Alt+Shift+plus billenty\u0171kombin\u00e1ci\u00f3val lehet l\u00e9trehozni. Ez sz\u00e9tosztja a termin\u00e1l ablakot (Split pane) t\u00f6bb r\u00e9szre vertik\u00e1lisan vagy horizont\u00e1lisan.

"},{"location":"telepites/win10/#wsl-telepitese-es-ros-installalasa-script-segitsegevel","title":"WSL telep\u00edt\u00e9se \u00e9s ROS install\u00e1l\u00e1sa Script seg\u00edts\u00e9g\u00e9vel","text":"

A WSL telep\u00edt\u00e9s\u00e9t bemutat\u00f3 Windows 11-es vide\u00f3 (Windows 10 verzi\u00f3 lejjebb, de nagyr\u00e9szt megegyez\u0151 tartalommal):

A vide\u00f3 l\u00e9p\u00e9sei sz\u00f6vegesen:

  • Rendszergazdak\u00e9nt futtatva nyissatok egy PowerShell ablakot.
  • M\u00e1solj\u00e1tok be az al\u00e1bbi parancsot. Ezzel enged\u00e9lyezitek a WSL haszn\u00e1lat\u00e1t.
    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux\n
  • Ind\u00edts\u00e1tok \u00fajra a sz\u00e1m\u00edt\u00f3g\u00e9pet az Y bet\u0171 be\u00edr\u00e1s\u00e1val. (opcion\u00e1lis)
  • Nyiss\u00e1tok meg a Microsoft Store-t, \u00e9s keressetek r\u00e1 a Windows Subsystem for Linux Preview-ra. Telep\u00edts\u00e9tek.
  • Szint\u00e9n a Microsoft Store-ban keressetek r\u00e1 az Ubuntu 22.04-re, \u00e9s telep\u00edts\u00e9tek, vagy PowerShell (Admin):
    wsl --install -d Ubuntu-22.04\n
  • A k\u00f6nnyebb kezelhet\u0151s\u00e9g \u00e9rdek\u00e9ben \u00e9rdemes telep\u00edteni a Windows Terminal programot is. Szint\u00e9n a Microsoft Store-ban keressetek r\u00e1 a Windows Terminal-ra, \u00e9s telep\u00edts\u00e9tek.
  • Ind\u00edts\u00e1tok el a Windows Terminal programot, \u00e9s a Ctrl+, (Control \u00e9s vessz\u0151) billenty\u0171kombin\u00e1ci\u00f3val nyiss\u00e1tok meg a be\u00e1ll\u00edt\u00e1sokat. A Default Profile be\u00e1ll\u00edt\u00e1si sor leg\u00f6rd\u00fcl\u0151 list\u00e1j\u00e1b\u00f3l v\u00e1lassz\u00e1tok az Ubuntu 22.04-et.
  • Ind\u00edts\u00e1tok \u00fajra a Windows Terminal-t. Az els\u0151 indul\u00e1skor adjatok meg tetsz\u0151leges felhaszn\u00e1l\u00f3nevet \u00e9s jelsz\u00f3t.
  • A megold\u00e1s kidolgoz\u00e1s\u00e1hoz a VS Code szerkeszt\u0151t javasoljuk. Telep\u00edts\u00e9tek innen: code.visualstudio.com/download
  • V\u00e9g\u00fcl telep\u00edts\u00e9tek a VS Code Remote Development kieg\u00e9sz\u00edt\u0151j\u00e9t, hogy WSL haszn\u00e1lat\u00e1val is el\u00e9rhet\u0151 legyen: marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

A WSL telep\u00edt\u00e9s\u00e9t bemutat\u00f3 Windows 10-es vide\u00f3 itt \u00e9rhet\u0151 el:

A VS Code telep\u00edt\u00e9s\u00e9hez itt tal\u00e1ltok \u00fatmutat\u00f3t:

"},{"location":"tervezes/","title":"Tervez\u00e9s","text":"

Megk\u00fcl\u00f6nb\u00f6ztethet\u00fcnk glob\u00e1lis tervez\u00e9s \u00e9s lok\u00e1lis tervez\u00e9st.

A tervez\u00e9s mint fogalom arra a k\u00e9rd\u00e9sre ad v\u00e1laszt, hogy hogyan jutunk el A-b\u00f3l B pontba a megfelel\u0151 krit\u00e9riumok mellett. A tervez\u00e9snek k\u00e9t alr\u00e9sze van a p\u00e1lya- vagy \u00fatvonaltervez\u00e9s, amely megmondja hogy az adott szakaszon merre kell menni illetve a trajekt\u00f3riatervez\u00e9s, amely azt mondja meg hogy az adott szakaszon milyen sebess\u00e9gel kell haladnia az adott j\u00e1rm\u0171nek.

A tervez\u00e9si feladat jellege szerint megk\u00fcl\u00f6nb\u00f6ztett\u00fcnk glob\u00e1lis \u00e9s lok\u00e1lis tervez\u00e9st. A k\u00e9t tervez\u00e9si m\u00f3dszer k\u00fcl\u00f6nbs\u00e9geit az al\u00e1bbi t\u00e1bl\u00e1zat foglalja \u00f6ssze:

Glob\u00e1lis tervez\u00e9s Lok\u00e1lis tervez\u00e9s T\u00e9rk\u00e9p alap\u00fa Szenzor alap\u00fa Ismert terep/munkater\u00fclet Ismeretlen ter\u00fclet Az \u00fat tervez\u00e9s el\u0151bb t\u00f6rt\u00e9nik mint a mozg\u00e1s Az \u00fat tervez\u00e9s \u00e9s a mozg\u00e1s egyszerre t\u00f6rt\u00e9nik Nincs szigor\u00fa k\u00f6vetelm\u00e9ny a sz\u00e1m\u00edt\u00e1si id\u0151re K\u00f6vetelm\u00e9ny hogy val\u00f3s id\u0151ben m\u0171k\u00f6dj\u00f6n

A tervez\u00e9s v\u00e9geredm\u00e9nye mind lok\u00e1lis \u00e9s glob\u00e1lis esetben egy diszkr\u00e9t pontokra osztott szakasz, amelynek minden pontja tartalmaz poz\u00edci\u00f3, orient\u00e1ci\u00f3 \u00e9s sebess\u00e9g inform\u00e1ci\u00f3kat, amit r\u00f6viden trajekt\u00f3ri\u00e1nak h\u00edvunk: .

flowchart LR\nsubgraph Plan [Tervez\u00e9s]\n  G[Glob\u00e1lis<br/>tervez\u00e9s]:::red -->|\u00fatvonal| L[Lok\u00e1lis<br/>tervez\u00e9s]:::red\nend\nsubgraph Perception [\u00c9szlel\u00e9s]\n  T[T\u00e9rk\u00e9pez\u00e9s<br/>/\u00e9szlel\u00e9s/]:::light \n  H[Lokaliz\u00e1ci\u00f3<br/>/\u00e9szlel\u00e9s/]:::light\n  P[Predikci\u00f3<br/>/\u00e9szlel\u00e9s/]:::light \nend\nT --->|t\u00e9rk\u00e9p| L\nH --->|pose| L\nP --->|predikt\u00e1lt objektumok| L\nsubgraph Control [Szab\u00e1lyoz\u00e1s]\n  L --> |trajekt\u00f3ria| S[Szab\u00e1lyoz\u00e1s]:::light \nend\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"tervezes/#globalis-tervezes","title":"Glob\u00e1lis tervez\u00e9s","text":""},{"location":"tervezes/#bevezetes","title":"Bevezet\u00e9s","text":"

Az al\u00e1bbi n\u00e9met nyelv\u0171, de angol PPT-t \u00e9s feliratot tartalmaz\u00f3 vide\u00f3 a TU M\u00fcnchen tananyag\u00e1nak r\u00e9sze, a t\u00e9m\u00e1ban j\u00f3 \u00f6sszefoglal\u00f3:

A Vide\u00f3hoz tartoz\u00f3 PDF f\u00e1jl el\u00e9rhet\u0151 itt

Ismertebb glob\u00e1lis tervez\u0151 algoritmusok:

  • RRT (Rapidly exploring random tree): Az RRT egy mintav\u00e9telez\u00e9s alap\u00fa m\u00f3dszer bej\u00e1rand\u00f3 glob\u00e1lis t\u00e9r felder\u00edt\u00e9s\u00e9re \u00e9s \u00fatvonalak tervez\u00e9s\u00e9re. Megjegyz\u00e9s: bizonyos esetekben lok\u00e1lis tervez\u0151k\u00e9nt is haszn\u00e1lj\u00e1k. Az algoritmus random (v\u00e9letlenszer\u0171) m\u00f3don v\u00e1laszt ki pontokat \u00e9s n\u00f6vekv\u0151 ir\u00e1nyban kiterjeszti a f\u00e1t az\u00e1ltal, hogy a legk\u00f6zelebbi m\u00e1r megl\u00e9v\u0151 pontokhoz kapcsolja az \u00faj pontokat. Tov\u00e1bbi inform\u00e1ci\u00f3: en.wikipedia.org/wiki/Rapidly_exploring_random_tree.
  • Informed-RRT: Az Informed-RRT az alap RRT kiterjeszt\u00e9se, amely heurisztik\u00e1t haszn\u00e1l a c\u00e9l fel\u00e9 t\u00f6rt\u00e9n\u0151 hat\u00e9konyabb felder\u00edt\u00e9sre. Az algoritmus \u00fagy tervezi az \u00fatvonalakat, hogy el\u0151sz\u00f6r a k\u00f6zelebbi ter\u00fcleteket fedezze fel, majd a k\u00e9s\u0151bbi f\u00e1zisokban elmozduljon a t\u00e1volabbi ter\u00fcletek fel\u00e9.
  • A-star: Az A* algoritmus (ejtsd \"A csillag\") gr\u00e1fbej\u00e1r\u00f3 \u00e9s \u00fatvonalkeres\u00e9si algoritmus, amelyet teljess\u00e9ge, hat\u00e9konys\u00e1ga miatt gyakran r\u00e9gen el\u0151szeretettel haszn\u00e1ltak. Az egyik f\u0151 gyakorlati h\u00e1tr\u00e1nya az $$ O(b^{d}) $$ t\u00e1rhelybonyolults\u00e1ga, mivel az \u00f6sszes gener\u00e1lt csom\u00f3pontot elt\u00e1rolja a mem\u00f3ri\u00e1ban. \u00cdgy a gyakorlati \u00fatkeres\u0151 rendszerekben \u00e1ltal\u00e1ban jobban teljes\u00edtenek n\u00e1la olyan algoritmusok, amelyek k\u00e9pesek a gr\u00e1f el\u0151feldolgoz\u00e1s\u00e1ra a jobb teljes\u00edtm\u00e9ny \u00e9rdek\u00e9ben. Tov\u00e1bbi inform\u00e1ci\u00f3: hu.wikipedia.org/wiki/A*_algoritmus.
  • D-star: A D algoritmus (ejtsd \"D csillag\") a \"Dynamic A-star\" r\u00f6vid\u00edt\u00e9se. Ez az algoritmus egy m\u00f3dos\u00edtott v\u00e1ltozata az A algoritmusnak, amely dinamikus k\u00f6rnyezetekben haszn\u00e1lhat\u00f3. A Dynamic A-star algoritmus folyamatosan friss\u00edti az \u00fatvonalat, mik\u00f6zben a robot halad az \u00faton, hogy alkalmazkodjon a v\u00e1ltoz\u00f3 k\u00f6r\u00fclm\u00e9nyekhez vagy akad\u00e1lyokhoz. Tov\u00e1bbi inform\u00e1ci\u00f3: en.wikipedia.org/wiki/D* .
  • Dijkstra: A Dijkstra algoritmus az egyik legismertebb \u00e9s leggyakrabban haszn\u00e1lt algoritmus a legr\u00f6videbb \u00fat keres\u00e9s\u00e9re egy gr\u00e1fban. Ez egy sz\u00e9less\u00e9gi keres\u0151algoritmus, amely iterat\u00edvan b\u0151v\u00edti a f\u00e1t a kezd\u0151pontb\u00f3l kiindulva, \u00e9s kiv\u00e1lasztja a legk\u00f6zelebbi m\u00e9g nem l\u00e1togatott cs\u00facsot. Tov\u00e1bbi inform\u00e1ci\u00f3: en.wikipedia.org/wiki/Dijkstra's_algorithm.

J\u00f3 tudni, hogy a fenti algoritmusokanak sz\u00e1mos v\u00e1ltozata, tov\u00e1bbfejleszt\u00e9se ismert.

"},{"location":"tervezes/#utazo-ugynok-problema","title":"Utaz\u00f3 \u00fcgyn\u00f6k probl\u00e9ma","text":"

Az utaz\u00f3 \u00fcgyn\u00f6k probl\u00e9ma (TSP traveling salesman problem) egy j\u00f3l ismert kombinatorikus optimaliz\u00e1ci\u00f3s probl\u00e9ma, amely a sz\u00e1m\u00edt\u00e1studom\u00e1ny \u00e9s a matematika ter\u00fclet\u00e9n jelent meg. A probl\u00e9ma l\u00e9nyege az, hogy az utaz\u00f3 \u00fcgyn\u00f6knek egy adott v\u00e1rosokb\u00f3l \u00e1ll\u00f3 halmazt kell megl\u00e1togatnia, \u00e9s vissza kell t\u00e9rnie a kiindul\u00e1si v\u00e1rosba a lehet\u0151 legr\u00f6videbb \u00faton \u00fagy, hogy minden v\u00e1rost pontosan egyszer l\u00e1togat meg. Tob\u00e1bbi inform\u00e1ci\u00f3: hu.wikipedia.org/wiki/Az_utaz\u00f3_\u00fcgyn\u00f6k_probl\u00e9m\u00e1ja.

Form\u00e1lisan megfogalmazva, legyen adott egy ir\u00e1ny\u00edtott s\u00falyozott gr\u00e1f, ahol a csom\u00f3pontok reprezent\u00e1lj\u00e1k a v\u00e1rosokat, az \u00e9lek a v\u00e1rosok k\u00f6z\u00f6tti utakat jel\u00f6lik, \u00e9s a s\u00falyok az \u00e9lek hossz\u00e1t jel\u00f6lik. A c\u00e9l az, hogy tal\u00e1ljunk egy olyan Hamilton-k\u00f6rt (k\u00f6r, amely minden csom\u00f3pontot pontosan egyszer \u00e9rint), amelynek \u00f6sszs\u00falya minim\u00e1lis. A probl\u00e9ma az NP-neh\u00e9z oszt\u00e1lyba tartozik, ami azt jelenti, hogy nincs ismert hat\u00e9kony algoritmus, amely mindig garant\u00e1ltan megtal\u00e1lja a legoptim\u00e1lisabb megold\u00e1st polinomi\u00e1lis id\u0151ben a v\u00e1rosok sz\u00e1m\u00e1val ar\u00e1nyosan.

Auton\u00f3m j\u00e1rm\u0171vek \u00e9s robotika vonatkoz\u00e1s\u00e1ban legt\u00f6bbsz\u00f6r nem a klasszikus TSP probl\u00e9ma mer\u00fcl fel, hanem annak deriv\u00e1tuma, hiszen p\u00e9ld\u00e1ul egy auton\u00f3m j\u00e1rm\u0171 eset\u00e9ben pontosan tudjuk honnan indulunk \u00e9s hova \u00e9rkez\u00fcnk. Ez a klasszikus utaz\u00f3 \u00fcgyn\u00f6k probl\u00e9ma eset\u00e9n nem ismert felt\u00e9tel.

"},{"location":"tervezes/#lokalis-tervezes","title":"Lok\u00e1lis tervez\u00e9s","text":""},{"location":"tervezes/#bevezetes_1","title":"Bevezet\u00e9s","text":"

Az al\u00e1bbi n\u00e9met nyelv\u0171, de angol PPT-t \u00e9s feliratot tartalmaz\u00f3 vide\u00f3 a TU M\u00fcnchen tananyag\u00e1nak r\u00e9sze, a t\u00e9m\u00e1ban j\u00f3 \u00f6sszefoglal\u00f3:

A Vide\u00f3hoz tartoz\u00f3 PDF f\u00e1jl el\u00e9rhet\u0151 itt.

"},{"location":"tervezes/#motivacio","title":"Motiv\u00e1ci\u00f3","text":"

A lok\u00e1lis tervez\u00e9s voltak\u00e9pp a val\u00f3s id\u0151ben m\u00e9rt, dinamikusan v\u00e1ltoz\u00f3 k\u00f6r\u00fclm\u00e9nyekre adott tervez\u00e9si v\u00e1lasz. Mit \u00e9rt\u00fcnk ez alatt? A legegyszer\u0171bb p\u00e9lda, ha a glob\u00e1lis tervez\u00e9st gyakorlatilag egy \u00fatvonal megtervez\u00e9s\u00e9hez (pl. hogyan jussak el A-b\u00f3l B-be) hasonl\u00edtjuk, a lok\u00e1lis tervez\u00e9st pedig az adott s\u00e1vban, adott forgalmi helyzetben t\u00f6rt\u00e9n\u0151 feladathoz hasonl\u00edtjuk. Azonban l\u00e1thatjuk, hogy egy tervez\u00e9si szint \"lok\u00e1lis\" \u00e9s \"glob\u00e1lis\" mivoltja nem mindig k\u00fcl\u00f6n\u00fcl el 100%-ban egym\u00e1st\u00f3l. Pl. megtervezz\u00fck, hogy az M1-es aut\u00f3p\u00e1ly\u00e1n szeretn\u00e9nk haladni. Ezen bel\u00fcl t\u00f6bb s\u00e1v is van, \u00edgy melyiket v\u00e1lasszuk? Alapb\u00f3l a k\u00fcls\u0151 s\u00e1vot v\u00e1lasztjuk, ezt tekinhetj\u00fck a glob\u00e1lis trajekt\u00f3ri\u00e1nak. Ugyanakkor menetk\u00f6zben s\u00e1vot kell v\u00e1ltanunk, \u00e9s \u00edgy a bels\u0151 s\u00e1vot k\u00f6vetj\u00fck. Ezt egy \u00fat sor\u00e1n t\u00f6bbsz\u00f6r megtessz\u00fck. A teljes \u00fatra vet\u00edtve \u00edgy a k\u00f6vetni k\u00edv\u00e1nt s\u00e1v id\u0151nk\u00e9nt a bels\u0151, id\u0151nk\u00e9nt a k\u00fcls\u0151 s\u00e1v lesz. Ezt el\u0151re nem tudjuk megmondani, \u00edgy a legels\u0151 glob\u00e1lis trajekt\u00f3ria defin\u00edci\u00f3t nem el\u00e9g\u00edtj\u00fck ki. Tekinthetj\u00fck lok\u00e1lis tervez\u00e9si probl\u00e9m\u00e1nak, viszont az, hogy a bels\u0151 vagy k\u00fcls\u0151 s\u00e1vot k\u00f6vetj\u00fck, nem f\u00fcgg k\u00fcls\u0151 t\u00e9nyez\u0151kt\u0151l, kiz\u00e1r\u00f3lag a d\u00f6nt\u00e9s maga f\u00fcgg att\u00f3l (pl. s\u00e1vot v\u00e1ltunk egy el\u0151tt\u00fcnk halad\u00f3 aut\u00f3 miatt), viszont ha m\u00e1r s\u00e1vot v\u00e1ltottunk, az \u00faj s\u00e1v \u00e1ltal kijel\u00f6lt \u00fatvonal megintcsak nem f\u00fcgg dinamikus t\u00e9nyez\u0151kt\u0151l. Ezeket az ellentmond\u00e1sokat t\u00f6bbf\u00e9lek\u00e9ppen is feloldhatjuk:

  • egy el\u0151re eltervezett \u00fatvonalat tekint\u00fcnk glob\u00e1lisnak (ez esetben ez a k\u00fcls\u0151 s\u00e1v), mind m\u00f3dos\u00edt\u00e1s lok\u00e1lis, vagy
  • mag\u00e1t az aut\u00f3p\u00e1ly\u00e1n halad\u00e1st tekintj\u00fck glob\u00e1lis \u00fatvonalnak, ami \u00edgy nem f\u00fcgg a s\u00e1vokt\u00f3l, bevezet\u00fcnk egy k\u00f6z\u00e9ps\u0151 szintet, nevezz\u00fck glob\u00e1lis trajekt\u00f3ri\u00e1nak, amely ez esetben k\u00e9t alternat\u00edv \u00fatvonalat jelent (k\u00fcls\u0151 vagy bels\u0151 s\u00e1v), \u00e9s egy lok\u00e1lis trajekt\u00f3ri\u00e1t, ami ennek a m\u00f3dos\u00edt\u00e1sa val\u00f3s idej\u0171 inform\u00e1ci\u00f3k alapj\u00e1n, vagy
  • a glob\u00e1lis trajekt\u00f3ria sem fix, hanem id\u0151ben v\u00e1ltozhat, de csak ritk\u00e1n, ha erre k\u00fcls\u0151 trigger jelt ad (pl. s\u00e1vv\u00e1lt\u00e1s).

Ebben a fejezetben a lok\u00e1lis trajekt\u00f3ria megtervez\u00e9s\u00e9h\u00e9z sz\u00fcks\u00e9ges alapokat vessz\u00fck \u00e1t, \u00edgy a k\u00f6vetkez\u0151kben kiz\u00e1r\u00f3lag erre a szintre koncentr\u00e1lunk. A fenti p\u00e9ld\u00e1ban szerepl\u0151 lok\u00e1lis tervez\u00e9si feladatr\u00f3l mind elmondhat\u00f3, hogy:

  • adott hozz\u00e1 valamilyen glob\u00e1lis \u00fatvonal (pl. s\u00e1v), amit alapul vesz\u00fcnk,
  • figyelembe kell venni a val\u00f3sidej\u0171 v\u00e1ltoz\u00f3kat (pl. m\u00e1s j\u00e1rm\u0171vek),
  • mindig a j\u00e1rm\u0171 \u00e1ltal befuthat\u00f3 \u00fatvonalat kell tervezni, azaz a lek\u00f6vet\u0151 szab\u00e1lyz\u00e1s szempontj\u00e1b\u00f3l stabil, az utasok sz\u00e1m\u00e1ra pedig komfortos; ezt r\u00f6viden mondhatjuk \"kinetikailag j\u00f3l kondicion\u00e1lt\" \u00fatvonalnak is,
  • az \u00fatvonal legyen biztons\u00e1gos, azaz ne s\u00e9rtsen hat\u00e1rokat illetve kell\u0151 t\u00e1vols\u00e1got tartson m\u00e1s objektumokt\u00f3l.

Ahhoz, hogy ezeket a c\u00e9lokat teljes\u00edteni tudjuk, tudni kell, pontosan a glob\u00e1lis \u00fatvonalat, m\u00e9rni kell a dinamikus v\u00e1ltoz\u00f3kat, ismern\u00fcnk kell a j\u00e1rm\u0171vet illetve tudnunk kell, pontosan mit jelent az utasok sz\u00e1m\u00e1ra a \"komfort\". Emellett fontos kiemelni, hogy a lok\u00e1lis \u00fatvonal a legt\u00f6bbsz\u00f6r nem kiz\u00e1r\u00f3lag pontok halmaza. A trajekt\u00f3ria reprezent\u00e1l\u00e1s\u00e1ra valamilyen modellt haszn\u00e1lunk, azaz geometriailag kompakt form\u00e1ban \u00edrjuk le. Ez a gyakorlatban jelenthet pl. polinomi\u00e1lis form\u00e1t, Euler-g\u00f6rb\u00e9t, Spline-t...stb. Ezek a g\u00f6rbe le\u00edr\u00e1sok mind v\u00e9ges sz\u00e1m\u00fa param\u00e9terrel \u00edrnak le egy g\u00f6rb\u00e9t. Ahhoz, hogy a g\u00f6rbe egy pontj\u00e1t megkapjuk, a g\u00f6rb\u00e9t le\u00edr\u00f3 f\u00fcggv\u00e9nyt ki\u00e9rt\u00e9kelj\u00fck egy adott X t\u00e1vols\u00e1gon. Ez a megk\u00f6zel\u00edt\u00e9s az\u00e9rt hasznos, mert \u00edgy hossz\u00fa g\u00f6rb\u00e9ket is kev\u00e9s param\u00e9ter seg\u00edts\u00e9g\u00e9vel tudunk le\u00edrni, \u00e9s \u00edgy a megval\u00f3s\u00edt\u00e1s sor\u00e1n mem\u00f3ri\u00e1t \u00e9s fut\u00e1sid\u0151t sp\u00f3rolunk. Tov\u00e1bb\u00e1 az egyenlet deriv\u00e1ltjai tov\u00e1bbi mennyis\u00e9geket (pl. orient\u00e1ci\u00f3, g\u00f6rb\u00fclet) adnak meg, \u00e9s \u00edgy a szab\u00e1lyz\u00e1s sz\u00e1m\u00e1ra ezeket k\u00f6nnyen el\u0151 tudjuk \u00e1ll\u00edtani.

"},{"location":"tervezes/#lokalis-tervezo-algoritmusok","title":"Lok\u00e1lis tervez\u0151 algoritmusok","text":"

A lok\u00e1lis megold\u00e1sokat, ahogy a bevezet\u0151 vide\u00f3ban is l\u00e1thattuk neh\u00e9z csoportos\u00edtani, rendszerezni, a megold\u00e1sok gyakran nem tisz\u00e1n egy m\u00f3dszertant haszn\u00e1lnak. P\u00e9lda erre a State Lattice tervez\u0151, ami grid-szer\u0171 r\u00e1cs szerkezeten dolgozik, de gr\u00e1f-szer\u0171 keres\u00e9st haszn\u00e1l. Ide t\u00f6bbnyire olyan ismertebb lok\u00e1lis tervez\u0151 algoritmusokat, algoritmuscsal\u00e1dokat sorolunk fel, amiknek van ny\u00edlt forr\u00e1s k\u00f3d\u00fa implement\u00e1ci\u00f3juk:

  • DWA (Dynamic Window Approach): A robotikai / auton\u00f3m mozg\u00e1stervez\u00e9sben a DWA megk\u00f6zel\u00edt\u00e9s egy online \u00fctk\u00f6z\u00e9s elker\u00fcl\u00e9si strat\u00e9gia, \u00fatvonaltervez\u00e9s\u00e9hez \u00e9s navig\u00e1ci\u00f3j\u00e1hoz dinamikus k\u00f6rnyezetben. Ahogy a neve is mutatja az el\u0151rehalad\u00e1s sor\u00e1n egy dinamikus ablakot tol maga el\u0151tt a robot / j\u00e1rm\u0171. T\u00f6bb lehets\u00e9ges ir\u00e1nyt (pontosabban trajakt\u00f3ri\u00e1t) vesz sz\u00e1mba, majd ebb\u0151l azt az \u00e1llapotot v\u00e1laszt\u00e1sztja, amit a lekisebb k\u00f6lts\u00e9g\u0171nek \u00edt\u00e9l. Tov\u00e1bbi inform\u00e1ci\u00f3: en.wikipedia.org/wiki/Dynamic_window_approach.
  • TEB (Timed Elastic Band): Szint\u00e9n online, mozg\u00f3 robotok trajekt\u00f3ri\u00e1j\u00e1nak tervez\u00e9s\u00e9re \u00e9s k\u00f6vet\u00e9s\u00e9re szolg\u00e1l dinamikus k\u00f6rnyezetben. A TEB algoritmus k\u00fcl\u00f6n\u00f6sen hasznos nem-holon\u00f3m robotok (mint p\u00e9ld\u00e1ul az aut\u00f3k) sz\u00e1m\u00e1ra, amelyeknek korl\u00e1tozott a mozg\u00e1si szabads\u00e1guk. A m\u00f3dszer lok\u00e1lisan optimaliz\u00e1lja a robot p\u00e1ly\u00e1j\u00e1t a p\u00e1lyafut\u00e1si id\u0151, az akad\u00e1lyokt\u00f3l val\u00f3 elv\u00e1laszt\u00e1s \u00e9s a fut\u00e1s k\u00f6zbeni kinodinamikai korl\u00e1tok betart\u00e1sa tekintet\u00e9ben. Neve az gumi / elasztikus szalagra utal, ami k\u00f6nnyed\u00e9n hajtogathat\u00f3 a megfele\u0151 ir\u00e1nyba. Tov\u00e1bbi inform\u00e1ci\u00f3: github.com/rst-tu-dortmund/teb_local_planner.
  • State Lattice: A robot / j\u00e1rm\u0171 kinodinamikai korl\u00e1tai az \u00e1llapotr\u00e1cs gr\u00e1fban vannak k\u00f3dolva, \u00e9s ebben a gr\u00e1fban b\u00e1rmely \u00fatvonal megval\u00f3s\u00edthat\u00f3. A gr\u00e1f fel\u00e9p\u00edt\u00e9se ut\u00e1n b\u00e1rmilyen gr\u00e1fkeres\u0151 algoritmus haszn\u00e1lhat\u00f3 a tervez\u00e9shez. navigation.ros.org/configuration/packages/smac/configuring-smac-lattice.html
  • RRT (Rapidly exploring random tree): RRT-r\u0151l m\u00e1r volt sz\u00f3 a glob\u00e1lis tervez\u00e9skor is, de lok\u00e1lis m\u00f3dszerekn\u00e9l is haszn\u00e1lj\u00e1k.

Algroitmuscsal\u00e1dok:

  • Gr\u00e1f alap\u00fa megold\u00e1sok: A folytonos t\u00e9rben gr\u00e1f seg\u00edts\u00e9g\u00e9vel keres\u0151 megold\u00e1sok tartoznak ide. Gyakran seg\u00edts\u00e9gk\u00e9ppen valamilyen lok\u00e1lis t\u00e9rk\u00e9pmodellt haszn\u00e1lnak, mint a Lanelet2. Ide tartozik pl. az Autoware obstacle_avoidance_planner.
  • Grid alap\u00fa megold\u00e1sok: A folytonos t\u00e9r r\u00e1csszer\u0171 diszkretiz\u00e1l\u00e1s\u00e1val keletkez\u0151 grid-et haszn\u00e1l\u00f3 algoritmusok tartoznak ide. Gyakran haszn\u00e1ljuk a voxel grid, illetve az occupancy grid (foglats\u00e1gi r\u00e1cs) kifejez\u00e9st a diszkr\u00e9t t\u00e9r le\u00edr\u00e1s\u00e1ra. El\u0151nye, hogy bizonyos algoritmusok k\u00f6nnyebben Tov\u00e1bbi inform\u00e1ci\u00f3: github.com/jkk-research/pointcloud_to_grid, https://github.com/ANYbotics/grid_map. Bizonyos DWA megold\u00e1sok ebbe csal\u00e1dba tartoznak.
  • Potential field alap\u00fa megold\u00e1sok: A potenci\u00e1lt\u00e9r alap\u00fa tervez\u00e9s (APF) sor\u00e1n a robotot vonz\u00f3 \u00e9s tasz\u00edt\u00f3 er\u0151kkel modellezik a k\u00f6rnyezetben l\u00e9v\u0151 objektumokt\u00f3l. A grid alap\u00fa m\u00f3dszerekkel ellent\u00e9tben itt maga a mez\u0151 mondja meg, hogy milyen t\u00e1vol ker\u00fclj\u00fcnk egy objektumot, m\u00edg a grid alapon a tervez\u0151 hat\u00e1rozza ezt meg. M\u00e1sik k\u00fcl\u00f6nbs\u00e9g, hogy a potenci\u00e1lt\u00e9r folytonos (nincs diszkretiz\u00e1l\u00e1s), m\u00edg a grid t\u00e9r diszkr\u00e9t. Tov\u00e1bbi inform\u00e1ci\u00f3: en.wikipedia.org/wiki/Motion_planning#Artificial_potential_fields, illetve itt is tal\u00e1lhat\u00f3 egy APF (artificial potential field) alap\u00fa megold\u00e1s.
  • Fren\u00e9t rendszer alap\u00fa megold\u00e1sok: A Fren\u00e9t-koordin\u00e1tarendszerben a robot \u00e1llapota k\u00e9t dimenzi\u00f3ban van megadva: a hosszanti \u00e9s a later\u00e1lis poz\u00edci\u00f3. A hosszanti tengelyen a robot aktu\u00e1lis helyzete \u00e9s sebess\u00e9ge tal\u00e1lhat\u00f3, m\u00edg a later\u00e1lis tengelyen a robot poz\u00edci\u00f3ja az \u00fatvonalhoz k\u00e9pest. Tov\u00e1bbi inform\u00e1ci\u00f3: roboticsknowledgebase.com/wiki/planning/frenet-frame-planning/

Megjegyz\u00e9s: TU M\u00fcnchen tananyaga hasonl\u00f3k\u00e9ppen, de m\u00e1s hangs\u00falyokkal osztja fel a lok\u00e1lis tervez\u0151 algoritmusokak: Graph-Based methods, Variational methods, Incremental Methods, Hybrid Methods.

M\u00f3dszerek Tulajdons\u00e1gok Korl\u00e1tok Inkrement\u00e1lis m\u00f3dszerek (pl. DWA) Val\u00f3sz\u00edn\u0171leg teljes A v\u00e9ges id\u0151n bel\u00fcli megold\u00e1s nem garant\u00e1lt Vari\u00e1ci\u00f3s m\u00f3dszerek (pl. APF) Nincs diszkretiz\u00e1l\u00e1s Helyi optimumot tal\u00e1l Alacsony sz\u00e1m\u00edt\u00e1si id\u0151 K\u00f6lts\u00e9gf\u00fcgg\u0151 solver Gr\u00e1f alap\u00fa m\u00f3dszerek (pl Lanelet2-alap\u00fa) Megtal\u00e1lja a glob\u00e1lis optimumot A dimenzionalit\u00e1s \u00e1tka Rugalmas k\u00f6lts\u00e9gf\u00fcggv\u00e9ny Diskretiz\u00e1lt megold\u00e1s Methods Properties Limitations Incremental Methods (eg. DWA) Probabilistically complete Solution in finite time not guaranteed Variational Methods (eg. APF) No discretization Finds local optimum Low computation time Cost dependent solver Graph-Based Methods (eg. pl Lanelet2-based) Finds global optimum Curse of dimensionality Flexible cost function Discretized solution"},{"location":"tervezes/#tervezesi-pelda","title":"Tervez\u00e9si p\u00e9lda","text":"

Az ebben a fejezetben szerepl\u0151 p\u00e9ld\u00e1t Werling \u00e9s mtsai. munk\u00e1j\u00e1b\u00f3l vett\u00fck [1]. Ez a p\u00e9lda egy \u00e1ltal\u00e1nos tervez\u00e9si probl\u00e9m\u00e1t mutat be, amely tartalmazza fenti szempontok legt\u00f6bbj\u00e9t. K\u00e9t fontos dologra h\u00edvjuk fel a figyelmet: - a kereszt- illetve hosszir\u00e1ny\u00fa tervez\u00e9si probl\u00e9m\u00e1t sz\u00e9tv\u00e1lasztjuk, illetve - a keresztir\u00e1ny\u00fa tervez\u00e9s az \u00fan. Fren\u00e9t-rendszerben t\u00f6rt\u00e9nik.

"},{"location":"tervezes/#keresztiranyu-tervezes","title":"Keresztir\u00e1ny\u00fa tervez\u00e9s","text":"

A keresztir\u00e1ny\u00fa tervez\u00e9s az \u00fatvonal g\u00f6rb\u00e9j\u00e9nek megtervez\u00e9s\u00e9t jelenti. El\u0151sz\u00f6r a Fren\u00e9t-rendszer fogalm\u00e1t vezetj\u00fck be. Az illuszt\u00e1rci\u00f3ja az 1. \u00e1br\u00e1n l\u00e1that\u00f3. A Fren\u00e9t-rendszer egy olyan koordin\u00e1tarendszer, amely egy tetsz\u0151leges g\u00f6rb\u00e9n (ez esetben pl. a s\u00e1vk\u00f6z\u00e9p, vagy a glob\u00e1lis trajekt\u00f3ria) fut v\u00e9gig az \\(\\(s(t)\\)\\) param\u00e9ter f\u00fcggv\u00e9ny\u00e9ben. A tetsz\u0151leges g\u00f6rb\u00e9t nevezz\u00fck referencia vonalnak. A Fren\u00e9t-rendszerben a referencia g\u00f6rbe koordin\u00e1t\u00e1ja csupa z\u00e9rus (\u00f6nmag\u00e1hoz k\u00e9pest vett elt\u00e9r\u00e9se nulla). Egy tervezett trajekt\u00f3ria pontjait ebben a koordin\u00e1tarendszerben \u00e9rtelmezve k\u00f6nny\u0171 kifejezni azt, ha a trajekt\u00f3ri\u00e1t egyel\u0151v\u00e9 szeretn\u00e9nk tenni a referencia g\u00f6rb\u00e9vel. Pl. ha egy tervezett trajekt\u00f3ri\u00e1t szeretn\u00e9nk, ha a referencia \u00fatvonalban v\u00e9gz\u0151dne, ebben az esetben a v\u00e9gpontja \\(\\([0; 0]\\)\\), a Fren\u00e9t-rendszerben. A nem z\u00e9rus t\u00e1vols\u00e1g a referencia vonalt\u00f3l vett t\u00e1vols\u00e1got adja meg. Pl. ha a s\u00e1vk\u00f6z\u00e9pet tekintj\u00fck referenci\u00e1nak, az ett\u0151l vett elt\u00e9r\u00e9s lett a Fren\u00e9t-rendszerben vett t\u00e1vols\u00e1g, amely egy j\u00f3 intuit\u00edv megk\u00f6zel\u00edt\u00e9s is, hiszen az ember maga is sokszor tekinti a s\u00e1v k\u00f6zep\u00e9t referenci\u00e1nak, az att\u00f3l val\u00f3 elt\u00e9r\u00e9st pedig m\u00e9rvad\u00f3 mennyis\u00e9gnek.

1. \u00c1bra: a Frenet frame illusztr\u00e1l\u00e1sa a tervezett trajekt\u00f3ria ment\u00e9n, forr\u00e1s: [1]

A kereszir\u00e1ny\u00fa tervez\u00e9s probl\u00e9m\u00e1j\u00e1t kiz\u00e1r\u00f3lag magas (>30-40kph) sebess\u00e9gekre vizsg\u00e1ljuk. Erre az esetre Werling \u00e9s mtsai. egy optimaliz\u00e1ci\u00f3s probl\u00e9mak\u00e9nt tekintenek. A l\u00e9nyeg, hogy a mindenkori \u00e1llapotban meghat\u00e1rozunk egy polinomot, amelynek a k\u00f6lts\u00e9ge a legkisebb. A k\u00f6lts\u00e9gek illetve s\u00falyok megv\u00e1laszt\u00e1s\u00e1val lehet k\u00fcl\u00f6nf\u00e9le trajekt\u00f3ri\u00e1kat megtervezni. A tervez\u00e9s k\u00e9t lehets\u00e9ges kimenetel\u00e9t a Fren\u00e9t-rendszerben a 2. \u00e1bra mutatja. Tegy\u00fck fel, hogy a szagatott vonal a s\u00e1v k\u00f6zepe, ez lesz a referencia vonal, vagyis a glob\u00e1lis trajekt\u00f3ria. A vastag vonal a lok\u00e1lisan tervezett trajekt\u00f3ria, aminek a c\u00e9lja, hogy r\u00e1vezesse a j\u00e1rm\u0171vet a glob\u00e1lis trajekt\u00f3ri\u00e1ra. A kezd\u0151pont lehet egy tetsz\u0151legesen v\u00e1lasztott pont (pl. a j\u00e1rm\u0171 poz\u00edci\u00f3ja, vagy a legut\u00f3bbi \u00e9rv\u00e9nyes lok\u00e1lis trajekt\u00f3ria utols\u00f3 pontja...stb.). A v\u00edzszintes ir\u00e1ny testes\u00edti meg a f\u00fcggetlen v\u00e1ltoz\u00f3t. Ennek \u00e9rt\u00e9ke 0 \u00e9s egy maxim\u00e1lis \u00e9rt\u00e9k k\u00f6z\u00f6tt v\u00e1ltozik, ezt a tartom\u00e1nyt tekinthetj\u00fck a g\u00f6rb\u00e9t le\u00edr\u00f3 egyenlet \u00e9rtelmez\u00e9si tartom\u00e1ny\u00e1nak. Mi sz\u00e1munkra a fontos a g\u00f6rbe megtervez\u00e9s\u00e9n\u00e9l? Egyr\u00e9szt, hogy a kezd\u0151pontban kezd\u0151dj\u00f6n \u00e9s a v\u00e9gpontban \u00e9rjen v\u00e9get (meglep\u0151 m\u00f3don). Emellett felt\u00e9telk\u00e9nt kezelhetj\u00fck azt is, hogy a kezdeti is v\u00e9gorient\u00e1ci\u00f3 legyen egy adott \u00e9rt\u00e9k (pl. a kezdeti orient\u00e1ci\u00f3 egyezzen meg a j\u00e1rm\u0171 orient\u00e1ci\u00f3j\u00e1val, a v\u00e9gorient\u00e1ci\u00f3 a referencia vonal orient\u00e1ci\u00f3j\u00e1val). A kezdeti \u00e9s v\u00e9gfelt\u00e9teleket nevezz\u00fck peremfelt\u00e9teleknek. Sz\u00fcks\u00e9g eset\u00e9n tov\u00e1bbi peremfelt\u00e9teleket szabhatunk meg.

2. \u00c1bra: tervez\u00e9s lehets\u00e9ges kimenetei a Fren\u00e9t-rendszerben, forr\u00e1s: [1]

A polinom illeszt\u00e9s sor\u00e1n olyan polinomokat keres\u00fcnk, amelyek kiel\u00e9g\u00edtek a peremfelt\u00e9teleket. A 2. \u00e1br\u00e1n l\u00e1thatjuk, hogy egyszerre t\u00f6bb polinom is kiel\u00e9g\u00edtheti ezeket a felt\u00e9teleket. A 3. \u00e1bra ilyen lehets\u00e9ges polinomokat mutat. L\u00e1that\u00f3, hogy nem mindegyik g\u00f6rbe \u00e9ri el ugyanott a referencia vonalat (a v\u00edzszintes tengelyt), teh\u00e1t a hossz f\u00fcggv\u00e9ny\u00e9ben k\u00fcl\u00f6nb\u00f6ztethet\u00fcnk m\u00e1s-m\u00e1s alak\u00fa g\u00f6rb\u00e9ket. Ezek mindegyike kiel\u00e9g\u00edti a peremfelt\u00e9teleket, ugyanakkor m\u00e1s alakjuk miatt ezen v\u00e9gigvezetve az aut\u00f3t m\u00e1s kinematikai tulajdons\u00e1gokat fognak eredm\u00e9nyezni. Ahhoz, hogy eld\u00f6nts\u00fck, melyik a sz\u00e1munkra legjobb g\u00f6rbe, bevezetj\u00fck az \u00fan. k\u00f6lts\u00e9gf\u00fcggv\u00e9nyt. A k\u00f6lts\u00e9gf\u00fcggv\u00e9ny egy olyan f\u00fcggv\u00e9ny, amely szabadon v\u00e1lasztott szempontjaink szerint eld\u00f6nti, hogy az adott szempont szerint mennyire j\u00f3 az adott g\u00f6rbe. A k\u00f6lts\u00e9geket \u00f6sszegezz\u00fck. Azonban nem mindegyik szempont egyform\u00e1n fontos, \u00edgy a k\u00f6lts\u00e9ge sem egyform\u00e1n relev\u00e1ns. \u00cdgy s\u00falyokat haszn\u00e1lunk hogy eld\u00f6nts\u00fck, melyek a legjelent\u0151sebb, \u00e9s melyek a legkev\u00e9sb\u00e9 \u00e9rdekes szempontok. Az \u00f6sszes lehets\u00e9ges g\u00f6rb\u00e9re meghat\u00e1rozzuk az \u00f6sszk\u00f6lts\u00e9get, majd kiv\u00e1lasztjuk a legkisebb k\u00f6lts\u00e9g\u0171 g\u00f6rb\u00e9t. Ez lesz a v\u00e9gs\u0151 trajekt\u00f3ri\u00e1nk, amely \u00edgy a probl\u00e9ma optim\u00e1lis megold\u00e1sa (optim\u00e1lis, azaz nem nulla k\u00f6lts\u00e9g\u0171, de a k\u00f6r\u00fclm\u00e9nyeket figyelembe v\u00e9ve a legkisebb k\u00f6lts\u00e9g\u0171 megold\u00e1s). A folyamatot optimaliz\u00e1ci\u00f3nak, a trajekt\u00f3ria hossz\u00e1t az optimaliz\u00e1ci\u00f3 v\u00e1ltoz\u00f3j\u00e1nak nevezz\u00fck.

3. \u00c1bra: tervez\u00e9s lehets\u00e9ges kimenetei a Fren\u00e9t-rendszerben, forr\u00e1s: [1]

Az, hogy mit tekint\u00fcnk optim\u00e1lisnak, a k\u00f6lts\u00e9gf\u00fcggv\u00e9nyt\u0151l f\u00fcgg. Ebben \u00e1ltal\u00e1ban egym\u00e1snak ellentmond\u00f3 tagok szerepelnek: a trajekt\u00f3ria hossza legyen min\u00e9l kisebb (min\u00e9l gyorsabban \u00e9rj\u00fck el a c\u00e9lt), de a kialakul\u00f3 oldalir\u00e1ny\u00fa j\u00e1rm\u0171gyorsul\u00e1s legyen min\u00e9l kisebb (komfort felt\u00e9tel). Ezek egym\u00e1snak ellentmondanak, \u00edgy egy k\u00f6ztes j\u00f3, azaz optim\u00e1lis trajekt\u00f3ria fog sz\u00fcletni. Tov\u00e1bbi k\u00f6lts\u00e9geket vezethet\u00fcnk be, pl. a t\u00fallend\u00fcl\u00e9s m\u00e9rt\u00e9ke (a s\u00e1v m\u00e1sik oldal\u00e1ra val\u00f3 \u00e1tt\u00e9r\u00e9s m\u00e9rt\u00e9ke), a kezdeti r\u00e1nt\u00e1s, a be\u00e1ll\u00e1s gyorsas\u00e1ga stb. A s\u00falyok v\u00e1ltoztat\u00e1s\u00e1val m\u00e1s-m\u00e1s preferenci\u00e1t val\u00f3s\u00edthatunk meg. Pl. agressz\u00edv man\u0151ver vagy k\u00e9nyelmes man\u0151ver. Ezen k\u00edv\u00fcl kiz\u00e1rjuk azokat a trajekt\u00f3ri\u00e1kat, amelyek nem felelnek meg a biztons\u00e1gi k\u00f6vetelm\u00e9nyeknek, pl. \u00e1tt\u00e9rnek a m\u00e1sik s\u00e1vba.

Werling \u00e9s mtsai. \u00f6t\u00f6dfok\u00fa polinomot hat\u00e1roztak meg, ez \u00edrja le a g\u00f6rb\u00e9t. A Fren\u00e9t-rendszerben \u00edgy a g\u00f6rbe egyenlete:

\\[ x(s) = c_{0} + c_{1}s + c_{2}s^{2}+c_{3}s^{3}+c_{4}s^{4}+c_{5}s^{5} \\]

L\u00e1thatjuk, hogy a g\u00f6rb\u00e9t 6 db param\u00e9ter adja meg, a 6 egy\u00fctthat\u00f3 c0-t\u00f3l c5-ig. Ahhoz, hogy az \u00f6sszes egy\u00fctthat\u00f3t meg tudjuk hat\u00e1rozni, 6 peremfelt\u00e9telre van sz\u00fcks\u00e9g\u00fcnk: - a kezdeti \u00e9s v\u00e9gpont elt\u00e9r\u00e9se a referencia vonalt\u00f3l, - a kezdeti \u00e9s v\u00e9gpont orient\u00e1ci\u00f3j\u00e1nak elt\u00e9s\u00e9re a referencia vonalt\u00f3l, - illetve a kezdeti \u00e9s v\u00e9gpontban a tervezett trajekt\u00f3ria g\u00f6rb\u00fclete.

Ezeket vektoros form\u00e1ba rendezve: $$ [d_{0}\\ d_{1}\\ \\theta_{0}\\ \\theta_{1}\\ \\kappa_{0}\\ \\kappa_{1}]$$

Ezeket tetsz\u0151legesen megv\u00e1laszthatjuk. A fenti magyar\u00e1zat alapj\u00e1n legyen: \\(\\([d_{0}\\ d_{1}\\ \\theta_{0}\\ \\theta_{1}\\ \\kappa_{0}\\ \\kappa_{1}]=[d_{0}\\ 0\\ \\theta_{0}\\ 0\\ 0\\ 0]\\)\\) azaz a kezdeti pontban a j\u00e1rm\u0171 helyzete a referenciavonalt\u00f3l, a v\u00e9gpontban a referencia vonal, a g\u00f6rb\u00fcletek pedig null\u00e1k, azaz a referencia vonal g\u00f6rb\u00fcletei a kezdeti \u00e9s v\u00e9gpontban. A peremfelt\u00e9telek seg\u00edts\u00e9g\u00e9vel fel\u00edrhat\u00f3 egy 6 ismeretlent \u00e9s 6 egyenletet tartalmaz\u00f3 egyenletrendszer: $$ x(s=0) = c_{0} = d_{0}$$ $$ x'(s=0) = c_{1} = \\theta_{1}$$ $$ x''(s=0) = 2c_{2} = \\kappa_{1}$$ $$ x(s=s_{1}) = c_{0} + c_{1}s + c_{2}s_{1}^{2}+c_{3}s_{1}^{3}+c_{4}s_{1}^{4}+c_{5}s_{1}^{5} $$ $$ x'(s=s_{1}) = c_{1}s + 2c_{2}s_{1}+3c_{3}s_{1}^{2}+4c_{4}s_{1}^{3}+5c_{5}s_{1}^{4} $$ $$ x''(s=s_{1}) = 2c_{2}+6c_{3}s_{1}+12c_{4}s_{1}^{2}+20c_{5}s_{1}^{3} $$

ahol \\(s_{1}\\) a v\u00e9gpont t\u00e1vols\u00e1ga. Ez lesz a fenti optimaliz\u00e1ci\u00f3s probl\u00e9ma v\u00e1ltoz\u00f3ja. Ezt a mennyis\u00e9get tetsz\u0151leges tartom\u00e1nyon vari\u00e1lva (pl. \\(s_{1,max}\\) \u00e9s \\(s_{1,min}\\) k\u00f6z\u00f6tt) keress\u00fck azt az egy\u00fctthat\u00f3 halmazt, amelyre \\(\\(J\\)\\) k\u00f6lts\u00e9gf\u00fcggv\u00e9ny a legkisebb. Hogyan v\u00e1lasszuk meg a \\(J\\) f\u00fcggv\u00e9nyt? Erre Werling \u00e9s mtsai. a k\u00f6vetkez\u0151 formul\u00e1t aj\u00e1nlj\u00e1k:

\\[ C_{d} = k_{j}J_{t}(d(t)) + k_{t}T + k_{d}(d_{1})^{2} \\]

Ahol \\(T = \\dfrac{s_{1}}{v_{x}}\\) a trajekt\u00f3ria hossza id\u0151ben kifejezve, \\(J_{t}\\) az \u00fan. jerk (magyarul r\u00e1nt\u00e1s) az oldalir\u00e1ny\u00fa gyorsul\u00e1s deriv\u00e1ltja, \\(d_{1}\\) a v\u00e9gs\u0151 pontban a t\u00e1vols\u00e1g a referencia vonalt\u00f3l. Mi ezt \\(d_{1}=0\\) \u00e9rt\u00e9kre v\u00e1lasztottuk, \u00edgy ez a tag kiesik.

"},{"location":"tervezes/#hossziranyu-tervezes","title":"Hosszir\u00e1ny\u00fa tervez\u00e9s","text":"

A hosszir\u00e1ny\u00fa tervez\u00e9s hasonl\u00f3an m\u0171k\u00f6dhet, mint a keresztir\u00e1ny\u00fa. Ebben az esetben a glob\u00e1lis trajekt\u00f3ria felfoghat\u00f3 \u00fagy, mint c\u00e9lsebess\u00e9gek sorozata az \u00fatvonal ment\u00e9n. Ezzel szemben a lok\u00e1lis trajekt\u00f3ria a helyi viszonyoknak megfelel\u0151 t\u00e9nyleges sebess\u00e9g megtervez\u00e9se. Figyelembe vessz\u00fck m\u00e1sik objektumok mozg\u00e1s\u00e1t, a c\u00e9l j\u00e1rm\u0171kinetik\u00e1t, a sebess\u00e9ghat\u00e1rokat...stb. Ennek szeml\u00e9ltet\u00e9se l\u00e1that\u00f3 a 4. \u00e1br\u00e1n. L\u00e1that\u00f3, hogy norm\u00e1l esetben a maxim\u00e1lis sebess\u00e9get tartjuk. Amikor pl. utol\u00e9r\u00fcnk egy m\u00e1sik j\u00e1rm\u0171vet ami el\u0151tt\u00fcnk halad, f\u00e9kez\u00fcnk, \u00e9s felvessz\u00fck ennek a j\u00e1rm\u0171nek a sebess\u00e9g\u00e9t. A f\u00e9kez\u00e9s sor\u00e1n olyan sebess\u00e9gprofilt tervez\u00fcnk, hogy biztosan kell\u0151 t\u00e1vols\u00e1got tudjunk tartani a m\u00e1sik j\u00e1rm\u0171t\u0151l, ne f\u00e9kezz\u00fcnk hirtelen de ne is t\u00fal hamar. Majd a m\u00e1sik j\u00e1rm\u0171vet \u00fagy k\u00f6vetj\u00fck, hogy ezt a t\u00e1vols\u00e1got (bizonyos hat\u00e1ron bel\u00fcl) tartsuk. Amikor enn\u00e9l is lassabb j\u00e1rm\u0171vet l\u00e1tunk (pl. biciklis) tov\u00e1bb cs\u00f6kkentj\u00fck a sebess\u00e9get, ha ez az akad\u00e1ly elt\u0171nt el\u0151l\u00fcnk, visszagyors\u00edtunk a megengedett sebess\u00e9gre. Mindig figyelembe vessz\u00fck a saj\u00e1t gyors\u00edt\u00e1si \u00e9s lass\u00edt\u00e1si preferenci\u00e1nkiat.

4. \u00c1bra: lok\u00e1lis sebess\u00e9gtrajekt\u00f3ria szeml\u00e9ltet\u00e9se

L\u00e1that\u00f3, hogy a keresztir\u00e1ny\u00fa tervez\u00e9shez hasonl\u00f3 felt\u00e9telek k\u00f6z\u00f6tt kell a lehet\u0151 legjobb profilt megtervezni. Ez szint\u00e9n egy optimaliz\u00e1ci\u00f3s probl\u00e9ma. Werling \u00e9s mtsai. ebben az eseben is egy \u00f6t\u00f6dfok\u00fa polinomot aj\u00e1nlanak a c\u00e9lsebess\u00e9g f\u00fcggv\u00e9ny\u00e9re, azaz:

\\[ v(s(t)) = c_{0} + c_{1}s + c_{2}s^2+c_3s^3+c_4s^4+c_5s^5 \\]

A mechanizmus ugyanaz: 6 peremfelt\u00e9telt fogalmazunk meg \u00e9s ezek seg\u00edts\u00e9g\u00e9vel trajekt\u00f3ri\u00e1kat tervez\u00fcnk. A legkisebb k\u00f6lts\u00e9g\u0171t v\u00e1lasztjuk ki. M\u00e1sik j\u00e1rm\u0171 k\u00f6vet\u00e9se eset\u00e9ben a v\u00e9gfelt\u00e9telek a k\u00f6vetkez\u0151k:

\\[ [s_1\\ \\dot{s_1}\\ \\ddot{s_1}\\ T] = [(s_{target}(T_j)+\\delta s_i),\\ \\dot{s}_{target}(T_j),\\ {\\ddot{s}}_{target}(T_j),\\ T_j] \\]

A kezdeti felt\u00e9telek pedig:

\\[ [s_0\\ \\dot{s_0}\\ \\ddot{s_0}\\ T] = [s_{target}(0),\\ \\dot{s}_{ego}(0),\\ {\\ddot{s}}_{ego}(0),\\ 0] \\]

Azaz a kezdeti felt\u00e9telek adottak az objektum t\u00e1vols\u00e1g\u00e1b\u00f3l, illetve a saj\u00e1t j\u00e1rm\u0171v\u00fcnk sebess\u00e9g\u00e9b\u0151l \u00e9s gyorsul\u00e1s\u00e1b\u00f3l. Egy ilyen tervez\u00e9si ciklus \u00f6sszes trajekt\u00f3ri\u00e1ja az 5. \u00e1br\u00e1n l\u00e1that\u00f3. A feket\u00e9k az \u00e9rv\u00e9nyes trajekt\u00f3ri\u00e1k, a sz\u00fcrk\u00e9k az \u00e9rv\u00e9nytelenek (pl. t\u00fal nagy gyorsul\u00e1s), a k\u00e9k az objektum mozg\u00e1sa, a z\u00f6ld az optim\u00e1lis trajekt\u00f3ria. A k\u00f6lts\u00e9g f\u00fcggv\u00e9ny lehet a k\u00f6vetkez\u0151:

\\[ C_t = k_jJ_t + k_tT+k_s[s_1-s_d]^2 \\]

Ahol \\(J_t\\) a trajekt\u00f3ria befut\u00e1sa sor\u00e1n tapasztalt \u00e1tlagos jerk (azaz r\u00e1nt\u00e1s), \\(T\\) a trajekt\u00f3ria hossza id\u0151ben \\(s_1-s_d\\) a trajekt\u00f3ria v\u00e9g\u00e9n a t\u00e1vols\u00e1g az objektumt\u00f3l. A \\(k\\) t\u00e9nyez\u0151k a s\u00falyok.

5. \u00c1bra: sebess\u00e9gtrajekt\u00f3ria tervez\u00e9se, forr\u00e1s: [1]

"},{"location":"tervezes/#ros-2-megoldasok","title":"ROS 2 megold\u00e1sok","text":""},{"location":"tervezes/#nav2","title":"Nav2","text":"

A Nav2 az ROS Navigation Stack t\u00e1mogatott szellemi ut\u00f3dja, amely ugyanazt a technol\u00f3gi\u00e1t alkalmazza, amely p\u00e9ld\u00e1ul a mobil robotik\u00e1ra, auton\u00f3m j\u00e1rm\u0171vekre alkalmazhat\u00f3, optimaliz\u00e1lt \u00e9s \u00e1tdolgozott megold\u00e1sok gy\u0171jtem\u00e9nye. A Nav2 projekt arra t\u00f6rekszik, hogy megtal\u00e1lja a biztons\u00e1gos m\u00f3dot arra, hogy egy mobil robot bonyolult feladatokat hajtson v\u00e9gre sokf\u00e9le k\u00f6rnyezeten \u00e9s robotkinematikai oszt\u00e1lyon kereszt\u00fcl. Nemcsak mozoghat A pontb\u00f3l B pontba, de lehetnek k\u00f6zbens\u0151 p\u00f3zok (poz\u00edci\u00f3 + orient\u00e1ci\u00f3) is, \u00e9s m\u00e1s t\u00edpus\u00fa feladatokat is k\u00e9pviselhet, p\u00e9ld\u00e1ul objektumk\u00f6vet\u00e9st, teljes lefedetts\u00e9g-navig\u00e1ci\u00f3t stb. A Nav2 egy gy\u00e1rt\u00e1si szint\u0171 \u00e9s j\u00f3 min\u0151s\u00e9g\u0171 navig\u00e1ci\u00f3s keretrendszer, amelyben vil\u00e1gszerte t\u00f6bb mint 50 v\u00e1llalat b\u00edzik meg.

A Nav2 architekt\u00fara \u00e1ttekint\u00e9se:

"},{"location":"tervezes/#autoware-tervezo","title":"Autoware tervez\u0151","text":"

Szint\u00e9n ROS 2 t\u00e1mogatott az Autoware keretrendszer tervez\u0151 (planning) komponense. Az Autoware tervez\u00e9s komponens f\u0151 funkci\u00f3ja, hogy l\u00e9trehozza azt a trajekt\u00f3ri\u00e1t, amelyre a Szab\u00e1lyz\u00e1s (control) komponens feliratkozik a Lokaliz\u00e1ci\u00f3 (Localization) \u00e9s az \u00c9szlel\u00e9s (Perception) komponensekb\u0151l kapott k\u00f6rnyezeti \u00e1llapot alapj\u00e1n.

"},{"location":"tervezes/#irodalomjegyzek","title":"Irodalomjegyz\u00e9k","text":"
  • [1] Moritz Werling, Julius Ziegler, S\u00f6ren Kammel, and Sebastian Thrun: Optimal Trajectory Generation for Dynamic Street Scenarios in a Fren\u00e9t Frame, 2010 IEEE International Conference on Robotics and Automation, Anchorage Convention District, May 3-8, 2010, Anchorage, Alaska, USA, pp. 987-993
  • [2] github.com/ai-winter/ros_motion_planning: ROS 1, de tervezetten ROS 2 Glob\u00e1lis tervez\u0151k: Dijkstra, A-star, D-star, RRT, Informed-RRT, GBFS Lok\u00e1lis tervez\u0151k: LQR (Linear\u2013quadratic regulator), DWA (Dynamic Window Approach), APF, RPP, TEB (Timed Elastic Band)
"},{"location":"tervezes/#tovabbi-cikkek","title":"Tov\u00e1bbi cikkek","text":"

A bemutatott algoritmusokhoz tartoz\u00f3 cikkek \u00e9s python_motion_planning repository-b\u00f3l kigy\u0171jt\u00f6tt cikkek gy\u0171tem\u00e9nye:

"},{"location":"tervezes/#globalis-tervezok","title":"Glob\u00e1lis tervez\u0151k","text":"
  • A* - A-star: A Formal Basis for the heuristic Determination of Minimum Cost Paths
  • Modified A-Star: Efficient and optimal penetration path planning for stealth unmanned aerial vehicle using minimal radar cross-section tactics and modified A-Star algorithm
  • Lifelong Planning A*: Lifelong Planning A*
  • D* - D-star: Optimal and Efficient Path Planning for Partially-Known Environments
  • D* Lite: D* Lite
  • JPS: Online Graph Pruning for Pathfinding On Grid Maps
  • Theta*: Theta*: Any-Angle Path Planning on Grids
  • Lazy Theta*: Lazy Theta*: Any-Angle Path Planning and Path Length Analysis in 3D
  • S-Theta*: S-Theta*: low steering path-planning algorithm
  • RRT: Rapidly-Exploring Random Trees: A New Tool for Path Planning
  • RRT-Connect: RRT-Connect: An Efficient Approach to Single-Query Path Planning
  • RRT*: Sampling-based algorithms for optimal motion planning
  • Informed RRT*: Optimal Sampling-based Path Planning Focused via Direct Sampling of an Admissible Ellipsoidal heuristic
  • ACO: Ant Colony Optimization: A New Meta-Heuristic
"},{"location":"tervezes/#lokalis-tervezok","title":"Lok\u00e1lis tervez\u0151k","text":"
  • DWA: The Dynamic Window Approach to Collision Avoidance
  • APF:Real-time obstacle avoidance for manipulators and mobile robots
  • RPP:Regulated Pure Pursuit for Robot Path Tracking
"},{"location":"tervezes/planning_control_diagram/","title":"Planning control diagram","text":"
flowchart LR\n\nGP1[Global planning\n  Inputs:\n  - Driver/User selection\n  -Mapdata\n  Output:\n  -Routeplan\n  Goal: to plan a global \n  route which leads from A\n  to B, considering e.g., \n  trafficdata,fuel\n  consumption\u2026 etc.]:::light \nGP2[I want to get \n  from address A \n  to address B \n  with a robotaxi]:::dark\n\nBP1[Behavior planning\n    Inputs:\n    -Route plan\n    -Perception info of\n    the surroundings\n    Output:\n    -Behavior strategy \n    Goal: \n    plan how the \n    vehicle should \n    behave in terms of \n    decisions and motion \n    characteristics\n]:::light \n\nBP2[I want to follow the\nmiddle lane then\n change to the inner\n lane smoothly]:::dark\n\nLP1[\n    Local planning\n    Inputs:\n    -Behavior strategy\n    -Planning constraints\n    Output:\n    -Local trajectory\n    Goal: plan a \n    kinematicly feasible,\n    safe and preferred\n    trajectory]:::light \nLP2[I plan a trajectory\nwithin the lane to be\nsafe and then a\nsmooth trajectory to\nthe inner lane]:::dark\n\n\nVC1[ Vehicle Control \n    High level control\n    Inputs:\n    -Local trajectory\n    -Vehicle state variables\n    -Localization info \n    Outputs:\n    -Vehicle level target \n    quantities\n    -Control constraints \n    Goal: calculate the\n    vehicle target state to \n    be controlled by the\n    low level controllers]:::light \nVC2[ I calculate the\n necessary speed and \n yaw rate of the \n vehicle to follow the \n local trajectory]:::dark\n\n\nAC1[ Actuator Control\nLow  level control\nInputs:\n-Vehicle level target \nquantities\n-Control constraints\n-Actuator state variables\nOutput:\n-Actuator target states \nGoal: realize vehicle \nmotion through \ncontrolling the \nactuators]:::light \nAC2[ I calculate the \nnecessary engine \ntorque and steering\nangle to realize the \nplanned motion\u2019]:::dark\n\n\nsubgraph Plan [Planning]\n  GP1\n  BP1\n  LP1\nend\nsubgraph Control [Control]\n  VC1\n  AC1\nend\nGP1-->BP1-->LP1-->VC1-->AC1\nGP2-.-BP2-.-LP2-.-VC2-.-AC2\n\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff\n
"},{"location":"tervezes/practice/","title":"1. feladat","text":"

Ebben a feladatban az elm\u00e9leti \u00f3r\u00e1n bemutatott polinom alap\u00fa lok\u00e1lis tervez\u0151 megval\u00f3s\u00edt\u00e1s\u00e1t fogjuk bemutatni. Ehhez els\u0151k\u00e9nt friss\u00edts\u00fck az arj_packages repository-t!

"},{"location":"tervezes/practice/#clone-es-build","title":"Clone \u00e9s build","text":"

cd ~/ros2_ws/src/arj_packages/\n
git pull\n
Ezek ut\u00e1n buildelj\u00fck az arj_local_planner nev\u0171 package-t!

cd ~/ros2_ws\n
colcon build --packages-select arj_local_planner\n

"},{"location":"tervezes/practice/#futtatas","title":"Futtat\u00e1s","text":"

Ezek ut\u00e1n futtassuk a planner-t a launch f\u00e1jl seg\u00edts\u00e9g\u00e9vel, source-ol\u00e1s ut\u00e1n.

source ~/ros2_ws/install/setup.bash\n
ros2 launch arj_local_planner run_all.launch.py\n

N\u00e9zz\u00fck meg, milyen topicok j\u00f6ttek l\u00e9tre (\u00faj termin\u00e1lban)!

ros2 topic list\n

L\u00e9trej\u00f6tt a /goal_pose topic illetve a /planner/trajectory topic. A goal_pose az a c\u00e9lpoz\u00edci\u00f3, amelyre a tervez\u0151 tervez, a planner/trajectory pedig a waypoint list, maga a tervezett trajekt\u00f3ria. Ind\u00edts\u00fcnk egy rviz-t!

ros2 run rviz2 rviz2\n

V\u00e1lasszuk ki a map frame-t, illetve adjuk hozz\u00e1 a /planner/trajectory topicot. Ezek ut\u00e1n a fenti s\u00e1vb\u00f3l a 2D Goal Pose opci\u00f3t haszn\u00e1lva vegy\u00fcnk fel egy goal pose-t a griden \u00fagy, hogy az a pozit\u00edv koordin\u00e1t\u00e1k ir\u00e1ny\u00e1ban helyezkedjen el! Ekkor a tervez\u0151 automatikusan r\u00e1illeszt egy polinomot a c\u00e9lpoz\u00edci\u00f3ra.

Ezt az egyszer\u0171 tervez\u0151t haszn\u00e1lhatjuk pl. mozg\u00f3 c\u00e9lpontra (m\u00e1sik j\u00e1rm\u0171, s\u00e1v k\u00f6zepe, glob\u00e1lis trajekt\u00f3ria egy pontja...stb) illetve statikus c\u00e9lpontra (pl. parkol\u00f3hely).

"},{"location":"tervezes/practice/#2-feladat","title":"2. feladat","text":"

A m\u00e1sodik feladat a ROS 2 Navigation stack-j\u00e9nek be\u00fczemel\u00e9se szimul\u00e1torban, \u00fcres p\u00e1ly\u00e1n. R\u00e9szletes dokument\u00e1ci\u00f3 a navigation.ros.org oldalon.

"},{"location":"tervezes/practice/#clone-es-build_1","title":"Clone \u00e9s build","text":"

cd ~/ros2_ws/src\n
git clone https://github.com/rosblox/nav2_outdoor_example\n

cd ~/ros2_ws\n
rosdep install -y --from-paths src --ignore-src --rosdistro $ROS_DISTRO\n

cd ~/ros2_ws\n
colcon build --packages-select nav2_outdoor_example\n

"},{"location":"tervezes/practice/#futtatas_1","title":"Futtat\u00e1s","text":"

source ~/ros2_ws/install/setup.bash\n
ros2 launch nav2_outdoor_example bringup.launch.py\n

"},{"location":"tervezes/practice/#3-feladat","title":"3. feladat","text":"

A harmadik feladat a ROS 2 Navigation stack-j\u00e9nek be\u00fczemel\u00e9se szimul\u00e1torban, a turlebot egyik p\u00e1ly\u00e1j\u00e1n. R\u00e9szletes dokument\u00e1ci\u00f3 a navigation.ros.org oldalon.

Vide\u00f3 direkt link

Megjegyz\u00e9s: el\u0151fordulhat, hogy az ign_ros_control package m\u00e1sik feladatban is buildelt package, ha ez m\u00e1r l\u00e9tezik, akkor a build / apt install kihagyhat\u00f3. A helyek, ahol ez lehets\u00e9ges, hogy megtal\u00e1lhat\u00f3:

ros2_ws/src/gz_ros2_control/ign_ros2_control\nros2_ws/src/navigation2_ignition_gazebo_example/src/gz_ros2_control/ign_ros2_control\n/opt/ros/humble/share/ign_ros2_control\n

"},{"location":"tervezes/practice/#clone-es-build_2","title":"Clone \u00e9s build","text":"
sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup ros-humble-turtlebot3-gazebo\n

cd ~/ros2_ws/src\n
git clone https://github.com/ros-controls/gz_ros2_control\n
git clone https://github.com/art-e-fact/navigation2_ignition_gazebo_example\n
cd ~/ros2_ws/src/gz_ros2_control\n
git checkout humble\n
cd ~/ros2_ws\n
rosdep install -y --from-paths src --ignore-src --rosdistro humble\n

cd ~/ros2_ws\n
colcon build --packages-select sam_bot_nav2_gz\n

"},{"location":"tervezes/practice/#futtatas_2","title":"Futtat\u00e1s","text":"

Gazebo, RViz2 \u00e9s Navigation2

source ~/ros2_ws/install/setup.bash\n
ros2 launch sam_bot_nav2_gz complete_navigation.launch.py\n

C\u00e9lpont kijel\u00f6l\u00e9se RViz2-ben:

source ~/ros2_ws/install/setup.bash\n
ros2 run sam_bot_nav2_gz follow_waypoints.py\n
source ~/ros2_ws/install/setup.bash\n
ros2 run sam_bot_nav2_gz reach_goal.py\n

"},{"location":"tervezes/practice/#navigacio","title":"Navig\u00e1ci\u00f3","text":""},{"location":"tervezes/practice/#sources","title":"Sources","text":"
  • navigation.ros.org/getting_started/index.html
  • navigation.ros.org
  • github.com/ros-controls/gz_ros2_control
  • github.com/art-e-fact/navigation2_ignition_gazebo_example
"},{"location":"transzformaciok/","title":"Elm\u00e9let - Transzform\u00e1ci\u00f3k","text":""},{"location":"transzformaciok/#ellenorzo-kerdesek","title":"Ellen\u0151rz\u0151 k\u00e9rd\u00e9sek","text":"
  • Mik a launch f\u00e1jlok \u00e9s mire haszn\u00e1ljuk \u0151ket?
  • Milyen nyelven \u00edrjuk a launch f\u00e1jlokat?
  • Mit jelen\u00edt meg az rqt_tf_tree, az rviz \u00e9s az rqt_graph?
  • Mit \u00e9rt\u00fcnk pose (vagy p\u00f3z / helyzet) alatt? (robotik\u00e1ban)
"},{"location":"transzformaciok/#bevezetes","title":"Bevezet\u00e9s","text":"

ROS-ben (\u00e9s \u00e1latal\u00e1ban robotik\u00e1ban) a transformok hat\u00e1rozz\u00e1k meg a hogy, mi merre tal\u00e1lhat\u00f3 az adott vonatkozat\u00e1si pontt\u00f3l (frame). T\u00f6bb transzform le\u00edrhatja p\u00e9ld\u00e1ul egy robotkar mozg\u00e1s\u00e1t vagy \u00e9pp egy j\u00e1rm\u0171 \u00e9s szenzorai helyzet\u00e9t a t\u00e9rben.

"},{"location":"transzformaciok/#merev-test-mozgasa","title":"Merev test mozg\u00e1sa","text":"

Merevnek tekinthet\u0151 az a test, mely pontjainak t\u00e1vols\u00e1ga mozg\u00e1s sor\u00e1n nem v\u00e1ltozik, vagyis b\u00e1rmely k\u00e9t pontj\u00e1nak t\u00e1vols\u00e1ga id\u0151ben \u00e1lland\u00f3.

  • Merev test alakja, t\u00e9rfogata \u00e1lland\u00f3.
  • Merev test t\u00e9rbeli helyzete megadhat\u00f3 b\u00e1rmely 3 nem egy egyenesbe es\u0151 pontj\u00e1nak helyzet\u00e9vel.
  • A test helyzet\u00e9t szeml\u00e9letesebben megadhatjuk egy tetsz\u0151leges pontj\u00e1nak 3 koordin\u00e1t\u00e1j\u00e1val (poz\u00edci\u00f3) \u00e9s a test orient\u00e1ci\u00f3j\u00e1val.
  • Merev testek mozg\u00e1sai k\u00e9t elemi mozg\u00e1sfajt\u00e1b\u00f3l tev\u0151dnek \u00f6ssze: halad\u00f3 mozg\u00e1s (transzl\u00e1ci\u00f3) \u00e9s tengely k\u00f6r\u00fcli forg\u00e1s (rot\u00e1ci\u00f3)
  • Transzl\u00e1ci\u00f3s mozg\u00e1s sor\u00e1n a test minden pontja egym\u00e1ssal p\u00e1rhuzamos, egybev\u00e1g\u00f3 p\u00e1ly\u00e1t \u00edr le, a test orient\u00e1ci\u00f3ja pedig nem v\u00e1ltozik.
  • Rot\u00e1ci\u00f3 sor\u00e1n a forg\u00e1stengelyen l\u00e9v\u0151 pontok poz\u00edci\u00f3ja nem v\u00e1ltozik, a test t\u00f6bbi pontja pedig a forg\u00e1stengelyre mer\u0151leges s\u00edkokban k\u00f6rp\u00e1ly\u00e1n mozog.

Rot\u00e1ci\u00f3 szeml\u00e9ltet\u00e9se Forr\u00e1s: University of Illinois

Az al\u00e1bbiakban egy r\u00f6vid (~9 perc), de hasznos vide\u00f3 l\u00e1that\u00f3 a t\u00e9m\u00e1r\u00f3l:

"},{"location":"transzformaciok/#transzformaciok","title":"Transzform\u00e1ci\u00f3k","text":"

A pose (p\u00f3z) a poz\u00edci\u00f3 (elhelyezked\u00e9s) \u00e9s orient\u00e1ci\u00f3 (ir\u00e1ny) \u00f6sszess\u00e9ge. Amennyiben egy t\u00e9rbeli pose-t transzform\u00e1lunk (mozgatunk \u00e9s forgatunk) egy m\u00e1sik pose keletkezik. Ez a k\u00e9t pose egym\u00e1shoz k\u00e9pest k\u00e9t transzform\u00e1ci\u00f3s frame. Ilyen transzform\u00e1ci\u00f3s frame-k \u00edrj\u00e1k le a teljes robotikai rendszert.

  • Poz\u00edci\u00f3: 3 elem\u0171 offszet vektor (x, y \u00e9s z 3D-ben).
  • Orient\u00e1ci\u00f3: t\u00f6bb reprezent\u00e1ci\u00f3t haszn\u00e1lhatunk:
    • 4 elem\u0171 quaternion (err\u0151l k\u00e9s\u0151bb)
    • 3 elem\u0171 Euler-sz\u00f6gek: roll (d\u0151l\u00e9s, gurul\u00e1s, \u03c8): pitch (b\u00f3lint\u00e1s, \u03b8), yaw (legyez\u0151mozg\u00e1s, \u03c6) wolfram alpha
    • 3 x 3 elem\u0171 rot\u00e1ci\u00f3s matrix

P\u00e9ld\u00e1ul a Nissan Leaf base_link framej\u00e9hez k\u00e9pest a k\u00f6vetkez\u0151 fontosabb framek tal\u00e1lhat\u00f3ak meg:

Frame-k a j\u00e1rm\u0171v\u00f6n

P\u00e9ld\u00e1ul a j\u00e1rm\u0171ves \u00e9s mobil robotos k\u00f6rnyezetben gyakran szeretn\u00e9nk tartani magunkat ahhoz a konvenci\u00f3hoz, hogy a glob\u00e1lis t\u00e9rk\u00e9pet map frame-nek, a j\u00e1rm\u0171 / robot h\u00e1ts\u00f3 tengely\u00e9t base_link-nek h\u00edvjuk. A map \u00e9s a base_link k\u00f6z\u00f6tti megfeleltet\u00e9s t\u00f6rt\u00e9nehet GPS, NDT matching, K\u00e1lm\u00e1n filter, odometria \u00e9s sz\u00e1mos tov\u00e1bbi m\u00f3don. Ezt a k\u00f6vetez\u0151 p\u00e9lda szeml\u00e9lteti:

\ngraph TD\n    %% Define first column\n        direction TB\n        map1([  /map]):::light\n        gps([ /gps]):::light\n        base_link1([ /base_link]):::light\n        velodyne_left([ /velodyne_left]):::light\n        zed_front([ /zed_front]):::light\n        laser([ /laser]):::light\n\n        %% Connections for the first column\n        map1 -.->|dynamic| gps\n        gps -->|static| base_link1\n        base_link1 -->|static| velodyne_left\n        base_link1 -->|static| zed_front\n        base_link1 -->|static| laser\n\n    %% Define second column\n        direction TB\n        map2([ /map]):::light\n        ndt_map([ ndt_map]):::light\n        base_link2([ base_link]):::light\n        sensor_a([ sensor_a]):::light\n        sensor_b([ sensor_b]):::light\n\n        %% Additional sensors can be represented by dots\n        dots2([ ...]):::light\n\n        %% Connections for the second column\n        map2 -.->|dynamic| ndt_map\n        ndt_map --> base_link2\n        base_link2 --> sensor_a\n        base_link2 --> sensor_b\n        base_link2 --> dots2\n\n    %% Define third column\n        direction TB\n        map3([ lexus3/map]):::light\n        kalman_f([ lexus3/kalman_f]):::light\n        base_link3([ lexus3/base_link]):::light\n\n        %% Representing additional connections with dots\n        dots3a([ lexus3/...]):::light\n        dots3b([ lexus3/...]):::light\n        dots3c([ lexus3/...]):::light\n        dots3d([ lexus3/...]):::light\n\n        %% Connections for the third column\n        map3 -.->|dynamic| kalman_f\n        kalman_f --> base_link3\n        base_link3 --> dots3a\n        base_link3 --> dots3b\n        base_link3 --> dots3c\n        dots3c --> dots3d\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff

P\u00e9lda TF tree

GPS haszn\u00e1lata eset\u00e9n nagyvonalakban a k\u00f6vetkez\u0151 p\u00e9lda alapj\u00e1n kell elk\u00e9pzelni a frameket. A map a glob\u00e1lis t\u00e9rk\u00e9p, viszont a gps helyzet\u00e9t is tudjuk ehhez k\u00e9pest. (Megjegyz\u00e9s: a 2020.A senzor \u00f6ssze\u00e1ll\u00edt\u00e1sban 2 GPS is van, ezek k\u00f6l\u00f6nb\u00f6z\u0151 helyen tal\u00e1lhat\u00f3ak, m\u00e9rni tudnak p\u00e1rhuzamosan, de csak egy transzform hat\u00e1rozhatja meg a base_link helyzet\u00e9t. Ezt az 1. \u00e1br\u00e1n a szaggatott nyilak jelzik.) Innen m\u00e1r egy tov\u00e1bbi (statikus) transzform\u00e1ci\u00f3val kaphat\u00f3 a base_link (a h\u00e1ts\u00f3 tengely). Tov\u00e1bbi statikus transzform\u00e1ci\u00f3kkal kaphat\u00f3k a szenzorok a p\u00e9ld\u00e1ban a left_os1/os1_sensor l\u00e1that\u00f3.

A TF tree 2d koordin\u00e1tarendszerben, vizu\u00e1lis p\u00e9lda

A transformok a tf topicaban hirdet\u0151dnek, azonban p\u00e9ld\u00e1ul az MPC szab\u00e1lyz\u00f3 egy current_pose nev\u0171 topicot haszn\u00e1l a szab\u00e1lyz\u00e1s megval\u00f3s\u00edt\u00e1s\u00e1hoz. Ezt \u00fagy oldottuk meg, hogy a base_link frame \u00e9rt\u00e9keit current_pose topic-k\u00e9nt is hirdetj\u00fck. A frame transzl\u00e1ci\u00f3ja a topic poz\u00edc\u00f3ja, illetve a frame rot\u00e1ci\u00f3ja a topic orient\u00e1ci\u00f3ja.

Nagy transzformokn\u00e1l az RVIZ megjelen\u00edt\u0151je nem m\u0171k\u00f6dik pontosan (https://github.com/ros-visualization/rviz/issues/502). Mivel az ROS SI m\u00e9rt\u00e9kegys\u00e9geket haszn\u00e1l, \u00edgy m\u00e9tert is, a GPS eset\u00e9n c\u00e9lszer\u0171 az UTM (wikipedia-utm) koordin\u00e1tarendszer haszn\u00e1lata. Ez \u00e9rtelemszer\u0171en nagy \u00e9rt\u00e9k\u0171 koorin\u00e1t\u00e1kkal sz\u00e1mol. Ahhoz, hogy ezt az ellentmond\u00e1st feloldjuk c\u00e9lszer\u0171 kisebb traszformokat megjelen\u00edteni. \u00cdgy p\u00e9ld\u00e1ul Gy\u0151rh\u00f6z (map_gyor_0) \u00e9s Zal\u00e1hoz (map_zala_0) egy fix statikus transformot, hirdetni, amihez k\u00e9pest m\u00e1r sz\u00e9pen m\u0171k\u00f6dik az RVIZ megjelen\u00edt\u0151je. A k\u00f6vetkez\u0151 \u00e1bra ezt szeml\u00e9lteti, illetve egy kicsit r\u00e9szletesebb szenzorrendszert mutat be.

graph TB\n    %% Define main components\n    map([ map]):::red\n    map_gyor_0([ map_gyor_0]):::dark\n    map_zala_0([ map_zala_0]):::dark\n    gps([ gps]):::light\n    base_link([ base_link]):::red\n\n    %% Define sensors and other components\n    velodyne_left([ velodyne_left]):::light\n    velodyne_right([ velodyne_right]):::light\n    laser([ laser]):::light\n    zed_camera_front([ zed_camera_front]):::light\n    duro_gps_imu([ duro_gps_imu]):::light\n\n    %% OS1 sensors and their subcomponents\n    left_os1_sensor([ left_os1/os1_sensor]):::light\n    left_os1_lidar([ left_os1/os1_lidar]):::light\n    left_os1_imu([ left_os1/os1_imu]):::light\n\n    right_os1_sensor([ right_os1/os1_sensor]):::light\n    right_os1_lidar([ ...]):::light\n    right_os1_imu([ ...]):::light\n\n    %% Connections among main components\n    map --> map_gyor_0\n    map --> map_zala_0\n    map ---> gps\n    gps --> base_link\n\n    %% Connections from base_link to sensors\n    base_link ---> velodyne_left\n    base_link ---> velodyne_right\n    base_link ---> laser\n    base_link --> zed_camera_front\n    base_link --> duro_gps_imu\n    base_link ----> left_os1_sensor\n    base_link ----> right_os1_sensor\n\n    %% Connections for OS1 sensors\n    left_os1_sensor --> left_os1_lidar\n    left_os1_sensor --> left_os1_imu\n\n    right_os1_sensor --> right_os1_lidar\n    right_os1_sensor --> right_os1_imu\n\n\nclassDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  \nclassDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5\nclassDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742\nclassDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff

Az rqt_tf_tree \u00e1ltal megjelen\u00edtett TF fa

Az \u00e1br\u00e1n csak a map gps transzform v\u00e1ltoz\u00f3, a t\u00f6bbi statikus. Statikus transzformot hirdetni launch f\u00e1jlban p\u00e9ld\u00e1ul a /base_link \u00e9s a left_os1/os1_sensor k\u00f6vetkez\u0151k\u00e9pp lehet (l\u00e1sd 3. \u00e1bra)

ROS 2ROS 1
Node(\n    package='tf2_ros',\n    executable='static_transform_publisher',\n    name='ouster_left_tf_publisher',\n    output='screen',\n    arguments=[\n        '--x',  '1.769',\n        '--y',  '0.58',\n        '--z',  '1.278',\n        '--roll', '3.1415926535', # or use math.pi\n        '--pitch', '0.0',\n        '--yaw', '0.0',\n        '--frame-id',      '/base_link',\n        '--child-frame-id','left_os1/os1_sensor'\n    ],\n),\n
<node \n  args=\"1.769 0.58 1.278 3.1415926535 0.0 0.0 /base_link left_os1/os1_sensor 50\"\n  name=\"ouster_left_tf_publisher\" \n  pkg=\"tf\" \n  type=\"static_transform_publisher\"\n/> \n

Ugyanezek parancsk\u00e9nt kiadva termin\u00e1lb\u00f3l:

ROS 2ROS 1
ros2 run tf2_ros static_transform_publisher \\\n--x 1.769 --y 0.58 --z 1.278 \\\n--roll 0.0 --pitch 0.0 --yaw 3.1415926535 \\\n--frame-id left_os1/os1_sensor --child-frame-id base_link\n
rosrun tf static_transform_publisher \\\n1.769 0.58 1.278 \\\n3.1415926535 0.0 0.0 \\\n/base_link left_os1/os1_sensor 50  \n

Itt az utols\u00f3 argumentum ROS 1-n\u00e9l 50 ms, teh\u00e1t 20 Hz-en hirdette a ugyanazt a transzform\u00e1ci\u00f3t. Ez nem a legszerencs\u00e9sebb, az ROS 2 ebben is fejl\u0151d\u00f6tt, ott el\u00e9g egyszer hirdetni ugyanezt.

P\u00e9lda a statikus transzform launch f\u00e1jlra: tf_static.launch

"},{"location":"transzformaciok/#matrix-szorzas","title":"M\u00e1trix szorz\u00e1s","text":"

A 3D transzform\u00e1ci\u00f3 (de term\u00e9szetesen a 2D is) egy m\u00e1trix seg\u00edts\u00e9g\u00e9vel, eg\u00e9sz pontosan m\u00e1trisx szorz\u00e1ssal \u00edrhat\u00f3 le. P\u00e9ld\u00e1ul, ha egy objektumot elmozd\u00edtunk egy adott t\u00e1vols\u00e1gra, akkor azt egy forgat\u00f3m\u00e1trix seg\u00edts\u00e9g\u00e9vel \u00edrhatjuk le. A forgat\u00f3m\u00e1trix 3 dimenzi\u00f3ban egy 3x3-as m\u00e1trix, amely a forgat\u00e1s ir\u00e1ny\u00e1t \u00e9s m\u00e9rt\u00e9k\u00e9t hat\u00e1rozza meg.

Forr\u00e1s: Robotic Systems, University of Illinois

matrixmultiplication.xyz

Python notebook

Danger

A python notebook-ot \u00e9s a m\u00e1trixszoz\u00e1s vizualiz\u00e1ci\u00f3t oktat\u00e1si c\u00e9llal linkelt\u00fck. ROS 2-ben rengeteg funkci\u00f3t ad a tf2 \u00e9s kapcsol\u00f3d\u00f3 megold\u00e1sai, \u00edgy nem kell \"k\u00e9zzel\" transzl\u00e1ci\u00f3t \u00e9s rot\u00e1ci\u00f3t \u00edrni. Transzform\u00e1ci\u00f3kat p\u00e9ld\u00e1ul le lehet k\u00e9rdezni 2 frame k\u00f6z\u00f6tt an\u00e9lk\u00fcl is, hogy tudn\u00e1nk pontosan h\u00e1ny frame-n keresz\u00fcl kapcsol\u00f3dnak. Az ROS 2 ezt k\u00e9nyelmesen biztos\u00edtja. Err\u0151l b\u0151vebben itt lehet olvasni

"},{"location":"transzformaciok/#homogen-koordinatak","title":"Homog\u00e9n koordin\u00e1t\u00e1k","text":"

A homog\u00e9n koordin\u00e1t\u00e1k k\u00e9nyelmes reprezent\u00e1ci\u00f3t ny\u00fajtanak a merevtest transzform\u00e1ci\u00f3khoz, mint a line\u00e1ris transzform\u00e1ci\u00f3k egy kib\u0151v\u00edt\u00e9sek\u00e9nt a t\u00e9rben. R\u00e1ad\u00e1sul kompaktan reprezent\u00e1lj\u00e1k a helyzetf\u00fcgg\u0151 \u00e9s ir\u00e1nyf\u00fcgg\u0151 mennyis\u00e9gek k\u00f6z\u00f6tti k\u00fcl\u00f6nbs\u00e9get. Az \u00f6tlet az, hogy minden pontot kieg\u00e9sz\u00edt\u00fcnk egy tov\u00e1bbi homog\u00e9n koordin\u00e1t\u00e1val, amely 1, ha helyzetf\u00fcgg\u0151, \u00e9s 0, ha ir\u00e1nyf\u00fcgg\u0151. Ezt az m\u0171veletet a \"hat\" (kalap) oper\u00e1torral (^) jel\u00f6lj\u00fck.

"},{"location":"transzformaciok/#quaternion-kvaterniok","title":"Quaternion (kvaterni\u00f3k)","text":"

A roll pitch yaw (Euler sz\u00f6gek) alternat\u00edv\u00e1ja, a komplex sz\u00e1mokhoz hasonl\u00f3 kiterjeszt\u00e9ssel.

Demonst\u00e1ci\u00f3: www.quaternions.online

El\u0151nyei:

  • Numerikus stabilit\u00e1s: A lebeg\u0151pontos reprezent\u00e1ci\u00f3b\u00f3l ad\u00f3d\u00f3 kis numerikus hib\u00e1k sokszor ism\u00e9tl\u0151dve egyre nagyobb hib\u00e1khoz vezethetnek Euler sz\u00f6gek eset\u00e9n. P\u00e9ld\u00e1ul egy forgat\u00e1s p\u00e1r sz\u00e1zad fokos pontatlans\u00e1ga ezrez vagy t\u00edzezres ism\u00e9tl\u00e9ssel komoly hib\u00e1v\u00e1 ad\u00f3dhat \u00f6ssze. Quaternion-okn\u00e1l ez a komlex reprezent\u00e1ci\u00f3 \u00e9s a norm\u00e1lt alak miatt sokkal kisebb.
  • Gyors sz\u00e1m\u00edt\u00e1s: A kvaterni\u00f3k hat\u00e9konyan reprezent\u00e1lj\u00e1k a 3D t\u00e9rbeli forgat\u00e1sokat, \u00e9s sokszor gyorsabbak \u00e9s stabilabbak lehetnek, mint m\u00e1s reprezent\u00e1ci\u00f3s m\u00f3dszerek, p\u00e9ld\u00e1ul Euler-sz\u00f6gek.
  • Pontoss\u00e1g:

    • Nem \u00e9rz\u00e9keny a \"Gimbal lock\" probl\u00e9m\u00e1ra: Az Euler-sz\u00f6gek eset\u00e9ben el\u0151fordulhat egy olyan helyzet, amikor a rot\u00e1ci\u00f3k szenzit\u00edvekk\u00e9 v\u00e1lnak bizonyos ir\u00e1nyokban, ami korl\u00e1tozhatja a sz\u00e1m\u00edt\u00e1sok pontoss\u00e1g\u00e1t. A kvaterni\u00f3k ezt a probl\u00e9m\u00e1t elker\u00fclik.
    • K\u00f6nnyen interpol\u00e1lhat\u00f3k: A kvaterni\u00f3k seg\u00edts\u00e9g\u00e9vel k\u00f6nnyen lehet interpol\u00e1lni a k\u00e9t rot\u00e1ci\u00f3t k\u00f6z\u00f6tt\u00fck, ami fontos az anim\u00e1ci\u00f3k simas\u00e1g\u00e1nak meg\u0151rz\u00e9se szempontj\u00e1b\u00f3l. S\u0151t nem line\u00e1ris interpol\u00e1ci\u00f3khoz is haszn\u00e1lhat\u00f3k. A kvaterni\u00f3k lehet\u0151v\u00e9 teszik a nem line\u00e1ris interpol\u00e1ci\u00f3kat is, ami olyan anim\u00e1ci\u00f3k l\u00e9trehoz\u00e1s\u00e1hoz hasznos, ahol a rot\u00e1ci\u00f3 nem line\u00e1risan v\u00e1ltozik az id\u0151ben.

H\u00e1tr\u00e1ny:

  • Nem intuit\u00edv az ember sz\u00e1m\u00e1ra: Nehezebben \u00e9rthet\u0151k, mint p\u00e9ld\u00e1ul az Euler-sz\u00f6gek, amiket megszoktunk a 3 tengely k\u00f6r\u00fcli forgat\u00e1sra.
\\[tan(\\frac{\\pi}{2}) = \\infty \\]

ROS 2-ben p\u00e9ld\u00e1ul \u00edgy lehet \u00e1talak\u00edtani roll, pitch, yaw \u00e9rt\u00e9keket quaternion-ra.

#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>\ntf2::Quaternion tf2_quat;\ntf2_quat.setRPY(roll, pitch, yaw);\n

Tov\u00e1bbi inform\u00e1ci\u00f3 err\u0151l itt olvashat\u00f3.

"},{"location":"transzformaciok/#konvenciok","title":"Konvenci\u00f3k","text":""},{"location":"transzformaciok/#koordinatarendszerek-gpsgnss","title":"Koordin\u00e1tarendszerek (GPS/GNSS)","text":"

A WGS84 vagy World Geodetic System 1984 egy glob\u00e1lis referencia rendszer a t\u00e9rk\u00e9p\u00e9szetben, geolok\u00e1ci\u00f3ban, navig\u00e1ci\u00f3ban \u00e9s a GPS (Global Positioning System) rendszerben t\u00f6rt\u00e9n\u0151 haszn\u00e1latra. Ez egy szabv\u00e1nyos koordin\u00e1ta rendszer, amelyet a f\u00f6ldrajzi sz\u00e9less\u00e9g, hossz\u00fas\u00e1g \u00e9s tengerszint feletti magass\u00e1g megad\u00e1s\u00e1ra haszn\u00e1lnak. A f\u00f6ldrajzi sz\u00e9less\u00e9gi (latitude) k\u00f6r\u00f6k v\u00edzszintesen futnak, \u00e9s fokokban adj\u00e1k meg egy pont hely\u00e9t a F\u00f6ld felsz\u00edn\u00e9n az egyenl\u00edt\u0151t\u0151l (0 fok sz\u00e9less\u00e9g) \u00e9szakra vagy d\u00e9lre. A hossz\u00fas\u00e1gi k\u00f6r\u00f6k (longitude) f\u00fcgg\u0151legesen futnak, \u00e9s fokokban adj\u00e1k meg egy pont hely\u00e9t a F\u00f6ld felsz\u00edn\u00e9n a keleti vagy nyugati nullameridi\u00e1nt\u00f3l (0 fok hossz\u00fas\u00e1g). A nullameridi\u00e1n a 0 fok hossz\u00fas\u00e1g\u00e1n\u00e1l tal\u00e1lhat\u00f3, \u00e9s Londonon Greenwich v\u00e1rosr\u00e9sz\u00e9n kereszt\u00fcl halad. A hossz\u00fas\u00e1gi \u00e9rt\u00e9kek -180 fokt\u00f3l +180 fokig terjednek, az 180 fokn\u00e1l pedig az \u00c9szaki \u00e9s D\u00e9l-Keleti hossz\u00fas\u00e1gok \u00f6sszekapcsol\u00f3dnak. A m\u00e9r\u00e9sadat f\u00e1jl navsatfix topicja (sensor_msgs/msg/NavSatFix) ebben a form\u00e1tumban ker\u00fclt ment\u00e9sre. Ennek alternat\u00edv\u00e1ja az UTM vet\u00fcleti rendszer, amely nem fokokban, hanem m\u00e9terekben sz\u00e1mol. Az UTM, vagyis az Egyes\u00edtett T\u00e9rk\u00e9pi Projekci\u00f3 (Universal Transverse Mercator), egy t\u00e9rk\u00e9pi projekci\u00f3s rendszer, amelyet a t\u00e9rk\u00e9pek k\u00e9sz\u00edt\u00e9s\u00e9re \u00e9s a navig\u00e1ci\u00f3hoz haszn\u00e1lnak. A vil\u00e1g k\u00fcl\u00f6nb\u00f6z\u0151 z\u00f3n\u00e1it egy sor speci\u00e1lis hengert\u00e9rk\u00e9pen \u00e1br\u00e1zolj\u00e1k, ahol a hossz\u00fas\u00e1gi \u00e9s sz\u00e9less\u00e9gi vonalak egyenesek. Ahogy lejjebb l\u00e1that\u00f3, Magyarorsz\u00e1g 4 UTM z\u00f3n\u00e1ba esik: 33U, 34U, 33T \u00e9s 34T. Az UTM z\u00f3n\u00e1k 6 fokos sz\u00e9less\u00e9gi s\u00e1vokra oszlanak sz\u00e9t, ahol minden s\u00e1vban az \u00e1br\u00e1zol\u00e1s egy transzverz\u00e1lis Merk\u00e1tor-projekci\u00f3n alapul\u00f3 hengert\u00e9rk\u00e9pen t\u00f6rt\u00e9nik. Az UTM rendszer el\u0151nye, hogy egyszer\u0171 koordin\u00e1ta-rendszert biztos\u00edt, ami kis torzul\u00e1ssal rendelkezik a z\u00f3n\u00e1kon bel\u00fcl. Ez\u00e9rt sokszor haszn\u00e1lj\u00e1k katonai t\u00e9rk\u00e9pek, topogr\u00e1fiai t\u00e9rk\u00e9pek, navig\u00e1ci\u00f3s rendszerek \u00e9s m\u00e1s t\u00e9rk\u00e9pk\u00e9sz\u00edt\u00e9si alkalmaz\u00e1sokn\u00e1l. P\u00e9ld\u00e1ul a m\u00e9r\u00e9sadatokn\u00e1l a jellemz\u0151en current_pose v\u00e9gz\u0151d\u00e9s\u0171 topicja (geometry_msgs/msg/PoseStamped) ebben a form\u00e1tumban \u00e9rkez\u0151 adat.

"},{"location":"transzformaciok/#forrasok","title":"Forr\u00e1sok","text":"
  • articulatedrobotics.xyz/ready-for-ros-6-tf
  • Kris Hauser: Robotic Systems University of Illinois at Urbana-Champaign
  • \u00d3budai Egyetem ABC-iRobotics
  • docs.ros.org/en/humble/Tutorials/Intermediate/Tf2/Tf2-Main.html
  • docs.ros.org/en/humble/Tutorials/Intermediate/Tf2/Quaternion-Fundamentals.html
  • mathworld.wolfram.com/EulerAngles.html
"},{"location":"transzformaciok/practice/","title":"Gyakorlat - Transzform\u00e1ci\u00f3k","text":""},{"location":"transzformaciok/practice/#gyakorlat","title":"Gyakorlat","text":"

A k\u00f6vetkez\u0151 gyakorlat a transzform\u00e1ci\u00f3k ROS2-ben t\u00f6rt\u00e9n\u0151 kezel\u00e9s\u00e9t szeml\u00e9lteti, C++-ban.

Python megfelel\u0151je

A C++ k\u00f3d python verzi\u00f3ja szint\u00e9n el\u00e9rhet\u0151 a github.com/sze-info/arj_packages c\u00edmen. \u00c9rdemes \u00f6sszehasonl\u00edtani a C++ \u00e9s a python k\u00f3dokat.

Friss\u00edts\u00fck a leg\u00fajabb verzi\u00f3ra az arj_packages repo-t. Ha friss\u00fcl, vagy Already up to date. \u00fczenetet kapunk, akkor nem kell kl\u00f3noznunk. Ha a cd ~/ros2_ws/src/arj_packages parancs ut\u00e1n a ~/ros2_ws/src/arj_packages: No such file or directory \u00fczenetetet kaptuk, akkor kl\u00f3nozzuk a repo-t.

cd ~/ros2_ws/src/arj_packages\n
git pull\n

Amennyiben a No such file or directory \u00fczenetetet kaptuk, kl\u00f3nozzuk a k\u00f6vetkez\u0151 parancsokkal:

Warning

A k\u00f6vetkez\u0151 k\u00e9t parancs csak nem l\u00e9tez\u0151 arj_packages eset\u00e9n kell:

cd ~/ros2_ws/src\n
git clone https://github.com/sze-info/arj_packages\n

Ha m\u00e1r l\u00e9tezik, akkor az el\u0151z\u0151 l\u00e9p\u00e9s helyett, csak friss\u00edts\u00fck.

cd ~/ros2_ws/src/arj_packages/\n
git status\n
A git checkout -- .: Minden nem staged (unstaged) v\u00e1ltoz\u00e1s elvet\u00e9se lok\u00e1lisan. VS code-ban kb ez a \"discard all changes\" parancs lenne.
git checkout -- .\n
git pull\n

Ezut\u00e1n m\u00e1r buildelhet\u00fcnk is:

cd ~/ros2_ws\n
colcon build --packages-select arj_transforms_cpp --symlink-install\n

C\u00e9lszer\u0171 \u00faj terminalban source-olni, majd futtatni:

source ~/ros2_ws/install/setup.bash\n
ros2 run arj_transforms_cpp pub_transforms\n

Vizsg\u00e1ljuk meg, nyers adatk\u00e9nt milyen kimenetet kapunk:

ros2 topic echo /tf\n

Erre a v\u00e1lasz hasonl\u00f3 lesz:

transforms:\n- header:\n    stamp:\n      sec: 1693475112\n      nanosec: 95339579\n    frame_id: orbit1\n  child_frame_id: orbit2\n  transform:\n    translation:\n      x: -2.487199068069458\n      y: 0.25266680121421814\n      z: 0.0\n    rotation:\n      x: 0.0\n      y: 0.0\n      z: 0.0\n      w: 1.0\n---\ntransforms:\n- header:\n    stamp:\n      sec: 1693475112\n      nanosec: 145005518\n    frame_id: map\n  child_frame_id: orbit1\n  transform:\n    translation:\n      x: -4.109088897705078\n      y: 2.8487515449523926\n      z: 0.0\n    rotation:\n      x: 0.0\n      y: 0.0\n      z: -0.46381551598382736\n      w: 0.8859318072699817\n
Ahogy l\u00e1thatjuk a map frame child_frame_id-ja orbit1. Az orbit1 frame child_frame_id-ja pedig az orbit2. Teh\u00e1t, ha a map-et naygsz\u00fcl\u0151nek tekintj\u00fck, akkor az orbit2 az unoka. Szeml\u00e9letesebb ezt az rqt_tf_tree seg\u00edts\u00e9g\u00e9vel megvizsg\u00e1lni.

ros2 run rqt_tf_tree rqt_tf_tree\n

Ha esetleg nem m\u0171k\u00f6dne a fenti parancs, akkor telep\u00edthet\u0151 a sudo apt install ros-humble-rqt-tf-tree seg\u00edts\u00e9g\u00e9vel. G\u00e9ptermi g\u00e9peken erre elvileg nincs sz\u00fcks\u00e9g.

N\u00e9zz\u00fck meg RVIZ2 seg\u00edts\u00e9g\u00e9vel, \u00edgy fog kin\u00e9zni:

ros2 launch arj_transforms_cpp rviz1.launch.py\n

Vizsg\u00e1ljuk meg a pub_transforms.cpp f\u00e1jlt. (Python eset\u00e9n a _py package-ben a transforms.py f\u00e1jlt.)

cd ~/ros2_ws/src/arj_packages/arj_transforms_cpp\n
code .\n

A leg\u00e9rdekesebb most tal\u00e1n a loop f\u00fcggv\u00e9ny. Pitagorasz t\u00e9tele \u00e9rtelm\u00e9ben tr1.transform.translation.x \u00e9s y a sz\u00ednusz \u00e9s a koszinusz sz\u00f6gf\u00fcggv\u00e9nyek miatt mindig egy k\u00f6r\u00f6n fog elhelyezkedni. A loop_count_ v\u00e1ltoz\u00f3 folyamatosan n\u00f6vekszik, \u00edgy a k\u00f6rt az x \u00e9s az y \u00f3ramutat\u00f3 j\u00e1r\u00e1s\u00e1nak megfelel\u0151en teszi meg. Ez a speed1 \u00e9rt\u00e9k\u00e9nek megfele\u0151en gyors\u00edthat\u00f3 rqt_reconfigure seg\u00edts\u00e9g\u00e9vel (ezt k\u00e9s\u0151bb megn\u00e9zz\u00fck). A k\u00f6r nagys\u00e1ga, az origo-t\u00f3l val\u00f3 t\u00e1vols\u00e1ga pedig a distance1 seg\u00edts\u00e9g\u00e9vel n\u00f6velhet\u0151. Hasonl\u00f3 a helyzet a tr2.transform eset\u00e9ben is, ami az orbit1 -> orbit2 transzfomot adja. A tr1.transform egy plusz forgat\u00e1st is jelent, quaternion seg\u00edts\u00e9g\u00e9vel. A roll, pitch, yaw \u00e9rt\u00e9kekb\u0151l csak az ut\u00f3bbin\u00e1l forgatunk, teh\u00e1t csak Z tengely szerint.

void loop()\n{\n    // Publish transforms\n    tr1.header.stamp = this->get_clock()->now();\n    tr1.header.frame_id = \"map\";\n    tr1.child_frame_id = \"orbit1\";\n    tr1.transform.translation.x = sin(loop_count_ * speed1) * distance1;\n    tr1.transform.translation.y = cos(loop_count_ * speed1) * distance1;\n    tf2::Quaternion quaternion1;\n    quaternion1.setRPY(0.0, 0.0, loop_count_ * speed1);\n    quaternion1=quaternion1.normalize();\n    tr1.transform.rotation.x = quaternion1.x();\n    tr1.transform.rotation.y = quaternion1.y();\n    tr1.transform.rotation.z = quaternion1.z();\n    tr1.transform.rotation.w = quaternion1.w();\n    tf_broadcaster_->sendTransform(tr1);\n    tr2.header.stamp = this->get_clock()->now();\n    tr2.header.frame_id = \"orbit1\";\n    tr2.child_frame_id = \"orbit2\";\n    tr2.transform.translation.x = sin(loop_count_ * speed2) * distance2;\n    tr2.transform.translation.y = cos(loop_count_ * speed2) * distance2;\n    tf_broadcaster_->sendTransform(tr2);\n    loop_count_++;\n}\n

B\u0151v\u00edts\u00fck orbit3 statikus transformmal:

ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3\n

\u00c1ll\u00edtsuk a sebess\u00e9geket \u00e9s a t\u00e1vols\u00e1gokat:

ros2 run rqt_reconfigure rqt_reconfigure\n

Hirdess\u00fcnk egy markert, majd adjuk hozz\u00e1 RVIZ2-ben. Ez a parancs orbit2-re hirdet egy z\u00f6ld kock\u00e1t:

ros2 topic pub --rate 40 --print 40 /marker_topic2 visualization_msgs/msg/Marker '{header: {frame_id: \"orbit2\"}, ns: \"markers2\", id: 2, type: 1, action: 0, pose: {position: {x: 0.0, y: 0.0, z: 0.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}, scale: {x: 1.0, y: 1.0, z: 1.0}, color: {r: 0.2, g: 0.4, b: 0.3, a: 1.0}}'\n

Ez a parancs orbit1-re hirdet egy piros nyilat:

ros2 topic pub --rate 40 --print 40 /marker_topic3 visualization_msgs/msg/Marker '{header: {frame_id: \"orbit1\"}, ns: \"markers3\", id: 3, type: 0, action: 0, pose: {position: {x: 0.0, y: 0.0, z: 0.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}, scale: {x: 1.8, y: 0.4, z: 0.4}, color: {r: 0.8, g: 0.2, b: 0.2, a: 1.0}}'\n

A Marker \u00fczenet tpye attrib\u00fatuma adja meg, hogy a marker pl ARROW=0 vagy CUBE=1:

ros2 interface show  visualization_msgs/msg/Marker\n\n...\ntype:\nint32 ARROW=0\nint32 CUBE=1\nint32 SPHERE=2\nint32 CYLINDER=3\nint32 LINE_STRIP=4\nint32 LINE_LIST=5\nint32 CUBE_LIST=6\nint32 SPHERE_LIST=7\nint32 POINTS=8\nint32 TEXT_VIEW_FACING=9\nint32 MESH_RESOURCE=10\nint32 TRIANGLE_LIST=11\n\n...\n

Tov\u00e1bbi sz\u00ednekre p\u00e9lda lejjebb, sz\u00ednekr\u0151l pedig b\u0151vebben: github.com/jkk-research/colors.

. . . 0.96 0.26 0.21 0.53 0.05 0.31 0.19 0.11 0.57 0.73 0.87 0.98 0.13 0.59 0.95 0.00 0.59 0.53 0.78 0.90 0.79 0.30 0.69 0.31 0.80 0.86 0.22 1.00 0.93 0.70 1.00 0.76 0.03 1.00 0.44 0.00 0.84 0.80 0.78 0.47 0.33 0.28 0.24 0.15 0.14 0.96 0.96 0.96 0.62 0.62 0.62 0.13 0.13 0.13"},{"location":"transzformaciok/practice/#onallo-feladat","title":"\u00d6n\u00e1ll\u00f3 feladat","text":"

\u00d6n\u00e1ll\u00f3 feladatk\u00e9nt k\u00e9sz\u00edts\u00fcnk egy my_launch_pkg nev\u0171 package-t, amiben egy run_transforms_and_markers.launch.py elind\u00edtja a:

  • node-ot, ami a map, orbit1 \u00e9s orbit2 frame-ket publik\u00e1lja (ros2 run arj_transforms_cpp pub_transforms)
  • az rqt_reconfigure-t (ros2 run rqt_reconfigure rqt_reconfigure)
  • a statikus orbit3 frame-et (ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3)
  • \u00e9s az Rviz2-t ind\u00edt\u00f3 launch-t is (ros2 launch arj_transforms_cpp rviz1.launch.py)

Ellen\u0151rizz\u00fck rviz2-ben a helyes m\u0171k\u00f6d\u00e9st.

Teh\u00e1t ind\u00edthat\u00f3 legyen az \u00f6n\u00e1ll\u00f3 feladat v\u00e9g\u00e9n a k\u00f6vetkez\u0151 paranccsal:

ros2 launch my_launch_pkg run_transforms_and_markers.launch.py\n

Megold\u00e1s: el\u00e9rhet\u0151 az \u00f6n\u00e1ll\u00f3 feladatok k\u00f6z\u00f6tt

"},{"location":"transzformaciok/practice/#segitseg-az-onallo-feladathoz","title":"Seg\u00edts\u00e9g az \u00f6n\u00e1ll\u00f3 feladathoz","text":"

A ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3 az el\u0151z\u0151 \u00f3r\u00e1k alapj\u00e1n k\u00f6nnyen \u00f6ssze\u00e1ll\u00edthat\u00f3:

Node(\n    package='tf2_ros',\n    executable='static_transform_publisher',\n    arguments=['1.0', '0.2', '1.4','0', '0', '0', '1', 'orbit2','orbit3'],\n),     \n

Warning

Nehezebb dolgunk van az Rviz2-vel, ugyanis ott egy launch f\u00e1jlt kell megh\u00edvni nem egy node-ot.

Els\u0151, de kev\u00e9sb\u00e9 sz\u00e9p opci\u00f3, hogy bem\u00e1soljuk az eredeti launch f\u00e1jlt \u00e9s azt eg\u00e9sz\u00edtj\u00fck ki:

from launch import LaunchDescription\nfrom launch_ros.actions import Node\nimport os\nfrom ament_index_python.packages import get_package_share_directory\n\n\ndef generate_launch_description():\n\n    pkg_name = 'arj_transforms_cpp'\n    pkg_dir = get_package_share_directory(pkg_name)\n\n\n    return LaunchDescription([\n        Node(\n            package='rviz2',\n            namespace='',\n            executable='rviz2',\n            name='rviz2',\n            arguments=['-d', [os.path.join(pkg_dir, 'rviz', 'rviz1.rviz')]]\n        )\n    ])\n

M\u00e1sodik, sokkal szebb opci\u00f3, hogy a launch f\u00e1jlt include-oljuk a launch f\u00e1jlba:

from launch import LaunchDescription\nfrom launch_ros.actions import Node\nfrom launch.actions import IncludeLaunchDescription\nfrom launch.launch_description_sources import PythonLaunchDescriptionSource\nfrom launch_ros.substitutions import FindPackageShare\n\n\ndef generate_launch_description():\n    return LaunchDescription([\n        # ros2 launch arj_transforms_cpp rviz1.launch.py\n        IncludeLaunchDescription(\n            PythonLaunchDescriptionSource([\n                FindPackageShare(\"arj_transforms_cpp\"), '/launch/', 'rviz1.launch.py'])\n        ),\n    ])\n
"},{"location":"transzformaciok/practice/#hazi-feladat","title":"H\u00e1zi feladat","text":"

H\u00e1zi feladat

K\u00e9sz\u00edts\u00fcnk ROS 2 package-t (mindegy, hogy python vagy C++), ami a map frame-re hirdet egy CUBE t\u00edpus\u00fa markert. A marker sz\u00edne legyen a md_blue_500 (0.13 0.59 0.95) \u00e9s a m\u00e9rete 1.0. A marker poz\u00edci\u00f3ja legyen a map frame-ben (r1, r2, 0.0). AZ r1, r2 k\u00e9t v\u00e9letlensz\u00e1m 0 \u00e9s 2 k\u00f6z\u00f6tti intervallumon. Hirdesse a topicot 5 Hz-en. A marker id-ja legyen 1. A marker \u00fczenetet a /marker_topic topic-ra hirdess\u00fck. A package neve legyen my_cool_marker_pkg.

"},{"location":"transzformaciok/practice/#tovabbi","title":"Tov\u00e1bbi","text":"

Python notebook transform

Python notebook quaternion

gps_utm.ipynb

"},{"location":"transzformaciok/practice/#olvasnivalo","title":"Olvasnival\u00f3","text":"
  • articulatedrobotics.xyz/ready-for-ros-6-tf
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..64a3a2e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,239 @@ + + + + https://sze-info.github.io/ajr/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/copilot/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/gepterem/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/linux/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/ros2/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/ros2gyak/ + 2024-10-20 + + + https://sze-info.github.io/ajr/bevezetes/vscodegit/ + 2024-10-20 + + + https://sze-info.github.io/ajr/erzekeles/ + 2024-10-20 + + + https://sze-info.github.io/ajr/erzekeles/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/ground_filter/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/practice_cluster/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/road_filter/ + 2024-10-20 + + + https://sze-info.github.io/ajr/eszleles/slam/ + 2024-10-20 + + + https://sze-info.github.io/ajr/feleves_beadando/ + 2024-10-20 + + + https://sze-info.github.io/ajr/feleves_beadando/kisbeadando/ + 2024-10-20 + + + https://sze-info.github.io/ajr/feleves_beadando/nagyfeleves/ + 2024-10-20 + + + https://sze-info.github.io/ajr/kalman_filter/ + 2024-10-20 + + + https://sze-info.github.io/ajr/kalman_filter/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/linkek/ + 2024-10-20 + + + https://sze-info.github.io/ajr/mesterseges_intelligencia/ + 2024-10-20 + + + https://sze-info.github.io/ajr/mesterseges_intelligencia/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/bashalias/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/joystick/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/linux/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/mermaid/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/ros2git/ + 2024-10-20 + + + https://sze-info.github.io/ajr/onallo/ros2launchmarker/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/docker/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/mcap/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/pointcloud_to_grid/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/py_cpp/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/qos/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/ros2launch/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/rqt/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/state/ + 2024-10-20 + + + https://sze-info.github.io/ajr/ros2halado/vizualizacio/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szabalyozas/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szabalyozas/ros1practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szabalyozas/ros2practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szimulacio/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szimulacio/f1tenth_sim_a/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szimulacio/gazebo_fortress/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szimulacio/gyakorlat/ + 2024-10-20 + + + https://sze-info.github.io/ajr/szimulacio/lgsvl_nissan/ + 2024-10-20 + + + https://sze-info.github.io/ajr/telepites/ + 2024-10-20 + + + https://sze-info.github.io/ajr/telepites/ros_humble/ + 2024-10-20 + + + https://sze-info.github.io/ajr/telepites/ubuntu/ + 2024-10-20 + + + https://sze-info.github.io/ajr/telepites/win10/ + 2024-10-20 + + + https://sze-info.github.io/ajr/tervezes/ + 2024-10-20 + + + https://sze-info.github.io/ajr/tervezes/planning_control_diagram/ + 2024-10-20 + + + https://sze-info.github.io/ajr/tervezes/practice/ + 2024-10-20 + + + https://sze-info.github.io/ajr/transzformaciok/ + 2024-10-20 + + + https://sze-info.github.io/ajr/transzformaciok/practice/ + 2024-10-20 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000..d395934 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/stylesheets/extra.css b/stylesheets/extra.css new file mode 100644 index 0000000..5a0bb9a --- /dev/null +++ b/stylesheets/extra.css @@ -0,0 +1,37 @@ +[data-md-color-scheme="youtube"] { + /* Primary color shades */ + --md-primary-fg-color: #43AEC5; + --md-primary-fg-color--light: #9fd4e0; + --md-primary-fg-color--dark: #182744; + --md-primary-bg-color: #ffffff; + /* Accent color shades */ + --md-accent-fg-color: #43AEC5; + --md-accent-fg-color: #43AEC5; + --md-accent-fg-color--light: #9fd4e0; + --md-accent-fg-color--dark: #182744; +} + +:root { + --md-primary-fg-color: #43AEC5; + --md-primary-fg-color--light: #9fd4e0; + --md-primary-fg-color--dark: #182744; + --md-primary-bg-color: #182744; +} + +[data-md-color-scheme="youtube"] img[src$="#only-dark"], +[data-md-color-scheme="youtube"] img[src$="#gh-dark-mode-only"] { + display: none; /* Hide dark images in light mode */ +} + +:root>* { + + + + + /* Footer */ + --md-footer-bg-color: #182744; + --md-footer-bg-color--dark: #182744; + --md-footer-fg-color: #43AEC5; + --md-footer-fg-color--light: #b9e7f2; + --md-footer-fg-color--lighter: #d9eef3; +} \ No newline at end of file diff --git a/szabalyozas/arj_control_01.png b/szabalyozas/arj_control_01.png new file mode 100644 index 0000000..89f7676 Binary files /dev/null and b/szabalyozas/arj_control_01.png differ diff --git a/szabalyozas/arj_control_02.svg b/szabalyozas/arj_control_02.svg new file mode 100644 index 0000000..5a66775 --- /dev/null +++ b/szabalyozas/arj_control_02.svg @@ -0,0 +1 @@ +MissionGuidanceGlobal planningInputs:-Driver/Userselection-MapdataOutput:-RouteplanGoal:toplana globalroutewhichleadsfromA toB, consideringe.g., trafficdata,fuelconsumption…etc.BehaviorGuidanceBehaviorplanningInputs:-Routeplan-PerceptioninfoofthesurroundingsOutput:-BehaviorstrategyGoal: planhowthevehicleshouldbehavein termsof decisionsand motioncharacteristicsTrajectoryGuidanceLocal planningInputs:-Behaviorstrategy-PlanningconstraintsOutput:-Local trajectoryGoal:planakinematiclyfeasible,safeandpreferredtrajectoryVehicleControlHighlevelcontrolInputs:-Local trajectory-Vehiclestatevariables-LocalizationinfoOutputs:-Vehicleleveltargetquantities-ControlconstraintsGoal: calculatethevehicletargetstatetobe controlledbythelowlevelcontrollersActuatorControlLow levelcontrolInputs:-Vehicleleveltargetquantities-Controlconstraints-ActuatorstatevariablesOutput:-ActuatortargetstatesGoal: realizevehiclemotionthroughcontrollingtheactuatorsPlanningControl‚I wanttogetfromaddressA toaddressB witha robotaxi‚I wanttofollowthemiddlelanethenchangetotheinnerlanesmoothly‚I plana trajectorywithinthelanetobe safeand thena smoothtrajectorytotheinnerlane‚I calculatethenecessaryspeedand yawrateof thevehicletofollowthelocal trajectory‚I calculatethenecessaryenginetorqueand steeringangletorealizetheplannedmotion \ No newline at end of file diff --git a/szabalyozas/arj_control_03.svg b/szabalyozas/arj_control_03.svg new file mode 100644 index 0000000..5637934 --- /dev/null +++ b/szabalyozas/arj_control_03.svg @@ -0,0 +1 @@ +SzabályzottSzakaszModellje (absztrakt rendszer)Szabályzó++𝑑(𝑡)𝑢(𝑡)𝑖(𝑡)Érzékelő𝑦(𝑡)𝑚(𝑡)SzabályzottSzakasz (valós fizikai modell)𝑒(𝑡)𝑟(𝑡)Előrecsatolás+𝑓(𝑡) \ No newline at end of file diff --git a/szabalyozas/arj_control_04.svg b/szabalyozas/arj_control_04.svg new file mode 100644 index 0000000..e1bad5d --- /dev/null +++ b/szabalyozas/arj_control_04.svg @@ -0,0 +1 @@ +𝐹𝑝𝑟𝑜𝑝(𝑡)𝑎𝑡,𝑣(𝑡)𝐹𝑎𝑒𝑟𝑜(𝑡)𝐹𝑓𝑟𝑖𝑐(𝑡)𝐹𝑓𝑟𝑖𝑐(𝑡)m𝑡0𝑡1 \ No newline at end of file diff --git a/szabalyozas/arj_control_05.png b/szabalyozas/arj_control_05.png new file mode 100644 index 0000000..d3a7e59 Binary files /dev/null and b/szabalyozas/arj_control_05.png differ diff --git a/szabalyozas/arj_control_06.png b/szabalyozas/arj_control_06.png new file mode 100644 index 0000000..768e6c4 Binary files /dev/null and b/szabalyozas/arj_control_06.png differ diff --git a/szabalyozas/arj_control_07.png b/szabalyozas/arj_control_07.png new file mode 100644 index 0000000..60d8d78 Binary files /dev/null and b/szabalyozas/arj_control_07.png differ diff --git a/szabalyozas/arj_control_08.png b/szabalyozas/arj_control_08.png new file mode 100644 index 0000000..577bffc Binary files /dev/null and b/szabalyozas/arj_control_08.png differ diff --git a/szabalyozas/arj_control_09.png b/szabalyozas/arj_control_09.png new file mode 100644 index 0000000..a3acdb4 Binary files /dev/null and b/szabalyozas/arj_control_09.png differ diff --git a/szabalyozas/arj_control_10.png b/szabalyozas/arj_control_10.png new file mode 100644 index 0000000..cc427ff Binary files /dev/null and b/szabalyozas/arj_control_10.png differ diff --git a/szabalyozas/arj_control_11.png b/szabalyozas/arj_control_11.png new file mode 100644 index 0000000..76945ad Binary files /dev/null and b/szabalyozas/arj_control_11.png differ diff --git a/szabalyozas/arj_control_12.png b/szabalyozas/arj_control_12.png new file mode 100644 index 0000000..f7955bd Binary files /dev/null and b/szabalyozas/arj_control_12.png differ diff --git a/szabalyozas/arj_control_13.png b/szabalyozas/arj_control_13.png new file mode 100644 index 0000000..8294389 Binary files /dev/null and b/szabalyozas/arj_control_13.png differ diff --git a/szabalyozas/arj_control_14.png b/szabalyozas/arj_control_14.png new file mode 100644 index 0000000..66c9797 Binary files /dev/null and b/szabalyozas/arj_control_14.png differ diff --git a/szabalyozas/arj_control_15.png b/szabalyozas/arj_control_15.png new file mode 100644 index 0000000..3111ad6 Binary files /dev/null and b/szabalyozas/arj_control_15.png differ diff --git a/szabalyozas/arj_control_16.png b/szabalyozas/arj_control_16.png new file mode 100644 index 0000000..8729df5 Binary files /dev/null and b/szabalyozas/arj_control_16.png differ diff --git a/szabalyozas/arj_control_17.png b/szabalyozas/arj_control_17.png new file mode 100644 index 0000000..3cd8411 Binary files /dev/null and b/szabalyozas/arj_control_17.png differ diff --git a/szabalyozas/arj_control_18.png b/szabalyozas/arj_control_18.png new file mode 100644 index 0000000..62b8923 Binary files /dev/null and b/szabalyozas/arj_control_18.png differ diff --git a/szabalyozas/arj_control_18.svg b/szabalyozas/arj_control_18.svg new file mode 100644 index 0000000..78af2d5 --- /dev/null +++ b/szabalyozas/arj_control_18.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/szabalyozas/arj_control_19.png b/szabalyozas/arj_control_19.png new file mode 100644 index 0000000..288534a Binary files /dev/null and b/szabalyozas/arj_control_19.png differ diff --git a/szabalyozas/arj_control_19_look_ahead.svg b/szabalyozas/arj_control_19_look_ahead.svg new file mode 100644 index 0000000..726fb0a --- /dev/null +++ b/szabalyozas/arj_control_19_look_ahead.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/szabalyozas/arj_control_20.png b/szabalyozas/arj_control_20.png new file mode 100644 index 0000000..f5a798b Binary files /dev/null and b/szabalyozas/arj_control_20.png differ diff --git a/szabalyozas/arj_control_21.png b/szabalyozas/arj_control_21.png new file mode 100644 index 0000000..0d6919a Binary files /dev/null and b/szabalyozas/arj_control_21.png differ diff --git a/szabalyozas/arj_control_22.png b/szabalyozas/arj_control_22.png new file mode 100644 index 0000000..efd2977 Binary files /dev/null and b/szabalyozas/arj_control_22.png differ diff --git a/szabalyozas/arj_control_23.png b/szabalyozas/arj_control_23.png new file mode 100644 index 0000000..81d2d9e Binary files /dev/null and b/szabalyozas/arj_control_23.png differ diff --git a/szabalyozas/arj_control_24.png b/szabalyozas/arj_control_24.png new file mode 100644 index 0000000..0d8b83e Binary files /dev/null and b/szabalyozas/arj_control_24.png differ diff --git a/szabalyozas/foxglove_speed_30.PNG b/szabalyozas/foxglove_speed_30.PNG new file mode 100644 index 0000000..83f16c7 Binary files /dev/null and b/szabalyozas/foxglove_speed_30.PNG differ diff --git a/szabalyozas/foxglove_speed_30_I.PNG b/szabalyozas/foxglove_speed_30_I.PNG new file mode 100644 index 0000000..c109c1a Binary files /dev/null and b/szabalyozas/foxglove_speed_30_I.PNG differ diff --git a/szabalyozas/foxglove_speed_zero.PNG b/szabalyozas/foxglove_speed_zero.PNG new file mode 100644 index 0000000..f876031 Binary files /dev/null and b/szabalyozas/foxglove_speed_zero.PNG differ diff --git a/szabalyozas/index.html b/szabalyozas/index.html new file mode 100644 index 0000000..c256c01 --- /dev/null +++ b/szabalyozas/index.html @@ -0,0 +1,3238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - szabályozás - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Szabályozás

+

A szabályozás célja a megtervezett trajektória kivitelezése.

+

+

1. Motiváció a zárthurkú szabályozás mögött - bevezetés

+

Egy rendszer tervezett célállapotát úgy érhetjük el, ha célérték figyelembevételével a rendszerbe beavatkozunk. Például egy jármű esetén a célsebességet a gáz és fékpedál mozgatásával, közvetetten a motor nyomatékának és a fékerőnek a változtatásával érhetjük el. Kezdeti példának tekintsünk egy járművezetőt: a vezető általában tisztában van a megengedett legnagyobb sebességgel, ekörül alkalmaz egy számára megfelelő tűrési sávot. Ezen belül meghatároz egy számára biztonságos és kényelmes sebességet, amit tartani szeretne. A vezető addig gyorsít, amíg el nem éri a kívánt sebességet, majd a gázpedált kicsit visszábbengedve tartja a sebességet. +Helyes az az állítás, hogy amennyiben elértük a kívánt sebességet, a pedált elengedhetjük, nincs több dolgunk? Természetesen nem. Miért nem? Hisz a jármű a veszteségekből adódóan lassulni fog, lejtő esetén akár gyorsulhat is. Ahhoz, hogy tartani tudjuk a sebességet a vezetőnek folyamatosan figyelnie kell a jármű mozgását illetve a környezetet, és ez alapján beavatkoznia a pedálokon keresztül. +Ez az egyszerű példa legtöbb részét a tervezési és szabályzási komponenseknek lefedi. A szabályzás téren a következő megfigyeléseket tehetjük meg: +- a vezető érzékeli a jármű akutális állapotát (valamilyen pontossággal) +- a vezető tudja, hogyha beavatkozik a gáz- vagy fékpedállal, milyen hatást fog elérni, azaz mennyire lassul vagy gyorsul az autó (valamilyen pontossággal) +- a vezető különösebb érzékeléstől függetlenül (tehát anélkül, hogy tudná, pl. milyen erő hat az autóra) nagyjából (!) meg tudja határozni a kívánt gázpedál állást (nagy hibával)

+

Az utolsó pontot szokás ún. előrecsatolt ágnak is hívni (lásd 3. alfejezet), avagy nyílthurkú szabályzásnak (amennyiben nincs semmilyen infónk az érzékelésről). +Egy nagyon durva összehasonlítást tartalmaz az 1. Ábra. Képzeljünk el egy helyzetet, amikor nincs információnk arról, milyen gyorsan megy a jármű, csupán a pedált tudjuk kezelni. A feladat hogy álló helyből gyorsítva elérjük a 90 km/h sebességet, majd ezt a sebességet tartsuk. Ha nem tudjuk, épp mennyivel megyünk, honnan tudjuk, hogy kell-e még nyomni a pedált avagy nem? Ilyenkor arra tudunk alapozni, hogy ismerjük az útviszonyokat (pl. sík talaj, aszfaltos út), ismerjük az autónkat (milyen motor, milyen nyomatékviszonyok...stb.). Így nagyjából meg tudjuk határozni, milyen hosszan kell nyomni a gázpedált, majd amikor nagyjából elértük a sebességet, mennyire kell ott tartani a pedálon a lábunkat, hogy ne lassuljunk, ne gyorsuljunk. Az eredmény valószínűleg hasonlítani fog a kívánt sebességgörbéhez, de messze nem lesz pontos. Hiszen pontatlanul ismerjük az utat, a saját autónkat, befolyásolja a gyorsulást a hőmérséklet, emelkedő/lejtő, szembeszél...stb. Ezért általában nem, vagy nem csak ezt a nyílthurkú megközelítést használjuk, hanem minél pontosabb érzékelők segítségével korrigáljuk az általunk előre meghatározott pedál állásokat, és ezzel bármilyen zavar hatását le tudjuk kezelni. Ez utóbbi megközelítést nevezzük zárthurkú szabályzásnak, az érzékelésből kapott információkat pedig visszacsatolásnak.

+
+

Note

+

A magyar terminológiában szokás a nyílthurkú szabályzást vezérlésnek, a zárthurkú szabályzást röviden csak szabályzásnak hívni. A kettőt együtt pedig irányításnak. Az angol terminológia ezzel szemben mindkettőt controlnak, azon belül is closed loop controlnak illetve open loop controlnak hívja. A visszacsatolást feedbacknek, az előrecsatolást feed-forwardnak szokás hívni.

+
+

image info

+

1. Ábra: a zárthurkú szabályozás mögötti motiváció. Forrás: Autonomous Driving Software Engineering - Lecture 08: Control

+

2. Architekturális áttekintés, visszatekintés

+

Ahogyan azt a korábbi fejezetekben is láttuk, a teljes járműirányítási lánc moduláris. A legfőbb feladatok: +- érzékelés +- észlelés +- tervezés +- szabályzás

+

Ez a fejezet a szabályzásról szól. A szabályzások alapjairól a 3. alfejezetben olvashatunk. A szabályzó rétegnek a tervezés biztosítja a bemenetet. Így - némileg kiegészítve - vessünk egy pillantást az architektúrára! Ezt a 2. Ábra mutatja.

+

flowchart LR
+
+GP1[Globális tervezés
+   Bemenetek:
+   - Sofőrprofil
+   - Térkép
+   Kimenet:
+   - Útvonalterv
+   Cél: globális terv megtervezése
+   útvonalon, amely A-ból vezet
+   B-be, figyelembe véve pl.
+   forgalmi adatok, üzemanyag
+   fogyasztás… stb.]:::light
+
+GP2[Szeretnék eljutni
+   A-ból B-be
+   robotaxival]:::dark
+
+BP1[Magatartás tervezés
+     Bemenetek:
+     - Útvonalterv
+     -Érzékelési információ
+     a környezetről
+     Kimenet:
+     - Viselkedési stratégia
+     Cél: megtervezni, hogy
+     viselkedjen, 
+     milyen mozgási
+     karakterisztikát
+     kövessen a jármű]:::light
+
+BP2[Követni szeretném
+  a középső sávot,
+  majd váltani a 
+  belső sávra]:::dark
+
+LP1[Lokális tervezés
+     Bemenetek:
+     - Viselkedési stratégia
+     - Térkép
+     - Pose
+     - Prediktált objektumok
+     Kimenet:
+     - Lokális trajektória
+     Cél: kinematikailag 
+     megvalósítható,
+     biztonságos trajektória
+     előállítása]:::light
+LP2[A sávon belül
+  biztonságos és
+  sima pálya tervezése]:::dark
+
+
+VC1[Járműszintű szabályzás
+     Magas szintű szabályozás
+     Bemenetek:
+     - Lokális trajektória
+     - A jármű állapotának változói
+     - Lokalizációs információ
+     Kimenetek:
+     - Járműszintű cél
+     mennyiségek
+     - Ellenőrzési korlátok
+     Cél: kiszámítani a
+     jármű célállapotát, amit 
+     az alacsony szintű
+     szabályzás megvalósít]:::light
+VC2[A járművet a 
+  tervezett trajektórián
+  végigvezesse a 
+  megfelelő sebességgel]:::dark
+
+
+AC1[Aktuátor szabályozás
+  Alacsony szintű szabályozás
+  Bemenetek:
+  - Járműszintű cél
+  mennyiségek
+  - Ellenőrzési korlátok
+  - Aktuátor
+  állapotváltozói
+  Kimenet:
+  - Aktuátor célállapotai
+  Cél: A járműszintű 
+  mennyiségeket lebontsa
+  és megvalósítsa 
+  az aktuátorokon keresztül]:::light
+  AC2[Kiszámolni a
+szükséges motor
+nyomaték és kormányzási
+szög referenciát]:::dark
+
+
+
+
+subgraph Plan [Tervezés]
+  GP1
+  BP1
+  LP1
+end
+subgraph Control [Szabályozás]
+  VC1
+  AC1
+end
+GP1-->BP1-->LP1-->VC1-->AC1
+GP2-.-BP2-.-LP2-.-VC2-.-AC2
+
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+2. Ábra: a legfőbb tervezési és szabályzási rétegek az architektúrában.

+

A szabályzó réteg általában több szinre bomlik. Minimum két ilyen szintet megkülönböztetünk: +- járműszintű szabályzás +- aktuátor szabályzás

+

Mindkettő rétegnek meg van a feladata. A járműszintű szabályzás feladata, hogy a járművet a tervezett trajektórián végigvezesse a megfelelő sebességgel. Ehhez a jármű szintjén megfogalmazott célértékeket határoz meg. Ökölszabályként elfogadhatjuk, hogy azok a mennyiségek a járműszintűek, amelyek még nem kapcsolódnak egy kimondott aktuátorhoz. Azaz, pl. minden autóra jellemző annak gyorsulása vagy szögsebessége, attól függetlenül, milyen hajtással (elektromos, hibrid, belsőégésű) vagy kormányzással (elektromos szervó, hidraulikus szervó, lánctalpas...stb.) rendelkezik. Általában ez a szabályzó réteg a "leglassabb", beágyazott környezetben a ciklus idő 10-50ms. +Az aktuátot szabályzás feladata, hogy a járműszintű mennyiségeket lebontsa és megvalósítsa az aktuátorokon keresztül. Pl. a hosszirányú gyorsulást befolyásolhatjuk a motoron és a féken keresztül. A motor esetében a gyorsulást a motor nyomatékának szabályzásával érjük el, amit pedig a fojtószelep állásával érünk el. A fojtószelep állását pedig az azt mozgató pl. szervómotor pozíciójának, voltaképp a szervómotor kapocsfeszültségének szabályzásával érünk el. A fékrendszer esetén a fékerőt tudjuk befolyásolni, ami egyben a féknyomás szabályzását jelenti (pl. az ESP szelepein keresztül), amit pedig a hidraulikus fékrendszer motor szivattyújának nyomásával érhetünk el. Ezt pedig a szivattyú motorjának fordulatszámával tudjuk befolyásolni, ami megint a motor kapocsfeszültségének a szabályzásával érünk el...stb. Láthatjuk, hogy aktuátoroktól függően itt több (akár 4-6) egymásba ágyazott szabályzó hurokról beszélünk. +Belülről kifelé érdemes a problémát megközelíteni, ahogy a legbelső szabályzás ciklusideje akár 1 ms (vagy az alatti) lehet, még ahogy kintebb lépünk ez nő, 5-10-20ms tartományban. +Fontos, hogy automatizált vezetési rendszerek mozgásszabályzása esetén az aktuátor szabályzó rétegeket sokszor nem vesszük figyelembe, hanem feltételezzük, hogy azok teljesítménye, pontossága, sebessége megfelelő, "közel ideális". Persze a gyakorlatban ezt sokszor nehéz elválasztani, de arra törekszünk, hogy csak a járműszintű szabályzást kelljen megtervezni.

+

A legfelső szintű szabályzás feladata tehát az, hogy a jármű a trajektóriát lekövesse. Általában két dimenziót különböztetünk meg: +- hosszirányú mozgás: a jármű hosszirányú gyorsulásának, és végül a fék és motorerők meghatározása. +- keresztirányú mozgás: a jármű célszögesebességének, és végül a kormányszögnek a meghatározása.

+

A trajektória általában egy időben leírt sebességtarjektória illetve egy térben megadott célpont halmaz, azaz egy görbe (vagy annak egy reprezntációja). A cél, hogy a görbét minél kisebb pozícióhibával lekövessük, illetve a sebességet minél pontosabban tartsuk. Mindezt úgy, hogy ne lépjünk át semmilyen határértéket (pl. túl nagy gyorsulás, pályaelhagyás...stb).

+

Mielőtt rátérnénk a létező járműszabályzási megoldásokra, a 3. alfejezetben áttekintést adunk a szabályzási alapokról.

+

3. Szabályzási alapok

+

Ebben a fejezetben ismertetjük a szabályzástechnikához kapcsolódó alapfogalmakat, és erre példákat is hozunk a járműirányítás területéről.

+

3.1. Definíciók

+

Valós fizikai rendszer: egy olyan fizikai objektum, amely mérhető külső kényszer hatására mérhető módon megváltozik.

+

Bemenetek: A valós fizikai rendszerre ható és időben változni képes kényszereket nevezzük fizikai bemeneteknek.
+Kimenetek: A valós fizikai rendszernek a fizikai kényszerek hatására bekövetkező bármely változása lehet fizikai kimenet, ezek közül azt tekintjük fizikai kimenetnek, amelyet az adott vizsgálatban közvetlenül vagy közvetve mérünk.
+Példa: ezt mindig a szabályzási feladatnak megfelelően határozzuk meg. Például járműszintű irányítás: a rendszer a jármű maga, bemenete pl. a hosszirányú és keresztirányú gyorsulás. Kimenete pl. a pozíció, sebesség...stb.
+Példa: alacsonyszintű szabályzás esetén ez lehet pl. a fékszabályzás, ahol a bemenet a főfékhenger pozíciója, a kimenet a féktárcsa és a fékpofa között fellépő erő, vagy a kerékre ható nyomaték...stb..

+

Az absztrakt rendszer: Az absztrakt rendszer egy valós fizikai rendszer valamilyen pontosságú és meghatározott működési tartományra érvényes absztrakt modellje, amely a bemenőjelek és a kimenőjelek között teremt matematikai kapcsolatot. Ez voltaképp egy modellezési eljárás eredménye, amely modell a valós fizikai rendszer matematikai leírása, jellemzően differenciálegyenletek formájában.
+Példa: a jármű kinematikai bicikli modellje.

+

Rendszer paraméterek: A valós fizikai rendszert leíró egyenletek együtthatóit paramétereknek nevezzük.
+Időinvariancia: Az időinvariáns rendszer esetén, ha a rendszer egy U(t) gerjesztésre adott válasza Q(t), akkor az időben eltolt U(t-tau) gerjesztésre adott Y(t-tau) válasz is egyszerű időbeni eltolással megkapható. Ez egyúttal azt is jelenti, hogy a rendszer modellje időben nem változik, azaz a rendszer paraméterei állandóak.
+Példa: a jármű kinematikai bicikli modelljének paraméterei pl. a jármű tengelytávja, amely (remélhetőleg) időben nem változik, azaz ez a paraméter időinvariáns. Ha a rendszer modelljének összes paramétere időinvariáns, maga az absztrakt rendszer is invariáns.
+Példa: a jármű dinamikai bicikli modelljének egy paramétere a jármű tömege. Ez változhat "menet közben is", hiszen pl. többen ülnek az autóban, csomagokat pakolnak bele, az üzemanyag szintje változik, azaz ez a paraméter nem időinvariáns, tehát a fizikai rendszer sem időinvariáns. Ugyanakkor tekinthetjük bizonyos feltételek mellett időinvariánsnak, ekkor a modell pontatlansága nő.

+

Állapot: Az állapot a memória jelleggel rendelkező dinamikai rendszerekben a múlt összesített hatása. A rendszer állapotának a következő két tulajdonsággal kell rendelkeznie +- Bármely T időpillanatban a kimenőjel az adott pillanatbeli állapot és bemenőjel együttes ismeretében egyértelműen meghatározható legyen. Kimeneti egyenletnek nevezzük azt az összefüggést, amely az állapotból és a bemenőjelből meghatározza a kimenőjeleket. +- Az állapot egy adott T időpillanatban egyértelműen meghatározható legyen a bemenőjel a t≤T időtartománybeli értékének ismeretében. Az állapot változását leíró egyenletet állapotegyenletnek nevezzük.

+

Állapotváltozó: Az állapotváltozók az állapot egyértelmű leírására szolgálnak. Az állapotváltozó lehet egy időfüggvény, az állapot mennyiségi változásainak leírására, illetve logikai változó az állapot minőségi váltásainak leírására.

+

Rendszer dimenzió: Egy rendszer állapotának egyértelmű leírásához minimálisan szükséges állapotváltozók számát a rendszer dimenziójának szokás nevezni.

+

Kanonikus állapotváltozók: Kanonikus állapotváltozónak nevezzük az állapotváltozók legkisebb olyan halmazának elemeit, amelyek segítségével az állapot egyértelműen leírható. A nem kanonikus állapotváltozókat származtatott állapotváltozóknak nevezzük.

+

Ljapunov-féle stabilitás: Egy nemlineáris autonóm működésű rendszert akkor mondunk Ljapunov értelemben stabilisnak, ha az egyensúlyi állapot bármely környezetéhez találunk egy olyan nullánál nagyobb maximális kitérítést, amelynél kisebb kitérítések esetén a rendszer garantáltan visszatér az eredetileg meghatározott környezetbe.

+

BIBO stabilitás: Korlátos bemenőjelre minden esetben korlátos kimenőjel a válasz. Ezt a feltételt teljesítő rendszert ismételten az angol név után BIBO (Bounded Input Bounded Output) stabilis rendszernek hívjuk.

+

Ezen fogalmak összessége elegendő a járműirányítási alapok megértéséhez. A szabályzási feladat sokszor két részre bontható: +- modellezés, az absztrakt matematikai modell elkészítése +- szabályzás, azaz a szabályzó megtervezése.

+

3.2. A szabályzási feladat megfogalmazása

+

A cél mindig a valós fizikai rendszer irányítása úgy, hogy az az előírt célértéknek megfelelően viselkedjen. Fontos, hogy minden célhoz meghatározzunk olyan mérhető mennyiségeket, amelyek alapján a szabályzás jóságát meg tudjuk határozni. A legtöbbször (de nem kizárólagosan) használt ilyen mennyiségek: +- beállási idő (gyorsaság) +- túllendülés mértéke +- állandósult állapotbeli hiba +- a szabályzás energiája.

+

A szabályzási láncot a 3. Ábrán látható módon írhatjuk fel. A következő jelöléseket használjuk:

+
    +
  • \(r(t)\): a célérték, avagy referenciajel
  • +
  • \(y(t)\): a visszacsatolt érték.
  • +
  • \(m(t)\): a valós rendszeren mért érték. Megjegyzés: sokszor az érzékelőt ideálisnak tekintjük, így \(y(t)=m(t)\), és így a visszacsatolt érték egyben az absztrakt rendszer kimenete.
  • +
  • \(e(t)\): hibajel, a szabályzó bemenete.
  • +
  • \(i(t)\): a szabályzó által meghatározott beavatkozó jel.
  • +
  • \(f(t)\): előrecsatolt ág.
  • +
  • \(u(t)\): a rendszer bemenete
  • +
  • \(d(t)\): külső zavarok.
  • +
+


+3. Ábra: a szabályzási lánc blokkdiagramja.

+

A szabályzó feladata, hogy a bemenetén keletkező hibát minimalizálja. A teljes szabályzási lánc feladata, hogy a valós fizikai rendszer kimenete a lehető legnagyobb pontossággal kövesse le a referencia jelet. +A következőkben egy egyszerű példán szemléltetjük egy rendszer modellezését, a zavarok hatását, továbbá példát adunk egy szabályzóra illetve az előrecsatolás lehetőségére. A példát MATLAB/Simulink környezetben készítettük el.

+

3.3. Példa a szabályzási alapokra

+

Ebben a példában egy egyszerű modellt fogunk felépíteni hogy szemléltessük a zárthurkú szabályzást. A feladat egy jármű sebességszabályzása. Ehhez a jármű egyszerű modelljét fogjuk elkészíteni. +1. Feladat: határozzuk meg a rendszer be- és kimeneteit! +A rendszerre a járműre ható gyorsító erővel szeretnénk hatni, ezért ez a bemenet. A kimenet a jármű sebessége, hiszen ezt szeretnénk egy adott célértékre szabályozni. Mivel ennek a rendszernek 1 be- és 1 kimenete van, ezért szokás SISO (Single Input Single Output) rendszernek is hívni. Ennek analógiáján léteznek MIMO (Multiple Inputs Multiple Outputs) rendszerek is. +Megjegyzés: a valóságban a járműre a gázpedállal és a fékpedállal hatunk, de ezek voltaképp a jármű gyorsulását befolyásolják, így az egyszerűség kedvéért a szakasz ezen részét nem modellezzük. Ezzel természetesen hibát viszünk a modellbe, de növeljük annak általánosságát.

+
    +
  1. Feladat: készítsük el a jármű matematikai modelljét / absztrakt modelljét! +Olyan egyenletrendszert keresünk, amely összeköti a be- és kimenetet. Itt meg kell határoznunk, mennyire törekszünk pontos modellre. Az egyszerűség kedvéért éljünk a következő megkötésekkel:
  2. +
  3. eltekintünk a hosszirányban fellépő kerékszliptől
  4. +
  5. eltekintünk az aktuátorok dinamikai viselkedésétől, azaz a kért gyorsulás egyből megvalósul
  6. +
  7. eltekintünk a mért mennyiségeket terhelő hibáktól, azaz a szenzorok pontatlanságától.
  8. +
  9. eltekintünk a futómű és a felfüggesztés dinamikai tulajdonságaitól.
  10. +
+

Az egyenletünk így egy koncentrált tömegpont lineáris mozgásává egyszerűsödik. A modellbe foglaljuk be a következő mennyiségeket: +- a jármű tömege +- a jármű légellenállása +- a jármű sebességarányos súrlódása.

+

Newton II. tételének megfelelően írjuk fel a következő dinamikai egyensúlyi egyenletet:
+$$ +\ddot I = \sum F +$$

+

Azaz:

+
\[ +m*\ddot v(t) = F_{prop}(t) - F_{aero}(t) - F_{fric}(t) +\]
+

Láthatjuk, hogy mind a bemenet, mind a kimenet szerepel az egyenletünkben, így valóban megtaláltuk a rendszer modelljét. Alakítsuk tovább, hogy csak a ki- és bemenet szerepeljen benne:

+
\[ +m*\ddot v(t) = F_{prop}(t) - \frac{1}{2}*v(t)^2*\rho*c*A - v(t)*b +\]
+

Ebben a formában az időben változó jelek a be- és kimenet (a sebesség illetve a hajtóerő), és vannak időben állandó (időinvariáns) paraméterek:

+
    +
  • \(\rho\): a levegő sűrűsége
  • +
  • \(A\): homlokfelület mérete
  • +
  • \(c\): jármű légellenállási együtthatója
  • +
  • \(b\): Coloumb-féle súrlódási tényező
  • +
+


+4. Ábra: a jármű modellezett erőegyensúlya

+

Ahhoz, hogy megkapjuk a sebességet, mint választott kimenet, meg kell oldanunk a differenciálegyenletet. Ezt Simulinkben numerikusan végezzük el. A megoldást az 5. Ábra mutatja.

+


+5. Ábra: a differenciálegyenlet numerikus megoldása.

+

A teljes szabályzási lánc blokkdiagramját a 6. Ábra mutatja. Ezen az ábrán nem használjuk a visszacsatolt ágat. A kezdő sebességet 20 m/s-ra állítottuk. A hajtóerő ez esetben nulla, így voltaképp a jármű tehetetlenségénél fogva gurul, és folyamatosan lassul a terheléssel arányosan.

+


+6. Ábra: a teljes szabályzási lánc blokkdiagramja.

+

A következő paraméter értékeket választottuk a szimulációhoz:

+
    +
  • \(A = 1.2m^2\)
  • +
  • \(b = 10 Ns/m\)
  • +
  • \(c = 0.4\)
  • +
  • \(\rho = 1 kg/m^3\)
  • +
  • \(m = 1250 kg\)
  • +
+

A 7. Ábrán látható a futtatás eredménye. 100s-ig futott a szimuláció, ez idő alatt 20 m/s-ról nagyjából 7 m/s-ra lassul a jármű.

+


+7. Ábra: a teljes szabályzási lánc blokkdiagramja.

+

A 8. Ábrán a visszacsatolt szabályzónak egy arányos szabályzót (P szabályzót) választunk, amely a hibával arányosan határozza meg a beavatkozó jelet. Az erősítést 100-ra választjuk, azaz 1 m/s sebességhiba 100N hajtóerőt eredményez. A kezdő sebesség 15 m/s, a célsebesség 20 m/s, így kezdetben 500N hajtóerőnk lesz.

+


+8. Ábra: arányos szabályzó, 100-as erősítéssel.*

+

A 9. Ábrán látható a szabályzó karakterisztikája, P szabályzóval, 100-as erősítéssel. A maradandó hiba relatíve nagy (több mint 10%). Ennek oka, hogy az arányos szabályzó a hibával arányos bemeneti jelet állít elő, és mivel a járműre hat ellentétes irányú erő, így a szabályzó ezzel fog egyensúlyt tartani. Amennyiben növeljük az erősítést, úgy csökken az állandósult állapotbeli hiba. Elméletben végtelen nagy erősítés nullára csökkenti ezt a hibát, viszont a végtelen erősítés végtelen beavatkozó jelet jelent, ami nem megvalósítható. A gyakorlatban ennél sokkal hamarabb elérjük a korlátokat, hiszen az aktuátorok csak véges erő kifejtésére képesek. Ezt a szabályzó megtervezésénél figyelembe kell venni.

+


+9. Ábra: arányos szabályzó karakterisztikája.

+

Az állandósult állapotbeli hibát úgy is eliminálhatjuk, ha az erősítés mellett egy olyan szabályzó tagot is hozzáadunk, ami "észre veszi", ha sokáig adott hiba áll fent, és növeli ennek megfelelően a beavatkozó jelet. Minél tovább áll fent a hiba, annál jobban növeljük a beavatkozó jelet. Ez gyakorlatilag a hiba időbeli integráljával arányos bevatkozó tagot jelent. Ezt szokás I tagnak nevezni. Az így kialakuló szabályzót pedig PI szabályzónak nevezni. A szabályzó elrendezését 10. Ábra mutatja, a kimeneti karakterisztikát a 11. Ábra. Láthatjuk, hogy a hiba valóban eltűnt, ugyanakkor a kezdeti tranziens szakasz is megváltozott. Megjelent a túllendülés, ezzel együtt a célérték körüli oszcilláció, továbbá a beállás is lassabb lett.

+


+10. Ábra: arányos szabályzó 100-as erősítéssel és integrátor, 10-es erősítéssel.

+


+11. Ábra: arányos szabályzó 100-as erősítéssel és integrátor, 10-es erősítéssel.

+

A fenti beállási oszcillációt és túllendülést javíthatjuk a paraméterek megváltoztatásával, illetve egy olyan szabályzó tag hozzáadásával, amely a hiba változására reagál. Ez gyorsítja a beállást, és a túllendülést is gyorsabban kompenzálja. Ez gyakorlatilag a hiba változásával arányos tagot jelent, ami egyenértékű a hiba deriváltjának figyelembevételével. Ezt a tagot szokás D tagnak nevezni, a kialakuló szabályzót PID szabályzónak nevezni. Ugyanakkor a D tag erősítését óvatosan kell megválasztani, mert könnyen instabillá teheti a rendszert. A szabályzó felépítését a 12. Ábra mutatja, a karakterisztikáját a 13. Ábra.

+


+12. Ábra: arányos szabályzó 100-as erősítéssel és integrátor, 10-es erősítéssel, D tag 10-es erősítéssel.

+


+13. Ábra: arányos szabályzó 100-as erősítéssel és integrátor 10-es erősítéssel, D tag 10-es erősítéssel.

+

Empirikus úton, figyelembe véve a túllendülés mértékét, a beállási időt és az állandósult állapotbeli hibát, válasszuk a következő paraméter értékeket:

+
\[ +P=175, +I=10, +D=50 +\]
+

Ezzel a beállás már nagyon szép, az eredményt a 14. Ábra mutatja.
+
+14. Ábra: arányos szabályzó, 170-es erősítéssel, I tag 10-es erősítéssel, D tag 50-es erősítéssel.

+

A 15. Ábrán látható, milyen hatása van, ha hozzádunk egy 3°-os lejtő által keltett extra gyorsító erőt. A túllendülés nagyobb lesz, hiszen a szabályzót egy olyan modellel állítottuk be, amely sík talajon mozgó autót feltételez.

+


+15. Ábra: lejtő hatása a zárt hurkú szabályzóra.

+

Ezt kompenzálhatjuk, ha a lejtővel arányos előrecsatolt ágat alkotunk meg. Azonban a lejtő becslése nehéz, általában a jármű mozgása alapján következtethetünk rá, ami így csak késve jelzi a lejtő mértékét. Adjunk hozzá egy 1 s-mal eltolt, 5%-os hibával rendelkező lejtőkompenzációt. A blokkdiagramot a 16. Ábra, az eredményt a 17. Ábra mutatja.

+


+16. Ábra: előrecsatolt ággal kiegészített szabályzó rendszer.

+


+17. Ábra: előrecsatolt ág hatása a szabályzóra.

+

3.4 Interaktív PID hangolás

+

A következőkben a egy másik szabályozási példa (hőmérséklet szabályozás) interaktív PID hangolását lehet megtenni:

+ + +

Ez az interaktív vizualizáció Mario Theers - CC BY 4.0 License megoldása.

+

Hasonló interaktív vizualizáció érhető el a Viktor.ai oldalon, de itt még hangolni is van lehetőségünk: cloud.viktor.ai/public/control-application

+

Összegzés

+

Ebben a fejezetben áttekintettük a szabályzástechnikai alapfogalmakat, példákat hoztunk a járműirányítás területéről. Ezen kívül a gyakorlatban megalkottunk egy egyszerű matematikai modellt, amely leírja egy jármű, mint tömegpont hosszirányú mozgását. Ezen keresztül MATLAB/Simulink segítségével sebességszabályzással kapcsolatos szimulációt végeztünk. Az egyik legelterjedtebb szabályzót, a PID szabályzót mutattuk be. +A következő pontokat érdemes megjegyezni: +- egy zárthurkú szabályzás általában áll a szabályzott szakaszból (mely a valós fizikai rendszer absztrakt matematikai modellje) és a szabályzóból. +- a valós fizikai rendszert matematikai modellel írjuk le, amely alapján tervezhető a szabályzó is. A modell pontossága befolyásolja a megtervezett szabályzó minőségét is. +- a matematikai modell általában differenciálegyenletek formájában áll elő. +- a PID szabályzók a hiba minimalizálására törekednek. A P tag gyorsítja a rendszert, az I tag eltünteti a maradandó hibát, a D tag szintén gyorsítja a szabályzó reakcióját, de instabilitást is okozhat. +- a valóságban a járműszabályzás összetett, a változó paraméterek (pl. autó tömege), az útviszonyok illetve az egymásba ágyazott szabályzó hurkok miatt.

+

4. Járműirányítási megoldások

+

A járműszabályzás területén - ahogy azt a 2. alfejezetben láttuk - több, egymásba ágyazott szabályzó kört használunk. Mindegyik jellemzően tartalmaz egy előre csatolt és egy visszcsatolt ágat. Automatizált vezetési rendszerek esetén általában a legfelső, ún. járműszintű irányítást szoktuk legelőre venni. Az alacsonyabb szintű szabályzókra most nem térünk ki, csupán egy lista erejéig összegezzük őket. Meg kell jegyezni, hogy ezek az alacsonyszintű szabályzók nagyban függnek a járműben elérhető aktuátoroktól, hiszen többféle fékrendszer, hajtás és kormányrendszer is elérhető lehet. Ez a felosztás nagyban támogatja moduláris tervezést, azaz a járműszintű szabályzást függetlenül tudjuk fejleszteni az alacsony szintű szabályzásoktól. Ez pl. sorozatgyártott szoftverek esetén nagyban megkönnyíti az újrahasznosíthatóságot. Az alacsony szintű, aktuátor szabályzó hurkok a következők lehetnek (a teljesség igénye nélkül): +- kormány szervó motor szögszabályzás +- kormány szervó motor nyomatékszabályzás +- motor nyomaték szabályzás +- fék erő szabályzás (fék nyomás szabályzás).

+

Innentől minden megállapítás a jármű szintjére vonatkozik. Fontos megjegyezni, hogy mindig két dimenzióban gondolkodunk: hosszirányú és keresztirányú szabályzásban. A hosszirányú szabályzásra láttunk példát a 3. alfejezetben. Ez általában a sebesség szabályzását, esetleg a gyorsulás szabályzását jelenti. Habár a hosszirányú szabályzás is rejt nem levés kihívást (a motor tehetetlensége, a fék- és hajtóerők szétválasztása...stb.), a legtöbb járműirányítási megoldás elsősorban a keresztirányú szabályzásra összpontosít. +Mivel a jármű automatikus irányítási feladata nagyban hasonlít az emberek vezetési feladatához (tehát a kormány és a pedálok segítségével a jármű mozgásának befolyásolása), ezért szokás ezeket az irányítási megoldásokat vezetői modelleknek (angolul driver models) is hívni. Az egyes modellekről rövid összefoglalókat találunk az ajánlott irodalom alatt. Ezek közül [1] szerint 3 csoportra oszthatjuk a vezetői modelleket: +- Inverz-modellek (inverse models) +- Prediktív modellek (predictive/forward models) +- Zárhurkú modellek (closed loop models).

+

+18. Ábra: járműirányítási megoldások szemléltetése.

+

Inverz modellek

+

Az inverz modelleket angol terminológiában pursuit modelleknek is szokás hívni, amely a legjobban talán előre tekintő, előre tolónak lehet fordítani. A lényege, hogy a kormányzáshoz szükséges célértéket az két információ alapján határozza meg: +- egy előretekintési pontban mi a jármű célállapota? +- a járműről előzetesen felállított modell. +Ezt felfoghatjuk úgy is, mint egy előrecsatolt szabályzási ág, avagy egy nyílthurkú szabályzás, azaz vezérlés. Amennyiben ez utóbbi áll fent (azaz nincs visszacsatolt ág), azt nevezzük tisztán előre tekintő, ismertebb angol nevén pure-pursuit irányításnak.

+
+

Warning

+

A pure-pursuit megoldás az egyik legrégebbi irányítási megoldás a járművek terén. Már az 1980as években a Robotics Institute of Pittsburgh fejlesztette ki [4]. A lényege, hogy egy megadott előretekintési távolságban (ami az irányítás legfontosabb paramétere) meghatározzuk a jármű kívánt pozícióját (pl. a korábban tervezett trajektória alapján).

+
+

Ennek a pontnak a koordinátái alapján meg tudjuk határozni, milyen görbületű köríven kell haladnunk ahhoz, hogy az aktuális pontból a célpontba érjünk. Fontos, hogy a pure-pursuit megoldás mindig köríveket használ. A geometriai összefüggéseket a 19. Ábra szemlélteti. +Egyszerű trigonometriai megfontolások alapján a következő összefüggést írhatjuk fel az előretekintési pont és a célgörbület között:

+
\[ +\kappa_{target}=\frac{2x}{l^2} +\]
+

Mint látjuk, a jármű szintjén megfogalmaztunk egy mennyiséget (görbület) a bemeneti trajektória alapján, így elméletben teljesítettük a járműirányítás fő feladatát. Azonban a megvalósítás során általában olyan mennyiséget állítunk elő, amely már az aktuátorok szintjén értelmezhető. Ehhez használjuk a jármű modelljét: összefüggést adunk meg a célgörbület és kormányszög között. A leggyakrabban a jármű kinematikai bicikli modelljét használjuk, azonban ez nagyobb sebességek esetén (>10 km/h) nagyon pontatlan. A kinematikai bicikli modell összefüggéseit felhasználva megkaphatjuk a kormányszöget:

+
\[ +\delta_f=atan(L_w*\kappa) +\]
+

Ahol \(L_w\) a jármű tengelytávja.

+

Feltételezzük a modellben, hogy a jármű elsőkerék-kormányzású. A kapott szög az út-kerék szög, amely a kormánymű geometriájának függvényében átszámítható pl. szervó motor szöggé, és így közvetlenül megvalósítható.

+

+ +19. Ábra: a pure pursuit szabályzó geometriai összefüggései.

+

A 20. Ábrán láthatjuk, milyen hatással van az előretekintési távolság a jármű viselkedésére. Amennyiben túl közeli pontot választunk, a jármű hajlamos oszcillációra (ez hasonló hatás, mint egy PID szabályzó túl nagy P erősítéssel). A túl nagy előretekintési távolság esetén a reakció lassul, de pl. élesebb kanyarokban a jármű hajlamos lesz kanyarlevágásra. +Szokás az előretekintési távot adaptívan, pl. a sebesség függvényében megadni. Ilyenkor gyakorlatilag előretekintési időről beszélünk.

+

+ +

+

20. Ábra: a pure pursuit előretekintési távolságának hatása a jármű viselkedésére

+

A pure-pursuit modellek továbbfejlesztett változatairól pl. a [2] és [3] cikkben olvashatunk.

+

Prediktív modellek

+

A prediktív modellek, hasonlóan a az inverz modellekhez a jármű modelljén alapszanak. Azonban egyúttal előre is tekintenek egy meghatározott horizonton: a modell segítségével becsüljük a jármű viselkedését előre, majd ennek függvényében a lehető legjobb megoldást választjuk a jelenben. Tehát ez esetben a jövő valamilyen pontosságú információit felhasználva hozunk döntést. Itt két esetet különböztetünk meg: +- receding horizon: azaz a jövőbeli horizont folyamatosan tolódik előttünk, mivel a megtervezett jövőbeli viselkedésnek mindig az első elemét hajtjuk csak végre, ezek után újratervezünk +- proceeding horizon: a horizont közeledik felénk, azaz a jövőbeli megtervezett viselkedést teljes egészében végrehajtjuk, és csak ez után tervezünk újra.

+

Mivel a szabályzás itt egyben egy mozgástervezést is jelent, így a tervezés eszköztárát is használnunk kell. Ezeket a szabályzókat szokás Optimális szabályzóknak, angolul Optimum controlsnak is hívni. Hiszen ebben az esetben az előretekintési horizonton a modell segítségével megtervezzük azt a mozgást, amely a legkisebb költséget eredményezi a megadott szempontok szerint. Itt visszautalunk a 3.2. alfejezet elején bevezetett szempontokra: +- beállási idő (gyorsaság) +- túllendülés mértéke +- állandósult állapotbeli hiba +- a szabályzás energiája.

+

Mivel itt egy véges hosszúságú időhorizonton szeretnénk az optimális mozgást megtervezni, a fenti szabályzó szempontok közül a beállási időt, a túllendülés mértékét továbbá az állandósult állapotbeli hibát egy vektorba vonjuk össze és ezen vektor elemeinek összegét szeretnénk minimalizálni (1. kritérium). +A szabályzás energiája voltaképp a beavatkozó jel vektorának amplitúdójával van összefüggésben. Azaz úgy szeretnénk elérni minél jobb eredményt, hogy közben alacsony jellel hatunk a rendszerre (pl. minél kevésbé szeretnénk gyorsulni, vagy a kormányra nyomatékot kifejteni...stb.). Ez a 2. kritérium, amely ellentétes igényt jelent a szabályzásra nézve, mint az 1. kritérium.

+

Ezeket a szabályzókat szokás Modell Prediktív Szabályzóknak (Model Predictive Controls, MPC) is hívni. A következő egyenlet egy példa arra, hogyan írhatjuk fel a megoldandó költségfüggvényt:

+
\[ +J(k)=\sum_{i=1}^{N_p}\|y(k+i)-y_{ref}(k+i)\|^2_M + \sum_{i=1}^{N_c-1}\|\Delta U(k+i)\|^2_N +\]
+

Ahol:

+
    +
  • \(N_p\): a predikciós horizont, számítási ciklusban kifejezve (a modell figyelembe vétele)
  • +
  • \(k\): az akutális számítási ciklus
  • +
  • \(y(k+i)\): az \(i.\) ciklusban a modell által becsült jármű keresztirányú pozíció
  • +
  • \(y_{ref}(k+i)\): az \(i.\) ciklusban a referencia pozíció (cél pozíció)
  • +
  • \(N_c\): a szabályzási horizont (a bemenet figyelembe vétele)
  • +
  • \(\Delta U\): a bemeneti vektor növekmény a szabályzási horizonton
  • +
  • \(M\) és \(N\): a súlymátrixok a hibára és a bemeneti energiára.
  • +
+

Ilyen szabályzókra találunk példát [1], [5-7] irodalmakban. +Az MPC-k előnye, hogy nagyon nagy pontossággal, stabil szabályzást adnak, amennyiben az alkalmazott modell nagy pontosságú. Ugyanakkor ez is a hátránya, hiszen ha a modell nem megfelelő, akkor a hiba exponenciálisan elnőhet. +Erre látunk példát a 21-23. Ábrán. Mindegyik szimulációban egy kinematikai bicikli modellt használtunk az MPC megtervezéséhez. A PID szabályzó a pozícióhibát minimalizálja. A szimulációban a jármű dinamikai modelljét alkalmaztuk, mint valós fizikai rendszer. Látható, hogy 5 m/s-on az MPC egyértelműen jobban teljesít, mint a PID szabályzó, sokkal pontosabb és stabilabb is. Azonban 2 m/s-on az MPC szétesik, az alacsony sebesség miatt a modell összefüggések nem lesznek érvényesek. Hasonló figyelhető meg a 23. Ábrán is. +A 22. Ábrán azt látjuk, hogy 10 m/s-ig az MPC és a PID is jól teljesít, az MPC továbbra is jobb, mint a PID. Azonban 10 m/s felett a dinamikai hatások felerősdnek, és a kinematikai modell nem megfelelő. Így az MPC instabillá válik, míg a PID - bár jelentős hibával - továbbra is stabil működésre képes.

+


+21. Ábra: MPC és PID szabályzó összevetése, kinematikai modell esetén, kanyarodás, alacsony sebességeken

+


+22. Ábra: MPC és PID szabályzó összevetése, kinematikai modell esetén, kanyarodás, magasabb sebességeken

+


+23. Ábra: MPC és PID szabályzó összevetése, kinematikai modell esetén, körpálya, alacsony sebességeken

+

Zárthurkú modellek

+

Az ilyen típusú modellek, ahogy a neve is sugallja, a PID szabályzók logikáján alapszanak. Jellemzően egy vagy több visszacsatolt mennyiség hibáját minimalizálják. Ilyen modellekre találunk példát a [3] és [8] irodalomban. +A 24. Ábrán a [3]-ban bemutatott példa illusztrációját látjuk. Eszerint kijelölünk kettő előretekintési pontot: egy közelit (a jármű előtt) és egy távolit (a horizonton). Hasonlóan a pure-pursuit megoldásokhoz, itt is azt vizsgáljuk, hogyan juthatunk el a jelenlegi pozícióból a távoliba. Azonban nem egy egyszerű görbületszámolással, hanem a hiba minimalizálásával érjük ezt el, a következő egyenlet szerint:

+
\[ +\phi=k_f\dot\Theta_f + k_n\dot\Theta_n + k_i\Theta_n +\]
+

Ahol:

+
    +
  • \(\dot\Theta_f\) és \(\dot\Theta_n\) a távoli és a közeli pont hozzánk viszonyított irányának megváltozása (szögsebessége)
  • +
  • \(\Theta_n\) a közeli pont iránya hozzánk képest (szöge)
  • +
  • \(k\) tagok: súlyok.
  • +
  • \(\phi\): az út kerék szög.
  • +
+

Ez az egyenlet felírás voltaképp egy minimalizálása a szög hibáknak, hiszen a cél, hogy mindig irányba álljunk. A visszacsatolás a környezet érzékelésből jön. A kimenet az út kerék szög.

+

+

24. Ábra: a dual-point irányítási megoldás szemléltetése

+

A 25. Ábrán a [8]-ban ismertetett megoldást látjuk. A lényege, hogy több egymásba ágyazott PID szabályzó segítségével a pozíció hibát minimalizálja. Ehhez a szabályzási feladatot szétbontja egy alacsony frekvenciás szabályzásra (pozíció hiba) és egy magasfrekvenciás szabályzásra (kormányszög hiba). Az átviteli függvények egy-egy szabályzót testesítenek meg, sorban a következőket jelentik:

+
    +
  • \(G_c\): a pozíció szabályzása egy PI szabályzóval
  • +
  • \(G_L\): az emberi szabályzás késése (reakcióideje)
  • +
  • \(G_NM\): a neuromotoros szabályzás, ahogyan az emberek a kormányt mozgatják. Ennek dinamikája nagyban függ az emberek izomszerkezetétől.
  • +
  • \(G_{P1}\) és \(G_{P2}\): a visszacsatolásba illesztett érzékelő modellek. Ezek reprezentálják az ember érzékelési dinamikáját, sorban a kormányon lévő nyomaték és a kormány szög tekintétben.
  • +
+

+

26. Ábra: egy teljes zárthurkú szabályzó, egyesítve a kormányszög szabályzással

+

Összefoglalás

+

Mint láttuk a vezetői modellek minden esetben egy korábban megtervezett trajektóriát igényelnek. Ennek lekövetésére használjuk a szabályzókat, amelyek a következő három csoportba oszthatók:

+
    +
  • Inverz-modellek (inverse models)
  • +
  • Prediktív modellek (predictive/forward models)
  • +
  • Zárhurkú modellek (closed loop models).
  • +
+

A legrégebbi inverz-modellek a legegyszerűbbek és robosztusabbak, azonban a teljesítményük jellemzően alacsony. A prediktív modellek nagyon pontosak, ugyanakkor nagyon érzékenyek a modell pontosságára. A zárthurkú modellek nagy tartományon stabilak, ugyanakkor általános pontosságuk alacsony. Több egymásba ágyazott hurokból állnak, melyek kalibrációja általában belülről kifelé történik. Ezek a legelterjedtem a mai sorozatgyártott rendszerekben.

+

Ajánlott irodalom

+
    +
  1. Introduction: System Modeling, University of Michigan
  2. +
  3. Interactive Live Script Control Tutorials for MATLAB and Simulink
  4. +
  5. Mario Theers - PID - CC BY 4.0 License
  6. +
  7. Mario Theers - Pure pursuit - CC BY 4.0 License
  8. +
  9. Youtube ControlLectures
  10. +
  11. Bokor József & Gáspár Péter. Irányítástechnika
  12. +
+

Vezetői modellek

+
    +
  1. A. Y. Ungoren and H. Peng, "An Adaptive Lateral Preview Driver Model," Vehicle System Dynamics, vol. 43, pp. 245-259, 2005.
  2. +
  3. W. Rui, L. Ying, F. Jiahao, W. Tan and C. Xuetao, "A Novel Pure Pursuit Algorithm for Autonomous Vehicles Based on Salp Swarm Algorithm and Velocity Controller," IEEE Access, vol. 8, pp. 166525-166540, 2020.
  4. +
  5. D. Salvucci and R. Gray, "A Two-Point Visual Control Model of Steering," Perception, vol. 33, pp. 1233-1248, 2004.
  6. +
  7. C. R. Coulter, "Implementation of the Pure Pursuit Path Tracking Algorithm," Vols. CMU-RI-TR-92-01, pp. 1-15, 1992.
  8. +
  9. H. Jiang, H. Tian and Y. Hua, "Model predictive driver model considering the steering characteristics of the skilled drivers," Advances in Mechanical Engineering, vol. 11, pp. 1-14, 2019.
  10. +
  11. U. Kiencke, R. Majjad and S. Kramer, "Modeling and performance analysis of a hybrid driver model," Control Engineering Practice, vol. 7, pp. 985-991, 1999.
  12. +
  13. C. MacAdam, "An Optimal Preview Control for Linear Systems," Journal of Dynamic Systems, Measurement and Control, vol. 102, pp. 188-190, 1980.
  14. +
  15. R. Hess and A. Modjtahedzadeh, "A Control Theoretic Model of Driver Steering Behavior," IEEE Control Systems Magazine, vol. 5, no. 8, pp. 3-8, 1990.
  16. +
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szabalyozas/pid_plot01.png b/szabalyozas/pid_plot01.png new file mode 100644 index 0000000..34315aa Binary files /dev/null and b/szabalyozas/pid_plot01.png differ diff --git a/szabalyozas/pid_plot02.png b/szabalyozas/pid_plot02.png new file mode 100644 index 0000000..26e7b62 Binary files /dev/null and b/szabalyozas/pid_plot02.png differ diff --git a/szabalyozas/pid_plot03.png b/szabalyozas/pid_plot03.png new file mode 100644 index 0000000..5cd75d3 Binary files /dev/null and b/szabalyozas/pid_plot03.png differ diff --git a/szabalyozas/ros1practice/index.html b/szabalyozas/ros1practice/index.html new file mode 100644 index 0000000..4e59947 --- /dev/null +++ b/szabalyozas/ros1practice/index.html @@ -0,0 +1,2539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ROS1 Gyakorlat - Szabályozás - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Gyakorlat

+

A gyakorlaton a robotverseny szimulációt fogjuk használni. A szimulátor linkenlt leírás alapján telepíthető.

+

Melodic

+

Noetic

+

Sebességszabályzó PID hangolása

+

A következő paranccsal egy üres (akadályok nélküli) szimuláció indul. Ez a PID sebességszabályzó hangolására alkalmas.

+
roslaunch racecar_gazebo racecar_empty.launch
+
+
roslaunch racecar_control cmd_vel_from_file.launch
+
+

Szükségünk lesz referencia jelek kiadására, megismételhető módon. Ezt a példában egy csv beolvasása, majd /cmd_vel topicon hirdetése jelenti. Vizsgáljuk meg a python fájlt. A topic hirdetése, a node ROS-ben történő regisztrálása, a csv fájl beolvasása a fájl elején található:

+
cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
+rospy.init_node('cmd_vel_from_file', anonymous=True)
+rate = rospy.Rate(10) # 10hz
+msg_twist = Twist()
+csv_file = rospy.get_param('~csv')
+rospack = rospkg.RosPack()
+path = rospack.get_path('racecar_control')
+rospy.loginfo('csv file is: %s/config/%s' % (path, csv_file))
+array = pd.read_csv(path + '/config/' + csv_file, header = None).to_numpy()
+start_time = rospy.Time.now()
+
+

A folyamatosan futó loop /cmd_vel.linear.x jeleket hirdet, a csv-ben található idő szerint. A np.where visszaadja, hogy az aktuális idő szerint (current_time) milyen sebesség indexnél (itemindex) tartunk. Ez egy 2D array, ami minden, a feltételnek megfelelő indexet tartalmaz, de számunkra persze csak ennek az első eleme a fontos, ezt fogjuk hirdetni.

+
while not rospy.is_shutdown():
+    current_time = (rospy.Time.now() - start_time).to_sec()
+    itemindex = np.where(array[:,0] >= current_time)
+    try:
+        msg_twist.linear.x = array[itemindex[0][0],1]
+    except:
+        msg_twist.linear.x = 0.0
+    cmd_pub.publish(msg_twist)
+    rate.sleep()
+
+

A roscd parancs segítségével lépjünk a racecar_control package config mappájába.

+
roscd racecar_control/config/
+
+

Ez valószínűleg a ~/sim_ws/src/racecar_gazebo/f1tenth/virtual/dependencies/racecar_control/config helyen található, de elképzelhtő, hogy valaki máshova telepítette.

+

Innen betölthetünk különböző PID beállításokat, pl:

+
rosparam load racecar_control01.yaml
+rosparam load racecar_control02.yaml
+rosparam load racecar_control03.yaml
+
+

Ellenőrizzük a get paranccsal, a következőhöz hasnonló eredményt fogunk kapni:

+
rosparam get /racecar/left_rear_wheel_velocity_controller/pid/
+{antiwindup: false, d: 0.0, i: 0.0, i_clamp: 0.0, i_clamp_max: 0.0, i_clamp_min: -0.0,
+  p: 5.0}
+
+
+

Note

+

Alternatívaként használhatjuk a rosrun rqt_reconfigure rqt_reconfigure parancsot is.

+
+

Futtassuk a következő parancsot a sebesség referencia kiadására: +

roslaunch racecar_control cmd_vel_from_file.launch
+
+A launch fájlba megadhatjuk, hogy pl a 01.csv, 02.csv stb fájlt töltse-e be. Többször futtathatjuk, akár más PID beállítások mellett is.

+

Figyeljünk meg két topicot pl Foxglove segítségével, különböző PID beállítások mellett: +- /racecar/left_rear_wheel_velocity_controller/state.process_value +- /racecar/left_rear_wheel_velocity_controller/command.data

+

Alt text

+

Kormányzás PID hangolása

+

A következő parancsra, már nem üres, hanem egy körbekerített versenypálya nyílik meg.

+
roslaunch racecar_gazebo racecar.launch
+
+

A pálya a következőképp néz ki:

+

+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szabalyozas/ros2practice/index.html b/szabalyozas/ros2practice/index.html new file mode 100644 index 0000000..20dd39e --- /dev/null +++ b/szabalyozas/ros2practice/index.html @@ -0,0 +1,3346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - szabályozás - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Gyakorlat

+

A gyakorlat első részében egy példa első illetve másodrendű rendszert fogunk használni, erre fogunk PID szabályzót alkalmazni, majd hangolni. +A gyakorlat második részében egy szimulált trajektóriakövető robot / jármű működését nézzük át és hangoljuk.

+

Static Badge

+ +

1. feladat: Trajektóriakövetés szimulációval

+

+

github.com/jkk-research/sim_wayp_plan_tools

+

Követelmények

+

A gyakorlat hibamentes lefutásához a következő programok telepítése szükséges: +- ROS 2 Humble: docs.ros.org/en/humble/Installation.html +- Gazebo Fortress: gazebosim.org/docs/fortress/install_ubuntu, Több információ az integrálásról: gazebosim.org/docs/fortress/ros2_integration +- ros-gz-bridge Egy parancsal installálható: sudo apt install ros-humble-ros-gz-bridge +- Ellenőrizük, hogy a colcon_cd megfelelően van telepítve. A csv fájlok a colcon_cd-vel töltődnek be.

+

Package-ek és build

+

Az alapértelmezett workspace a következő legyen:~/ros2_ws/.

+

Klónozuk le a package-eket

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/jkk-research/wayp_plan_tools
+
+
git clone https://github.com/jkk-research/sim_wayp_plan_tools
+
+

ROS 2 -es package-ek buildelése

+

cd ~/ros2_ws
+
+
colcon build --packages-select wayp_plan_tools sim_wayp_plan_tools
+

+

wayp_plan_tools használata szimulátorként

+

1.1. A gazebo indítása

+
ign gazebo -v 4 -r ackermann_steering.sdf
+
+

1.2. A Gazebo bridge indítása

+

Ha esetleg nem lenne telepítve a bridge, a következő parancsok segítenek: +

sudo apt update
+

+
sudo apt install ros-humble-ros-gz -y
+
+

Tanteremben pedig:

+
cd /mnt/kozos/script
+
+
./gz_bridge.sh
+
+

Ne felejtsünk el source-olni az ROS-es parancsok előtt.

+
source ~/ros2_ws/install/local_setup.bash
+
+
ros2 launch sim_wayp_plan_tools gazebo_bridge.launch.py
+
+

Ez a launch fájl a következő node-okat indítja el egyben:

+

ros2 run ros_gz_bridge parameter_bridge /world/ackermann_steering/pose/info@geometry_msgs/msg/PoseArray[ignition.msgs.Pose_V
+
+
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist
+
+
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry --ros-args -r /model/vehicle_blue/odometry:=/odom
+
+Több információ a bridge-ről: github.com/gazebosim/ros_gz/blob/ros2/ros_gz_bridge/README.md

+

Ez a launch a PoseArray-ből egy /tf-et is készít a pose_arr_to_tf.

+

Opcionális: A gazebo-ban lévő robot irányítása billentyűzettel:

+
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/model/vehicle_blue/cmd_vel
+
+

1.3. Waypointok betöltése

+

Megjegyzés: A waypointok egy ponthalmaz, amely az útvonal pozíció, orientáció és sebesség adatait tartalmazza diszkrét pontokra osztva. Ezeket az adatokat jellemzően úgy nyerjük ki hogy az útunk során ROS-ben rögzítjük a gps-től vagy az odometriától az x,y esetleg z koordinátákat, az aktuálishoz képest a következő pontra mutató orientációt és az éppen aktuális sebesség adatot. Végül az imént felsoroltakat csv fájlokban rögzítjük.

+

Használjuk a ROS 2-es workspacet file_dir-ként: +

ros2 run wayp_plan_tools waypoint_loader --ros-args -p file_name:=sim_waypoints1.csv -p file_dir:=$HOME/ros2_ws/src/sim_wayp_plan_tools/csv -r __ns:=/sim1
+
+Vagy az alapparaméterekel:

+
ros2 launch sim_wayp_plan_tools waypoint_loader.launch.py
+
+

1.4. Waypoint goal pose-ként

+

Ahogy az elméleti rész 4. fejezetben az ábrákon látható, minden szabályozási algoritmushoz tartozik egy vagy több goal pose amire az éppen működő szabálzó szabályoz.

+

ros2 run wayp_plan_tools waypoint_to_target --ros-args -p lookahead_min:=2.5 -p lookahead_max:=4.5 -p mps_alpha:=1.5 -p mps_beta:=3.5 -p waypoint_topic:=waypointarray -p tf_frame_id:=base_link -p tf_child_frame_id:=map -r __ns:=/sim1
+
+Vagy az alapparaméterekel:

+
ros2 launch sim_wayp_plan_tools waypoint_to_target.launch.py
+
+

1.5. A szabályzás indítása:

+

Több lehetőség van: +- single_goal_pursuit: Pure pursuit (for vehicles / robots), a simple cross-track error method +- multiple_goal_pursuit: Multiple goal pursuit for vehicles / robots an implementation of our paper +- stanley_control: Stanley controller, a heading error + cross-track error method +- follow_the_carrot: Follow-the-carrot, the simplest controller

+

Egy példa a pure pursuit-ra :

+

ros2 run wayp_plan_tools single_goal_pursuit --ros-args -p cmd_topic:=/model/vehicle_blue/cmd_vel -p wheelbase:=1.0 -p waypoint_topic:=targetpoints -r __ns:=/sim1
+
+Vagy az alapparaméterekel:

+
ros2 launch sim_wayp_plan_tools single_goal_pursuit.launch.py
+
+

1.6. Az eredmények vizualizálása RViz2-ben:

+

ros2 launch sim_wayp_plan_tools rviz1.launch.py
+
+Vagy futtasunk mindent együtt egyetlen parancsal:

+

After ign gazebo -v 4 -r ackermann_steering.sdf (terminal 1) and source ~/ros2_ws/install/local_setup.bash (terminal 2), run this command (also in terminal 2): +

ros2 launch sim_wayp_plan_tools all_in_once.launch.py
+

+

Hibaelhárítás

+

A ign gazebo server leállítása:

+
ps aux | grep ign
+
+
ab  12345 49.9  1.2 2412624 101608 ?      Sl   08:26  27:20 ign gazebo server
+ab  12346  518  6.6 10583664 528352 ?     Sl   08:26 283:45 ign gazebo gui
+ab  12347  0.0  0.0   9396  2400 pts/2    S+   09:21   0:00 grep --color=auto ign
+
+

Ha azonosítva van a PID a folyamat leállításához használd a kill parancsot. Például a gazebo szerver leállításához:

+
kill 12345
+
+

2. feladat: Saját fejlesztésű szabályzó és jármű modell

+

Ebben a feladatban elkészítjük az elméleten bemutatott sebesség szabályzót, és az ahhoz kapcsolódó egyszerű járműmodellt.

+

Ha ezt eddig nem tettük meg, frissítsük az arj_packages repository-t:

+
git pull
+
+

Navigáljunk a workspace src mappájában a repo gyökérmappájába:

+
cd ~ros2_ws/src/arj_packages
+
+

Vizsgáljuk meg a repository tartalmát:

+

dir
+
+Látjuk, hogy megjelent egy speed_control_loop nevű almappa. Ez a mappa tartalmazza a szabályzáshoz használt járműmodellt és a szabályzót. Nyissuk meg a forráskódot VS Code segítségével.

+

+

A mappa tartalmazza a szokásos package xml-t és a CMakeList-et, továbbá két cpp forrásfájlt. A vehicle_model.cpp értelemszerűen a járműmodellt, a speed_controller.cpp a szabályzót tartalmazza. Vizsgáljuk először a jármű modell forráskódját!

+

Járműmodell

+
class VehicleModel : public rclcpp::Node
+{
+public:
+    VehicleModel() : Node("vehicle_model")
+    {
+        timer_ = this->create_wall_timer(std::chrono::milliseconds(200), std::bind(&VehicleModel::loop, this));  
+        state_pub_ = this->create_publisher<std_msgs::msg::Float32MultiArray>("/vehicle/state", 10);
+        cmd_sub_ = this->create_subscription<std_msgs::msg::Float32>("/vehicle/propulsion", 10,  std::bind(&VehicleModel::propulsion_callback, this, std::placeholders::_1));
+        RCLCPP_INFO(this->get_logger(), "vehicle_model has been started");
+    }
+
+

A szokásos #include-ok és névdefiníciók után a járműmodell osztály konstruktora látható. A node neve "vehicle_model". Egy topic-ra iratkozunk fel, a /vehicle/propulsion nevűre, amely a nevéből is adódódan a járműre ható hajtóerőt adja meg. Ezen kívül hirdetjük a /vehicle/state nevű topicot, mely megadja a jármű mozgásállapotát.

+

Ezt követően definiálunk néhány változót. +1. Először egy lokális változót, melyben a bemeneti erőt tároljuk el. +2. Ezt követi egy tömb, mely tartalmazni fogja a jármű sebességét és gyorsulását, a két állapotváltozót, melyekkel a jármű állapotát leírjuk. +3. Definiálunk egy Fload nevű változót, amelyben megadhatjuk, milyen extra terhelések hassanak a járműre. +4. Végül definiálunk néhány nem változtatható paramétert, pl. a jármű súlyát, homlokfelületének nagyságát...stb.

+
private:
+    // input command
+    float Fprop {0.0f};
+
+    // vehicle state array
+    std::vector<float> state; //speed, acceleration
+    float vx{0.0f};
+    float ax{0.0f};
+
+    // load
+    float Fload{0.0f};
+
+    // params
+    float m {1350.0}; // kg
+    float A {1.5f}; // m^2
+    float rho {1.0f}; // kg/m^3
+    float c {0.33f}; // aerodynamic factor
+    float b {0.1f}; // rolling friction, viscosous
+
+

A topic callback függvény kizárólag a bejövő adatot másolja a lokális változónkba.

+
void propulsion_callback(const std_msgs::msg::Float32 input_msg)
+{
+    Fprop = input_msg.data;
+}
+
+

Végezetül a loop() függvény, melyben először számítjuk az ellenállási erőket (légellenállás és viszkózus súrlódás), majd számítjuk az eredő erőt és ebből a jármű gyorsulását. A jármű gyorsulását integrálva kapjuk a jármű sebességét.

+
void loop()
+{
+    // calculate new state based on load, prop force, mass and aerodynamic drag
+    float Faero = 0.5*A*rho*c*pow(vx,2);
+    float Ffric = b*vx;
+    ax = (Fprop - Ffric - Fload - Faero)/m;
+    vx = std::max(0.0f, vx + ax*0.1f); // 0.1s is the time step of the model
+
+    // Publish state
+    state.clear();
+    std_msgs::msg::Float32MultiArray state_msg;
+    state.push_back(vx); // m/s
+    state.push_back(ax); // m/s^2
+
+    state_msg.data = state;
+    state_pub_->publish(state_msg);
+}
+
+

Szabályzó

+

A speed_control.cpp-ben a jármű sebességének PID szabályzását láthatjuk. +A node neve "speed_control", feliratkozik a /vehicle/state topicra, melyet a jármű modell hirdet. +Ezen kívül hirdetjük a /vehicle/propulsion command topicot, egyúttal feliratkozunk a /vehicle/cmd célsebességet megadó topicra. +A szabályzó lényege, hogy a user által megadott sebességet szabályozza úgy, hogy előállítja a járműhajtás számára a célerőt. A modell állapotától függően növeljük vagy csökkentjük a célerőt.

+
class SpeedControl : public rclcpp::Node
+{
+public:
+    SpeedControl() : Node("speed_control")
+    {
+        timer_ = this->create_wall_timer(std::chrono::milliseconds(200), std::bind(&SpeedControl::loop, this));  
+
+        cmd_pub_ = this->create_publisher<std_msgs::msg::Float32>("/vehicle/propulsion", 10);
+        state_sub_ = this->create_subscription<std_msgs::msg::Float32MultiArray>("/vehicle/state", 10, std::bind(&SpeedControl::state_callback, this, std::placeholders::_1));
+        cmd_sub_ = this->create_subscription<std_msgs::msg::Float32>("/vehicle/cmd", 10, std::bind(&SpeedControl::cmd_callback, this, std::placeholders::_1));
+
+        this->declare_parameter("/control/P", 100.0f);
+        this->declare_parameter("/control/I", 5.0f);
+        this->declare_parameter("/control/D", 10.0f);
+
+        RCLCPP_INFO(this->get_logger(), "speed_control has been started");
+    }
+
+

A szabályzást a loop() függvényben láthatjuk. A P, I és D paraméterek ROS paraméterként állíthatók. A hajtó erő 3 tényezőből tevődik össze: a derivatív tagból (Fprop_D), az arányos tagból (Fprop_P) és az integrált tagból (Fprop_I). Ez egy párhuzamos PID struktúra, tehát a három tag összege adja ki a célerőt.

+
void loop()
+    {
+        P = (float)this->get_parameter("/control/P").as_double();
+        I = (float)this->get_parameter("/control/I").as_double();
+        D = (float)this->get_parameter("/control/D").as_double();
+        // calculate new state based on load, prop force, mass and aerodynamic drag
+        float Fprop_D = D*((vSet-vx)-error)/0.1;
+
+        float error = vSet-vx;
+        float Fprop_P = P*error;
+        float Fprop_I = I*integrated_error;
+
+        Fprop = Fprop_P+Fprop_I+Fprop_D;
+
+        Fprop = std::min(std::max(-Fprop_max, Fprop), Fprop_max);
+
+        // Publish cmd
+        std_msgs::msg::Float32 cmd_msg;
+        cmd_msg.data = Fprop;
+
+        cmd_pub_->publish(cmd_msg);
+
+        integrated_error+= error*0.1f;
+    }
+
+

Teszt

+

A teszthez először buildeljük a speed_control_loop packaget!

+
colcon build --packages-select speed_control_loop
+
+

Egy másik terminálban, source-olás után indítsuk el először a vehicle_model node-ot, majd a speed_control node-ot! +Ezt megtehetjük egyszerűen az előre elkészített run_all.launch.py launch fájl segítségével is!

+
cd ~/ros2_ws/src/arj_packages/speed_control_loop
+
+
ros2 launch launch/run_all.launch.py
+
+

Nyissuk meg a Foxglove studiot. És kapcsolódjunk a local host-hoz. Ahhoz, hogy a kapcsolat létrejöjjön, indítsuk el a megfelelő bridge-et! Tegyük ezt egy újabb terminálból!

+

cd ~/ros2_ws/
+
+
ros2 launch foxglove_bridge foxglove_bridge_launch.xml
+

+

Adjunk hozzá 3 plot panelt, majd válasszuk ki a képen látható topicokat. +Mivel még nem határoztuk meg a célsebességet, így az alapértéken zérus. A jármű gyakorlatilag áll, a szabályzó kimenete is zérus.

+

+

Hirdessünk kézzel egy topicot, amely megadja a kívánt sebességet (pl. tempomat esetén a kormányon beállított célsebesség)!

+
ros2 topic pub /vehicle/cmd std_msgs/msg/Float32 "data: 30.0"
+
+

Mit látunk? A szabályzó egy ideig a megengedett legnagyobb gyorsulással (kb. 9 m/s^2-el) gyorsítja a járművet, amíg az el nem éri a kívánt 30 m/s-os sebességet. További sebességekkel, illetve paraméter beállításokkal kísérletezhetünk.

+

+

Például

+
rosparam set /speed_control /control/I 200.0
+
+

esetén a sebesség felfutása kevésbé lesz egyenletes, továbbá túllendülés is megfigyelhető.

+

+

3. feladat: PID hangolás

+

Videó

+

A videóhoz hasonló módon szeretnénk szemléltetni a szabályozás kérdéskörét, azonban mi Plotjuggler helyett Foxglove Studio-t használunk.

+ + +

A következő leírás azzal a feltételezéssel él, hogy a ROS 2 workspace a ~/ros2_ws/ helyen található.

+

Terminal 1 clone

+

Klónozzuk a repositoryt:

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/dottantgal/ros2_pid_library
+
+

Terminal 1 build

+

Lépjünk vissza a workspace gyökerébe és build:

+
cd ~/ros2_ws
+
+
colcon build --packages-select use_library pid_library example_system
+
+

Terminal 2 run

+

Új terminált nyissunk és futtassuk a következő parancsokat:

+
source ~/ros2_ws/install/local_setup.bash && source ~/ros2_ws/install/setup.bash
+
+
ros2 launch example_system example_sys_launch.py
+
+

Terminal 3 set point

+
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 "data: 0.0"
+
+
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 "data: 1.0"
+
+
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 "data: 1.4"
+
+
ros2 topic pub -r 1  /set_point_topic std_msgs/msg/Float32 "data: 0.6"
+
+

Terminal 4 foxglove

+

Ha esetleg eddig nem lett volna telepítve: +

sudo apt install ros-humble-foxglove-bridge
+
+Maga bridge így indítható: +
source ~/ros2_ws/install/local_setup.bash && source ~/ros2_ws/install/setup.bash
+
+
ros2 launch foxglove_bridge foxglove_bridge_launch.xml
+
+Ezután Foxglove Studió segítségével ws://localhost:8765 címen elérhető minden adat.

+

+

VS code

+

Szerkesszük a example_sys_launch.py fájlt, majd colcon build (terminal 1) source és futtatás.

+
code ~/ros2_ws/src/ros2_pid_library/
+
+

+

Futtassuk és figyeljük meg az eredményeket a beavatkozó jel (control_value) enyhén más jelleget mutat:

+

+

Források / Sources

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szabalyozas/vs_code01.png b/szabalyozas/vs_code01.png new file mode 100644 index 0000000..7e4e303 Binary files /dev/null and b/szabalyozas/vs_code01.png differ diff --git a/szabalyozas/vscode_speed_controller.PNG b/szabalyozas/vscode_speed_controller.PNG new file mode 100644 index 0000000..5d8dde9 Binary files /dev/null and b/szabalyozas/vscode_speed_controller.PNG differ diff --git a/szimulacio/chassis.png b/szimulacio/chassis.png new file mode 100644 index 0000000..8eed29a Binary files /dev/null and b/szimulacio/chassis.png differ diff --git a/szimulacio/empty_world.png b/szimulacio/empty_world.png new file mode 100644 index 0000000..9034374 Binary files /dev/null and b/szimulacio/empty_world.png differ diff --git a/szimulacio/f1tenth_sim_a/index.html b/szimulacio/f1tenth_sim_a/index.html new file mode 100644 index 0000000..f54d905 --- /dev/null +++ b/szimulacio/f1tenth_sim_a/index.html @@ -0,0 +1,2857 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Gazebo Fortress ROS 2 Wheeltec - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

ROS 2 F1/10 Wheeltec Roboworks Gazebo simulation workshop

+

The workshop is ROS 2 compatible Static Badge

+

Video

+ + +

Requirements (high-level)

+
    +
  1. ROS 2 Humble: 🟠 see previous workshops or docs.ros.org/en/humble/Installation.html
  2. +
  3. Gazebo Fortress: ✅ current workshop gazebosim.org/docs/fortress/install_ubuntu
  4. +
  5. ROS gz bridge: ✅ current workshop, ROS integration. Install with a single command: sudo apt install ros-humble-ros-gz-bridge, gazebosim.org/docs/fortress/ros2_integration
  6. +
  7. Build and run custom worlds and models ✅ current workshop (e.g. F1/10 / Wheeltec, Roboworks)
  8. +
+
+ Image title +
Official F1/10 vehicle vs Wheeltec Roboworks Ackermann Rosbot mini vehicle
+
+

Binary Installation on Ubuntu

+

Fortress binaries are provided for Ubuntu Bionic, Focal and Jammy. All of the Fortress +binaries are hosted in the osrfoundation repository. To install all of them, +the metapackage ignition-fortress can be installed. The following is based on gazebosim.org/docs/fortress/install_ubuntu.

+

First install some necessary tools:

+

sudo apt-get update
+
+
sudo apt-get install lsb-release wget gnupg
+

+

Then install Ignition Fortress:

+

sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg
+
+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null
+
+
sudo apt-get update
+
+
sudo apt-get install ignition-fortress
+

+

All libraries should be ready to use and the ign gazebo app ready to be executed.

+

Gazebo Fortress ROS 2 integration

+

Issue the following command:

+
sudo apt install ros-humble-ros-gz-bridge
+
+

Additional settings to WSL2

+
+

Warning - WSL2

+

There is an issue, which can be set even in ~/.bashrc:

+
+
export LIBGL_ALWAYS_SOFTWARE=1
+
+

Set it in ~/.bashrc: +

echo "export LIBGL_ALWAYS_SOFTWARE=1" >> ~/.bashrc
+

+
+ Don't forget to source bashrc. + +
source ~/.bashrc
+
+
+ +

After new terminal or source:

+
echo $LIBGL_ALWAYS_SOFTWARE
+
+

should print 1. Alternatively

+

cat ~/.bashrc | grep LIBGL
+
+should print the line.

+

Check the installation

+
+

Success

+

Now the ign gazebo should work and the ros2 commands should be available.

+
+

+

Try at least one of the following commands:

+
ign gazebo
+
+
ign gazebo -v 4 -r ackermann_steering.sdf
+
+
ign gazebo shapes.sdf
+
+

+
ign param --versions
+
+

Packages and build

+

Detailed description of the packages and build process.

+

It is assumed that the workspace is ~/ros2_ws/.

+
cd ~/ros2_ws/src
+
+
git clone https://github.com/robotverseny/robotverseny_gazebo24
+
+

Build

+
cd ~/ros2_ws
+
+
colcon build --symlink-install --packages-select robotverseny_application robotverseny_description robotverseny_bringup robotverseny_gazebo 
+
+

Opcionális, de érdemes feltenni az RViz 2D Overlay csomagot, amivel a debug szövegeket lehet megjeleníteni a RViz2-ben:

+
sudo apt install ros-humble-rviz-2d-overlay*
+
+

Run

+
+ Don't forget to source before ROS commands. + +
source ~/ros2_ws/install/setup.bash
+
+
+ +
ros2 launch robotverseny_bringup roboworks.launch.py
+
+

+

Useful commands

+

Publish command topic: +

ros2 topic pub --once /roboworks/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.5, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -0.01}}"
+

+

Teleop twist keyboard: +

ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/roboworks/cmd_vel
+

+

Ignition info topic: +

ign topic -i --topic /model/roboworks/cmd_vel
+
+Ignition echo topic:

+
ign topic -et /model/roboworks/cmd_vel
+
+

Topics:

+
ros2 topic list
+
+
+ Here are the topics. + +
/clicked_point
+/clock
+/goal_pose
+/initialpose
+/joint_states
+/parameter_events
+/robot_description
+/roboworks/cmd_vel
+/roboworks/odometry
+/roboworks/scan
+/rosout
+/tf
+/tf_static
+
+
+ +

Linkek

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szimulacio/gazebo_fortress/index.html b/szimulacio/gazebo_fortress/index.html new file mode 100644 index 0000000..34c5510 --- /dev/null +++ b/szimulacio/gazebo_fortress/index.html @@ -0,0 +1,2542 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Gazebo Fortress ROS 2 - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Ignition Gazebo Fortress

+

Az Ignition Gazebo Fortress egy long-term support (LTS) release 2026 szeptemberéig támogatva. ROS 2 Humble kiadással kompatibilis, lásd a kompatibiltási mátrixot.

+

Static Badge

+

Telepítés

+

Ajánlott az Ubuntu és a binary telepítés: gazebosim.org/docs/fortress/install_ubuntu. Természetesen az előző linken továbbkattintva elérhetőek a Windowsos illetve a forráskódból fordított verziók is.

+

ROS 2 integráció

+ +

Megjegyzés WSL esetén

+

Gazebo szimulátort és Windows Subsystem for Linux-ot használva előfordulhat egy issue, ami egy egyszerű környezeti változó beállításával javítható. A ~/.bashrc fájlba a következőt kell beállítani:

+
export LIBGL_ALWAYS_SOFTWARE=1 ### GAZEBO IGNITION 
+
+

Új terminál vagy source után a echo $LIBGL_ALWAYS_SOFTWARE parancsra 1-et fog kiíni.

+

Példa: Gazebo Fortress beépített világok (world)

+

WSL elsetén első lépésként ellenőrizzük a beállítások helyességét:

+
echo $LIBGL_ALWAYS_SOFTWARE 
+
+

Amennyiben a parancsra 1-et ír válaszként, akkor helyes a beállításunk.

+

Nézzük meg a telepített verziót:

+
ign param --versions
+
+

A válasz pl 11.4.1 lehet.

+

Indítsuk el a Gazebo-t:

+
ign gazebo
+
+

gazebo

+

Nyissuk meg a shapes.sdf világot. Az SDF (Simulation Description Format) egy beépített XML leírás. Akár egy parancsként is indítható: ign gazebo shapes.sdf.

+

+

Példa: Ackermann robot

+

Ackermann robotnak a „személyautó-szerű”, hagyományos, elől két kormányzott, hátul pedig két nem kormányzott kerékkel rendelkező járművet / robotot nevezzük. Ebben a példában egy ilyen robotot szeretnénk mozgatni ROS 2-ből. Az ign gazebo parancsra a szimuláció-választó felület indul. Egy paranccsal indítható az Ackermann robotot tartalmazó szimuláció:

+
ign gazebo -v 4 -r ackermann_steering.sdf
+
+

Alt text

+

Az Ignition Gazebo ROS 2-től független, de jól támogatott, így ros_gz_bridge package segítségével indítható az a bridge, amin a szimmulációs topic-ok ROS 2 topic-ként látszanak, pl:

+
sudo apt update
+
+
sudo apt install ros-humble-ros-gz -y
+
+

Tanteremben pedig:

+
cd /mnt/kozos/script
+
+
./gz_bridge.sh
+
+
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist
+
+
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry --ros-args -r /model/vehicle_blue/odometry:=/odom
+
+
ros2 run ros_gz_bridge parameter_bridge /world/ackermann_steering/pose/info@tf2_msgs/msg/TFMessage[ignition.msgs.Pose_V  --ros-args -r /world/ackermann_steering/pose/info:=/tf
+
+

Ez a 3 parancs egy hosszú parancsként is kiadható:

+
ros2 run ros_gz_bridge parameter_bridge /model/vehicle_blue/cmd_vel@geometry_msgs/msg/Twist]ignition.msgs.Twist /model/vehicle_blue/odometry@nav_msgs/msg/Odometry[ignition.msgs.Odometry   /world/ackermann_steering/pose/info@tf2_msgs/msg/TFMessage[ignition.msgs.Pose_V  --ros-args -r /world/ackermann_steering/pose/info:=/tf -r /model/vehicle_blue/odometry:=/odom
+
+

Hogy pontosan milyen szimulációs topicok vannak, az ezekkel a parancsokkal ellenőrizhető:

+
ign topic -l
+
+
ign topic -et /model/vehicle_blue/tf
+
+
ign topic -i --topic /model/vehicle_blue/tf
+
+

Billentyűzetről teleoperálhatjuk a járművet:

+
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/model/vehicle_blue/cmd_vel
+
+

Linkek

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szimulacio/gyakorlat/index.html b/szimulacio/gyakorlat/index.html new file mode 100644 index 0000000..aea0edc --- /dev/null +++ b/szimulacio/gyakorlat/index.html @@ -0,0 +1,3461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Gazebo saját robotszimuláció készítése - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Ignition Gazebo gyakorlat

+

Saját robotszimuláció létrehozása

+

A következőkben létre fogunk hozni egy egyszerű környezetet (world), valamint egy robot modellt. Ennek érdekében hozzunk létre egy simulation mappát, majd ezen belül a building_robot.sdf nevű fájlt. A mappa bárhol létrehozható, illetve a fájl neve is szabadon választható, a követhetőség érdekében érdemes a megadott módon eljárni.

+

mkdir simulation
+
+
cd simulation
+
+
touch building_robot.sdf
+

+

Környezet létrehozása

+

Nyissuk meg a létrehozott fájlt Visual Studio Code segítségével, majd másoljuk be az alábbi kódrészletet:

+

<?xml version="1.0" ?>
+<sdf version="1.9">
+    <world name="car_world">
+        <physics name="1ms" type="ignored">
+            <max_step_size>0.001</max_step_size>
+            <real_time_factor>1.0</real_time_factor>
+        </physics>
+        <plugin
+            filename="gz-sim-physics-system"
+            name="gz::sim::systems::Physics">
+        </plugin>
+        <plugin
+            filename="gz-sim-user-commands-system"
+            name="gz::sim::systems::UserCommands">
+        </plugin>
+        <plugin
+            filename="gz-sim-scene-broadcaster-system"
+            name="gz::sim::systems::SceneBroadcaster">
+        </plugin>
+
+        <light type="directional" name="sun">
+            <cast_shadows>true</cast_shadows>
+            <pose>0 0 10 0 0 0</pose>
+            <diffuse>0.8 0.8 0.8 1</diffuse>
+            <specular>0.2 0.2 0.2 1</specular>
+            <attenuation>
+                <range>1000</range>
+                <constant>0.9</constant>
+                <linear>0.01</linear>
+                <quadratic>0.001</quadratic>
+            </attenuation>
+            <direction>-0.5 0.1 -0.9</direction>
+        </light>
+
+        <model name="ground_plane">
+            <static>true</static>
+            <link name="link">
+                <collision name="collision">
+                <geometry>
+                    <plane>
+                    <normal>0 0 1</normal>
+                    </plane>
+                </geometry>
+                </collision>
+                <visual name="visual">
+                <geometry>
+                    <plane>
+                    <normal>0 0 1</normal>
+                    <size>100 100</size>
+                    </plane>
+                </geometry>
+                <material>
+                    <ambient>0.8 0.8 0.8 1</ambient>
+                    <diffuse>0.8 0.8 0.8 1</diffuse>
+                    <specular>0.8 0.8 0.8 1</specular>
+                </material>
+                </visual>
+            </link>
+        </model>
+    </world>
+</sdf>
+
+A fenti kódrészlet üres környezetet definiál, mindössze egy sík (talaj), valamint alapértelmezett világítás (napfény) található meg benne. Mentsük el a kódot, majd indítsuk el a szimulációt az alábbi módon, a simulation mappából:

+

cd ~/simulation
+
+
ign gazebo building_robot.sdf
+

+

Indítást követően a leírtaknak megfelelő üres környezetet kell látnunk:

+

Alt text

+

Robot modell létrehozása

+

Folytassuk a building_robot.sdf szerkesztését, a </model> címkét követően. Észrevehető, hogy a talajt, vagyis a ground_plane elemet is modellként adtuk meg, hasonló módon adjuk hozzá a járművet is.

+

<model name='vehicle_blue' canonical_link='chassis'>
+    <pose relative_to='world'>0 0 0 0 0 0</pose>
+</model>
+
+A robot modell megnevezése ebben az esetben vehicle_blue . A megnevezés szabadon megválasztható, viszont fontos figyelni arra, hogy a név egyedi legyen az azonos környezeten belül használt modellek között.

+

A modellt felépítő elemeket (pl. karosszéria, kerekek stb.) a továbbiakban linkeknek nevezzük.

+

Minden modellnek lehet egyetlen ún. canonical_link eleme. Minden további modellen belül alkalmazott link ehhez fog csatlakozni. Amennyiben nem definiálunk egyetlen canonical_link elemet sem, az első link alapértelmezetten canonical típusú lesz.

+

A <pose> címke használatával megadható egy link pozíciója és orientációja. A címke után megadott relative_to attribútummal megadható, hogy mihez képest szeretnénk a link pozícióját és orientációját definiálni. Az attribútum megadása nélkül a pozíció megadása a környezethez képest történik. A pozíció és orientáció megadásának formátuma <pose>X Y Z R P Y</pose>, ahol X, Y és Z a frame-en belüli pozíció koordinátái, R, P és Y pedig az orientációt adja meg radiánban. A robot definiálása során minden paraméternek zérus értéket adtunk, tehát a robot és a környezet frame-je egybeesik.

+

Minden modell (robot) jointok (csuklók / ízületek) által összekapcsolt linkekből áll.

+

A robotot alkotó linkek definiálása

+

A következőkben az érthetőség kedvéért az SDF fájl magyarázata elemenként történik. Nehéz lehet követni az egyes részletek teljes kódon belüli helyét, ehhez a magyarázat végén található teljes SDF ad segítséget.

+

Minden link létrehozása során meg kell adnunk a következőket: +1. link neve, pozíciója +2. link inerciális tulajdonságai (tömeg és inerciamátrix) +3. vizuális és egyszerűsített (collision) geometria

+
    +
  • Karosszéria
  • +
+

Link létrehozása:

+
<model name='vehicle_blue' canonical_link='chassis'>
+    <pose relative_to='world'>0 0 0 0 0 0</pose>
+    <link name='chassis'>
+        <pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>
+    </link>
+</model>
+
+

Inerciális tulajdonságok (a mértékegységek ebben az esetben is SI-ben értendőek):

+
<inertial>
+    <mass>1.14395</mass>
+    <inertia>
+        <ixx>0.095329</ixx>
+        <ixy>0</ixy>
+        <ixz>0</ixz>
+        <iyy>0.381317</iyy>
+        <iyz>0</iyz>
+        <izz>0.476646</izz>
+    </inertia>
+</inertial>
+
+

Vizuális és egyszerűsített (ütközési/collision) geometria megadása:

+
<visual name='visual'>
+    <geometry>
+        <box>
+            <size>2.0 1.0 0.5</size>
+        </box>
+    </geometry>
+    <material>
+        <ambient>0.0 0.0 1.0 1</ambient>
+        <diffuse>0.0 0.0 1.0 1</diffuse>
+        <specular>0.0 0.0 1.0 1</specular>
+    </material>
+</visual>
+
+
<collision name='collision'>
+    <geometry>
+        <box>
+            <size>2.0 1.0 0.5</size>
+        </box>
+    </geometry>
+</collision>
+
+

Indítsuk el a szimulációt ismét:

+

cd ~/simulation
+
+
ign gazebo building_robot.sdf
+

+

Ezt követően a szimulátorban a robot karosszériáját kell látnunk:

+

Alt text

+
    +
  • Jobb és bal kerék
  • +
+

Hozzuk létre a robot jobb és bal (hajtott) kerekét képező linkeket. Ezt a robotot definiáló <model> címkék között kell megtennünk, ugyanis ide kerül minden olyan link definíciója, amely azonos modellen (a roboton) belül értendő.

+

A kerekeket hengerek (sphere) segítségével fogjuk létrehozni. A kerekeknek az Y tengely mentén kell elfordulniuk, ezért meg kell adnunk a helyes orientációjukat.

+
<link name='left_wheel'>
+    <pose relative_to="chassis">-0.5 0.6 0 -1.5707 0 0</pose>
+    <inertial>
+        <mass>1</mass>
+        <inertia>
+            <ixx>0.043333</ixx>
+            <ixy>0</ixy>
+            <ixz>0</ixz>
+            <iyy>0.043333</iyy>
+            <iyz>0</iyz>
+            <izz>0.08</izz>
+        </inertia>
+    </inertial>
+
+

Vizuális és egyszerűsített (ütközési/collision) geometria megadása:

+
<visual name='visual'>
+        <geometry>
+            <cylinder>
+                <radius>0.4</radius>
+                <length>0.2</length>
+            </cylinder>
+        </geometry>
+        <material>
+            <ambient>1.0 0.0 0.0 1</ambient>
+            <diffuse>1.0 0.0 0.0 1</diffuse>
+            <specular>1.0 0.0 0.0 1</specular>
+        </material>
+    </visual>
+    <collision name='collision'>
+        <geometry>
+            <cylinder>
+                <radius>0.4</radius>
+                <length>0.2</length>
+            </cylinder>
+        </geometry>
+    </collision>
+</link>
+
+

A bal kerék megadása analóg módon történik, csak a pozíció tekintetében (és természetesen a link nevében) tér el a jobb kerék megadásától:

+
<link name='right_wheel'>
+    <pose relative_to="chassis">-0.5 -0.6 0 -1.5707 0 0</pose> <!--szögek radiánban-->
+    <inertial>
+        <mass>1</mass>
+        <inertia>
+            <ixx>0.043333</ixx>
+            <ixy>0</ixy>
+            <ixz>0</ixz>
+            <iyy>0.043333</iyy>
+            <iyz>0</iyz>
+            <izz>0.08</izz>
+        </inertia>
+    </inertial>
+    <visual name='visual'>
+        <geometry>
+            <cylinder>
+                <radius>0.4</radius>
+                <length>0.2</length>
+            </cylinder>
+        </geometry>
+        <material>
+            <ambient>1.0 0.0 0.0 1</ambient>
+            <diffuse>1.0 0.0 0.0 1</diffuse>
+            <specular>1.0 0.0 0.0 1</specular>
+        </material>
+    </visual>
+    <collision name='collision'>
+        <geometry>
+            <cylinder>
+                <radius>0.4</radius>
+                <length>0.2</length>
+            </cylinder>
+        </geometry>
+    </collision>
+</link>
+
+
    +
  • Támasztógörgő hozzáadása
  • +
+

Van lehetőség enyéni frame-ek létrehozására is, a támasztógörgő felépítése során ezt fogjuk tenni:

+

<frame name="caster_frame" attached_to='chassis'>
+    <pose>0.8 0 -0.2 0 0 0</pose>
+</frame>
+
+A létrehozott frame neve caster_frame, amely a chassis linkhez csatlakozik. A <pose> címke megadja a pozícióját és orientációját ehhez a linkhez képest, viszont a relative_to attribútumra az egyéni frame esetében nem volt szükség.

+

Folytatódhad a támasztógörgő definiálása:

+
<link name='caster'>
+    <pose relative_to='caster_frame'/>
+    <inertial>
+        <mass>1</mass>
+        <inertia>
+            <ixx>0.016</ixx>
+            <ixy>0</ixy>
+            <ixz>0</ixz>
+            <iyy>0.016</iyy>
+            <iyz>0</iyz>
+            <izz>0.016</izz>
+        </inertia>
+    </inertial>
+    <visual name='visual'>
+        <geometry>
+            <sphere>
+                <radius>0.2</radius>
+            </sphere>
+        </geometry>
+        <material>
+            <ambient>0.0 1 0.0 1</ambient>
+            <diffuse>0.0 1 0.0 1</diffuse>
+            <specular>0.0 1 0.0 1</specular>
+        </material>
+    </visual>
+    <collision name='collision'>
+        <geometry>
+            <sphere>
+                <radius>0.2</radius>
+            </sphere>
+        </geometry>
+    </collision>
+</link>
+
+

Csuklók / ízületek (joints) definiálása

+

A korábban definiált linkek között összefüggéseket kell definiálnunk. Ezek az összefüggések fogják megadni, hogy a linkek milyen módon mozdulhatnak el egymáshoz képest. Ebből ered a definíció módjának neve is.

+
    +
  • Bal kerék joint
  • +
+

Megadjuk a joint nevét és típusát. A keréknek el kell fordulnia, ezért a revolute típust választjuk.

+

<joint name='left_wheel_joint' type='revolute'>
+    <pose relative_to='left_wheel'/>
+
+Ezt követően megadjuk az alá-fölé rendelő viszonyt: +
    <parent>chassis</parent>
+    <child>left_wheel</child>
+
+Végül meg kell adnunk a linkek közötti kényszerek definícióját. Ezek a definíciók bármely frame-re vonatkozóan megadhatóak, nem csak a szülő-gyerek frame-ek között.

+

Jelen esetben a keréknek az Y tengely körül kell elfordulnia. Teljesen, többször is körbefordulhat, ezért a mozgás korlátjai pozitív és negatív végtelen lesz.

+
 <axis>
+        <xyz expressed_in='__model__'>0 1 0</xyz>
+        <limit>
+            <lower>-1.79769e+308</lower>    <!--negatív végtelen-->
+            <upper>1.79769e+308</upper>     <!--pozitív végtelen-->
+        </limit>
+    </axis>
+</joint>
+
+
    +
  • Jobb kerék joint
  • +
+

A jobb kerék joint definiálása a bal kerékéhez hasonló módon történik:

+
<joint name='right_wheel_joint' type='revolute'>
+    <pose relative_to='right_wheel'/>
+    <parent>chassis</parent>
+    <child>right_wheel</child>
+    <axis>
+        <xyz expressed_in='__model__'>0 1 0</xyz>
+        <limit>
+            <lower>-1.79769e+308</lower>    <!--negatív végtelen-->
+            <upper>1.79769e+308</upper>     <!--pozitív végtelen-->
+        </limit>
+    </axis>
+</joint>
+
+
    +
  • Támasztókerék joint
  • +
+

Mivel a támasztókerék gömb, minden tengely mentén elfordulhat. Ebből adódóan esetében eltérő típusú joint kerül alkalmazásra:

+
<joint name='caster_wheel' type='ball'>
+    <parent>chassis</parent>
+    <child>caster</child>
+</joint>
+
+

Indítsuk el a szimulációt ismét:

+

cd ~/simulation
+
+
ign gazebo building_robot.sdf
+

+

Ezt követően a szimulátorban a robotot kell látnunk:

+

Alt text

+

Az eddig bemutatottakat tartalmazó XML leíró fájl tartalma:

+
<?xml version="1.0" ?>
+<sdf version="1.8">
+    <world name="car_world">
+        <physics name="1ms" type="ignored">
+            <max_step_size>0.001</max_step_size>
+            <real_time_factor>1.0</real_time_factor>
+        </physics>
+        <plugin
+            filename="gz-sim-physics-system"
+            name="gz::sim::systems::Physics">
+        </plugin>
+        <plugin
+            filename="gz-sim-user-commands-system"
+            name="gz::sim::systems::UserCommands">
+        </plugin>
+        <plugin
+            filename="gz-sim-scene-broadcaster-system"
+            name="gz::sim::systems::SceneBroadcaster">
+        </plugin>
+
+        <light type="directional" name="sun">
+            <cast_shadows>true</cast_shadows>
+            <pose>0 0 10 0 0 0</pose>
+            <diffuse>0.8 0.8 0.8 1</diffuse>
+            <specular>0.2 0.2 0.2 1</specular>
+            <attenuation>
+                <range>1000</range>
+                <constant>0.9</constant>
+                <linear>0.01</linear>
+                <quadratic>0.001</quadratic>
+            </attenuation>
+            <direction>-0.5 0.1 -0.9</direction>
+        </light>
+
+        <model name="ground_plane">
+            <static>true</static>
+            <link name="link">
+                <collision name="collision">
+                <geometry>
+                    <plane>
+                    <normal>0 0 1</normal>
+                    </plane>
+                </geometry>
+                </collision>
+                <visual name="visual">
+                <geometry>
+                    <plane>
+                    <normal>0 0 1</normal>
+                    <size>100 100</size>
+                    </plane>
+                </geometry>
+                <material>
+                    <ambient>0.8 0.8 0.8 1</ambient>
+                    <diffuse>0.8 0.8 0.8 1</diffuse>
+                    <specular>0.8 0.8 0.8 1</specular>
+                </material>
+                </visual>
+            </link>
+        </model>
+
+        <model name='vehicle_blue' canonical_link='chassis'>
+            <pose relative_to='world'>0 0 0 0 0 0</pose>   <!--alapbeállítás szerint a megadott póz a világ koordinátáihoz képest értendő-->
+
+            <!--karosszéria-->
+            <link name='chassis'>
+                <pose relative_to='__model__'>0.5 0 0.4 0 0 0</pose>
+                <inertial>
+                    <mass>1.14395</mass>
+                    <inertia>
+                        <ixx>0.095329</ixx>
+                        <ixy>0</ixy>
+                        <ixz>0</ixz>
+                        <iyy>0.381317</iyy>
+                        <iyz>0</iyz>
+                        <izz>0.476646</izz>
+                    </inertia>
+                </inertial>
+                <visual name='visual'>
+                    <geometry>
+                        <box>
+                            <size>2.0 1.0 0.5</size>
+                        </box>
+                    </geometry>
+                    <!--Az összetevő anyagjellemzői (színe)-->
+                    <material>
+                        <ambient>0.0 0.0 1.0 1</ambient>
+                        <diffuse>0.0 0.0 1.0 1</diffuse>
+                        <specular>0.0 0.0 1.0 1</specular>
+                    </material>
+                </visual>
+                <collision name='collision'>
+                    <geometry>
+                        <box>
+                            <size>2.0 1.0 0.5</size>
+                        </box>
+                    </geometry>
+                </collision>
+            </link>
+
+            <!--Bal kerék-->
+            <link name='left_wheel'>
+                <pose relative_to="chassis">-0.5 0.6 0 -1.5707 0 0</pose>
+                <inertial>
+                    <mass>1</mass>
+                    <inertia>
+                        <ixx>0.043333</ixx>
+                        <ixy>0</ixy>
+                        <ixz>0</ixz>
+                        <iyy>0.043333</iyy>
+                        <iyz>0</iyz>
+                        <izz>0.08</izz>
+                    </inertia>
+                </inertial>
+                <visual name='visual'>
+                    <geometry>
+                        <cylinder>
+                            <radius>0.4</radius>
+                            <length>0.2</length>
+                        </cylinder>
+                    </geometry>
+                    <material>
+                        <ambient>1.0 0.0 0.0 1</ambient>
+                        <diffuse>1.0 0.0 0.0 1</diffuse>
+                        <specular>1.0 0.0 0.0 1</specular>
+                    </material>
+                </visual>
+                <collision name='collision'>
+                    <geometry>
+                        <cylinder>
+                            <radius>0.4</radius>
+                            <length>0.2</length>
+                        </cylinder>
+                    </geometry>
+                </collision>
+            </link>
+
+            <!--Jobb kerék (ugyanaz, mint a bal kerék, a pozíció tükrözésével)-->
+            <link name='right_wheel'>
+                <pose relative_to="chassis">-0.5 -0.6 0 -1.5707 0 0</pose>
+                <inertial>
+                    <mass>1</mass>
+                    <inertia>
+                        <ixx>0.043333</ixx>
+                        <ixy>0</ixy>
+                        <ixz>0</ixz>
+                        <iyy>0.043333</iyy>
+                        <iyz>0</iyz>
+                        <izz>0.08</izz>
+                    </inertia>
+                </inertial>
+                <visual name='visual'>
+                    <geometry>
+                        <cylinder>
+                            <radius>0.4</radius>
+                            <length>0.2</length>
+                        </cylinder>
+                    </geometry>
+                    <material>
+                        <ambient>1.0 0.0 0.0 1</ambient>
+                        <diffuse>1.0 0.0 0.0 1</diffuse>
+                        <specular>1.0 0.0 0.0 1</specular>
+                    </material>
+                </visual>
+                <collision name='collision'>
+                    <geometry>
+                        <cylinder>
+                            <radius>0.4</radius>
+                            <length>0.2</length>
+                        </cylinder>
+                    </geometry>
+                </collision>
+            </link>
+
+            <!--Tetszőleges frame-->
+            <frame name="caster_frame" attached_to='chassis'>
+                <pose>0.8 0 -0.2 0 0 0</pose>
+            </frame>
+
+            <!--Támasztógörgő-->
+            <link name='caster'>
+                <pose relative_to='caster_frame'/>
+                <inertial>
+                    <mass>1</mass>
+                    <inertia>
+                        <ixx>0.016</ixx>
+                        <ixy>0</ixy>
+                        <ixz>0</ixz>
+                        <iyy>0.016</iyy>
+                        <iyz>0</iyz>
+                        <izz>0.016</izz>
+                    </inertia>
+                </inertial>
+                <visual name='visual'>
+                    <geometry>
+                        <sphere>
+                            <radius>0.2</radius>
+                        </sphere>
+                    </geometry>
+                    <material>
+                        <ambient>0.0 1 0.0 1</ambient>
+                        <diffuse>0.0 1 0.0 1</diffuse>
+                        <specular>0.0 1 0.0 1</specular>
+                    </material>
+                </visual>
+                <collision name='collision'>
+                    <geometry>
+                        <sphere>
+                            <radius>0.2</radius>
+                        </sphere>
+                    </geometry>
+                </collision>
+            </link>
+
+            <!--Bal kerék joint-->
+            <joint name='left_wheel_joint' type='revolute'>
+                <pose relative_to='left_wheel'/>
+                <parent>chassis</parent>
+                <child>left_wheel</child>
+                <axis>
+                    <xyz expressed_in='__model__'>0 1 0</xyz> 
+                    <limit>
+                        <lower>-1.79769e+308</lower>    <!--negatív végtelen-->
+                        <upper>1.79769e+308</upper>     <!--pozitív végtelen-->
+                    </limit>
+                </axis>
+            </joint>
+
+            <!--Jobb kerék joint-->
+            <joint name='right_wheel_joint' type='revolute'>
+                <pose relative_to='right_wheel'/>
+                <parent>chassis</parent>
+                <child>right_wheel</child>
+                <axis>
+                    <xyz expressed_in='__model__'>0 1 0</xyz>
+                    <limit>
+                        <lower>-1.79769e+308</lower>    <!--negatív végtelen-->
+                        <upper>1.79769e+308</upper>     <!--pozitív végtelen-->
+                    </limit>
+                </axis>
+            </joint>
+
+            <!--Támasztógörgő joint-->
+            <joint name='caster_wheel' type='ball'>
+                <parent>chassis</parent>
+                <child>caster</child>
+            </joint>
+        </model>
+    </world>
+</sdf>
+
+

A robotplatform mozgatása

+

A korábbiakban összeállított robot mozgatásához egy plugint, pontosabban a diff_drive plugint fogunk alkalmazni.

+

Nyissuk meg a korábban létrehozott building_robot.sdf fájlt, és a vehicle_blue <model> címkéin belül hívjuk meg a plugint, valamint definiáljuk a használatához szükséges alapvető paramétereket:

+
<plugin
+    filename="libignition-gazebo-diff-drive-system.so"
+    name="ignition::gazebo::systems::DiffDrive">
+    <left_joint>left_wheel_joint</left_joint>
+    <right_joint>right_wheel_joint</right_joint>
+    <wheel_separation>1.2</wheel_separation>
+    <wheel_radius>0.4</wheel_radius>
+    <odom_publish_frequency>1</odom_publish_frequency>
+    <topic>cmd_vel</topic>
+</plugin>
+
+

A <plugin> címkének két attribútuma van. Az egyik a könyvtár megnevezése, amelyből a plugin származik (filename), a másik a plugin neve (name). A további címkék a differenciálhajtású robot jellemzői: +- <left_joint> és <right_joint>: azok a jointok, amelyek kapcsolatot definiálnak a robot bal- illetve jobboldali kereke, és a robot karosszériája között. +- <wheel_separation>: a hajtott kerekek közötti távolság, vagyis a nyomtáv. Mivel korábban úgy adtuk meg, hogy a jobb és bal kerék pozíciója az Y tengely mentén -0,6m és 0,6m, a kerekek távolsága 1,2m. +- <wheel_radius>: a hajtott kerekek sugara. +- <odom_publish_frequency>: az a frekvencia, amellyel a plugin által számolt odometriát publish-olni szeretnénk.

+

A paraméterek beállításával a modellünk kész a mozgatásra. A következő lépés az, hogy utasításokat küldjünk neki, ami a cmd_vel topic segítségével hajtható végre.

+
    +
  1. +

    Indítsuk el a robotot kézi parancsmegadással

    +
  2. +
  3. +

    Az egyik terminálban indítsuk el a szimulációt: +

    ign gazebo building_robot.sdf
    +

    +
  4. +
  5. +

    Egy másik terminálból küldjünk utasítást a robotnak: +

    ign topic -t "/cmd_vel" -m ignition.msgs.Twist -p "linear: {x: 0.5}, angular: {z: 0.05}"
    +

    +
  6. +
  7. +

    Nyomjuk meg a lejátszás gombot a szimulátorban.

    +
  8. +
+

A fenti lépéseket követően a robotmodellnek mozognia kell.

+
    +
  1. Mozgassuk a robotot a billentyűzet segítségével
  2. +
+

Most a billentyűzet olvasásával, szintén ROS2 topic által fogjuk irányítani a robotot. Ehhez további két plugin alkalmazása lesz szükséges: KeyPublisher és TriggeredPublisher.

+

A KeyPublisher egy ign-gui plugin, amely beolvassa a billentyűzet billentyűinek lenyomását, és a /keyboard/keypress topic-ra küldi. Próbáljuk ki ezt a plugint:

+
    +
  • Egyik terminálban ismét indítsuk el a szimulátort:
  • +
+
ign gazebo building_robot.sdf
+
+
    +
  • +

    A szimulátor ablakának jobb felső sarkában klikkeljünk a plugins legördülő listára, majd a Key Publisher opcióra.

    +
  • +
  • +

    Egy másik terminálban adjuk meg a következőt, ezzel kiírva az összes billentyűzet-lenyomást:

    +
  • +
+
ign topic -e -t /keyboard/keypress
+
+

A következő lépés az, hogy a billentyűzet leütéseit megfeleltessük a robot irányítására alkalmas parancsoknak. Erre fogjuk használni a TriggeredPublisher plugint.

+

A TriggeredPublisher plugin általunk definiált módon hoz létre kimenetet egy adott bemenetnek megfelelően. A building_robot.sdf fájlban a <world> címkéken belül adjuk meg a következő megfeleltetést:

+
<plugin filename="libignition-gazebo-triggered-publisher-system.so"
+        name="ignition::gazebo::systems::TriggeredPublisher">
+    <input type="ignition.msgs.Int32" topic="/keyboard/keypress">
+        <match field="data">16777235</match>
+    </input>
+    <output type="ignition.msgs.Twist" topic="/cmd_vel">
+        linear: {x: 0.5}, angular: {z: 0.0}
+    </output>
+</plugin>
+
+

Próbáljuk ki a robot irányítását:

+
    +
  • Indítsuk el a szimulátort ismét:
  • +
+
ign gazebo building_robot.sdf
+
+
    +
  • +

    Válasszuk ki a Key Publisher plugint.

    +
  • +
  • +

    Győződjünk meg róla, hogy fut a szimuláció, szükség esetén nyomjuk le a Lejátszás gombot.

    +
  • +
  • +

    Nyomjuk le a Fel (↑) nyílbillentyűt. A robotnak el kell indulnia előre.

    +
  • +
+

Önálló feladat

+

Készítsük el az összes nyílbillentyű funkcióját a korábbi kódrészlet kibővítésével. A feladat analóg módon, csak a paraméterek módosításával megoldható, az alábbi megfeleltetések segítségével:

+
    +
  • Balra nyíl, értéke: 16777234, paraméterek: linear: {x: 0.0}, angular: {z: 0.5}
  • +
  • Fel nyíl, értéke: 16777235, paraméterek: linear: {x: 0.5}, angular: {z: 0.0}
  • +
  • Jobbra nyíl, értéke: 16777236, paraméterek: linear: {x: 0.0}, angular: {z: -0.5}
  • +
  • Le nyíl, értéke: 16777237, paraméterek: linear: {x: 0.5}, angular: {z: 0.0}
  • +
+

Környezet kibővítése

+

Az eddig létrehozott szimulált környezet csak egy talajsíkot és napfényt tartalmaz. Hozzunk létre további környezeti elemeket primitív statikus elemek hozzáadásával. Kezdjük egyetlen téglatest, "fal" létrehozásával:

+
<model name='wall'>
+    <static>true</static>
+    <pose>5 0 0 0 0 0</pose><!--póz a világhoz képest-->
+    <link name='box'>
+        <pose/>
+        <visual name='visual'>
+            <geometry>
+                <box>
+                    <size>0.5 10.0 2.0</size>
+                </box>
+            </geometry>
+            <!--adjunk hozzá anyagot (színt)-->
+            <material>
+                <ambient>0.0 0.0 1.0 1</ambient>
+                <diffuse>0.0 0.0 1.0 1</diffuse>
+                <specular>0.0 0.0 1.0 1</specular>
+            </material>
+        </visual>
+        <collision name='collision'>
+            <geometry>
+                <box>
+                    <size>0.5 10.0 2.0</size>
+                </box>
+            </geometry>
+        </collision>
+    </link>
+</model>
+
+

Önálló feladat

+

Adjunk hozzá a környezethez további két elemet az alábbi paraméterekkel: +1. elem + - neve (name): wall1 + - helyzete (pose): (0 12 0 0 0 1.5707) + - mérete: (0.5 10.0 2.0) + - anyaga, színe tetszőleges

+
    +
  1. elem
      +
    • neve (name): wall2
    • +
    • helyzete (pose): (0 -12 0 0 0 1.5707)
    • +
    • mérete: (0.5 10.0 2.0)
    • +
    • anyaga, színe tetszőleges
    • +
    +
  2. +
+

Szenzor hozzáadása

+

Az előző részekben kialakítottunk egy mozgatható robotszimulációt, viszont az autonóm működtetéséhez mindenképp szükséges valamilyen szenzor(ok) szimulációja is. A következő lépésekben IMU (Inertial Measurement Unit) szenzort, valamint LiDAR szenzort fogunk hozzáadni a korábban kialakított robothoz.

+
    +
  • IMU szenzor
  • +
+

Az IMU szenzor három elkülöníthető információt ad: +- A szenzor orientációja kvaternion formátumban. +- A szenzor szögsebessége (X, Y, Z) tengelyek körül. +- A szenzor lineáris gyorsulása (X, Y, Z) tengelyek mentén.

+

Az IMU szenzor szintén plugin segítségével adható hozzá. Definiáljuk az IMU szenzort a korábban létrehozott fájl szerkesztésével, a <world> címkék között:

+
<plugin filename="libignition-gazebo-imu-system.so"
+        name="ignition::gazebo::systems::Imu">
+</plugin>
+
+

A plugin definiálását követően definiáljuk a szenzorra vonatkozó paramétereket. A szenzor azon link paramétereit adja vissza, amelyhez hozzárendeljük. Mivel a robotra, vagyis a robot karosszériájára vonatkozó méréseket szeretnénk végezni, ezt a linket adjuk meg:

+
<sensor name="imu_sensor" type="imu">
+    <always_on>1</always_on>
+    <update_rate>1</update_rate>
+    <visualize>true</visualize>
+    <topic>imu</topic>
+</sensor>
+
+

Az alkalmazott paraméterek a következőek: +- <always_on>: ha az értéke 1, a szenzor mindig frissíteni fogja a kimenő adatát a frissítési rátának megfelelően. +- <update_rate>: a kimenő adat frissítési frekvenciája. +- <vizualize>: ha az értéke 1, a szenzor reprezentációja vizuálisan megjelenítésre kerül. +- <topic>: a kimenő adatokat tartalmazó topic neve.

+

Próbáljuk ki a létrehozott szenzort.

+
    +
  • Mentés után indítsuk el a szimulátort:
  • +
+
ign gazebo building_robot.sdf
+
+
    +
  • Egy másik terminálban írjuk ki az IMU adatait. Ha a billentyűzettel mozgatjuk a robotot, változás lesz megfigyelhető a szenzoradatokban:
  • +
+
ign topic -e -t /imu
+
+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szimulacio/ign_gazebo_01.png b/szimulacio/ign_gazebo_01.png new file mode 100644 index 0000000..42c04f7 Binary files /dev/null and b/szimulacio/ign_gazebo_01.png differ diff --git a/szimulacio/ign_gazebo_02.png b/szimulacio/ign_gazebo_02.png new file mode 100644 index 0000000..10788ba Binary files /dev/null and b/szimulacio/ign_gazebo_02.png differ diff --git a/szimulacio/index.html b/szimulacio/index.html new file mode 100644 index 0000000..23643ef --- /dev/null +++ b/szimulacio/index.html @@ -0,0 +1,2577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Szimuláció - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Szimuláció

+

A szimuláció során számítógépes modellen tanulmányozzuk a rendszer várható viselkedésését.

+

+

A szimuláció lényege tehát, hogy a kezdeti, akár komoly tesztelés nélküli programkódunkat ne a való világban az önvezető autónkon / robotunkon kezdjük el kipróbálni. Ennek ugyanis értelemszerű hátrányai lehetnek. Fontos azonban megjegyezni, hogy a szimulátor mindig a valóság egyszerűsített modelljét szimulálja csupán, így a szimulátorban jól működő kód nem mindig fog teljesen működni a való életben is.

+

Eddig egyedül a Turtlesim nevű 2D szimulátort használtuk. Egyszerűsége, oktatási jellege miatt közkedvelt, de a 3D világ természtesen ennnél sokkal összetettebb. Célszerű lehet tehát 3D szimulátorokat használni.

+ + + + + + + + + + + + + + + + + +
2D3D
TurtlesimGazebo, Carla, SVL, AWSIM, MVsim
+

Az ROS-által leginkább támogatott szimulátor a Gazebo, de érdemes megemlíteni az SVL-t, ebből saját verziónk is van a Nissan-ra optimalizáva, a Carla-t vagy a CoppeliaSim-et.

+ + +

Áttekintő videó a szimulátorokról

+
+ +

Simulate robots like never before with Open 3D Engine from Open Robotics on Vimeo.

+ +

További szimulátorok

+ +

+

Gazebo és ROS kompatibilitás

+

Az ROS és Gazebo kiválasztás a Picking the "Correct" Versions of ROS & Gazebo link alapján írjuk le. +Megjegyzés: a Gazebo 11 és előtt elévő verzióit Gazebo Classic néven, míg az utána lévőket Ignition Gazebo vagy röviden Ignition-ként említik.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GZ Citadel (LTS)GZ Fortress (LTS)GZ Garden
ROS 2 Rolling🔴🟢🟡
ROS 2 Humble (LTS)🔴🟢🟡
ROS 2 Foxy (LTS)🟢🔴🔴
ROS 1 Noetic (LTS)🟢🟡🔴
+
    +
  • 🟢 - Ajánlott kombináció
  • +
  • 🟡 - Lehetséges, de nem ajánott. Plusz munkával működésre lehet bírni együtt a két szoftvert.
  • +
  • 🔴 - Nem kompatibils / nem lehetséges.
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szimulacio/lgsvl_nissan/index.html b/szimulacio/lgsvl_nissan/index.html new file mode 100644 index 0000000..72d0e64 --- /dev/null +++ b/szimulacio/lgsvl_nissan/index.html @@ -0,0 +1,2471 @@ + + + + + + + + + + + + + + + + + + + + + + + + + LGSVL Nissan - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/szimulacio/robot.png b/szimulacio/robot.png new file mode 100644 index 0000000..27505ed Binary files /dev/null and b/szimulacio/robot.png differ diff --git a/telepites/index.html b/telepites/index.html new file mode 100644 index 0000000..b1ede4d --- /dev/null +++ b/telepites/index.html @@ -0,0 +1,2531 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Telepítés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Telepítés

+
+

ROS 2

+

ROS 1 verziókat csak történelmi okokból tárgyalunk, a jelenlegi fejlesztésekhez a ROS 2-t ajánljuk.

+
+

ROS 1 alapvetően Linux rendszereken támogatott, bár voltak próbálkozások más operációs rendszerekre is. Ezzel szemben az ROS 2 már támogatja a natív Windows, Mac OS vagy egyéb Real-Time operációs rendszen történő futtatást. Tehát alapvetően négy lehetőség adott:

+
    +
  1. Dual boot, Windows mellé telepített natív Linux (leginkább Ubuntu) ✅ leírás
  2. +
  3. Windows WSL2, könnyűsúlyú Linux virtuális gép ✅ leírás
  4. +
  5. Virtuális gép Windowsra 🟠
  6. +
  7. Windows build 🟠
  8. +
+

Ebből a 4 lehetőségből az első kettőt ajánljuk, de telmészetesen a többi sem tiltott. A dual boot betekintést nyújt a Linux világba, ami egy mérnöknél hasznos tudást jelent manapság. Telepítésnél körültekintően kell eljárni, hiszen egy rossz beállítás adatvesztést okoz, így a biztonsági mentés is ajánlott. A WSL (Windows Subsystem for Linux) egy könnyűsúlyú kompatibilitási réteg Linux-alapú elemek futtatásához Windows 10, vagy Windows 11 alapú rendszereken. Ahogy a következő ábrán is látszik, a Linux kernel ugyanolyan egyszerűen érheti el a hardverelemeket (CPU, memória, GPU), mint a Windows kernel. Ehhez képest a virtuális gép (3. lehetőség) egy jóval lassabb , több absztrakciós réteget használó megoldás, annak ajánlott, akinek vagy nagyon modern, gyors gépe van, vagy már eleve telepített ilyen rendszereket. A natív Windows build (4. lehetőség) elvileg adott, de mivel a dokumenátió túlnyomó része Linuxra érhető el, így nagyon sok extra munkát fog jelenteni.

+

Az első három opció szemléltetése:

+

wsl áttekintés

+

Támogatott operációs rendszerek és ROS disztibúciók

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operációs rendszertámogatotttámogatotttámogatott
Ubuntu 18.04ROS melodic
Ubuntu 20.04ROS noeticROS2 humble
Ubuntu 22.04ROS2 humble
Windows 10 (natív)ROS2 humble
Windows 11 (natív)ROS2 humble
Windows 10 (WSL2)ROS melodicROS noeticROS2 humble
Windows 11 (WSL2)ROS melodicROS noeticROS2 humble
+

Static Badge

+

Static Badge

+

Static Badge

+
+

Tip

+

Az ROS 1 melodic python 2.7-et támogat, ez nem ajánlott.

+
+

Ubuntu és Python

+
    +
  • Ubuntu 18.04.6 LTS Python 2.7.17
  • +
  • Ubuntu 20.04.4 LTS Python 3.8.10
  • +
  • Ubuntu 22.04.1 LTS Python 3.10.6
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/telepites/install_humble.sh b/telepites/install_humble.sh new file mode 100644 index 0000000..12f379b --- /dev/null +++ b/telepites/install_humble.sh @@ -0,0 +1,102 @@ + +echo "First arg: $1" +if [ "$1" != "campus" ] +then + echo "++++ home install settings ++++" +else + echo "!!!! campus settings !!!!" + sleep 2 +fi + +echo "++++ install script start ++++" +echo "" + +locale # check for UTF-8 + +sudo apt update && sudo apt install locales +sudo locale-gen en_US en_US.UTF-8 +sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +export LANG=en_US.UTF-8 + +locale # verify settings + +sudo apt install software-properties-common -y +sudo add-apt-repository universe -y + +sudo apt update -y && sudo apt install curl -y +sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg + +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null + + +sudo apt update -y +sudo apt upgrade -y + +echo ""y +echo "++++ install ros 2 humble ++++" +echo "" + +sudo apt install ros-humble-desktop -y +sudo apt install ros-dev-tools -y +sudo apt install ros-humble-rqt-tf-tree -y +sudo apt install python3-colcon-common-extensions -y +sudo apt install git -y + + +echo "" >> ~/.bashrc +echo "#### ADDED BY INSTALL SCRIPT wget https://raw.githubusercontent.com/sze-info/arj/main/docs/telepites/install_humble.sh" >> ~/.bashrc +echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc +echo "export RCUTILS_COLORIZED_OUTPUT=1" >> ~/.bashrc +echo "export LIBGL_ALWAYS_SOFTWARE=1" >> ~/.bashrc +echo "export ROS_DOMAIN_ID="$(( $RANDOM % 100 + 1 )) >> ~/.bashrc +echo "export ROS_LOCALHOST_ONLY=1" >> ~/.bashrc +echo "source /usr/share/colcon_cd/function/colcon_cd.sh" >> ~/.bashrc +echo "export _colcon_cd_root=/opt/ros/humble/" >> ~/.bashrc +echo "source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash" >> ~/.bashrc + +echo "" +echo "++++ create workspace ++++" +echo "" + + +mkdir -p ~/ros2_ws/src +cd ~/ros2_ws/src +git clone https://github.com/sze-info/arj_packages +git clone https://github.com/jkk-research/wayp_plan_tools +git clone https://github.com/jkk-research/sim_wayp_plan_tools +git clone https://github.com/dottantgal/ros2_pid_library + +cd ~/ros2_ws +source ~/.bashrc +colcon build + +echo "" +echo "++++ install gazebo ignition fortress ++++" +echo "" + +sudo apt-get update -y +sudo apt-get install lsb-release wget gnupg -y + +sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null +sudo apt-get update -y +sudo apt-get install ignition-fortress -y +sudo apt install ros-humble-foxglove-bridge -y +sudo apt install mc -y +sudo apt install ros-humble-rosbag2-storage-mcap ros-humble-rosbag2 -y +sudo apt install ros-humble-ros-gz -y + +echo "First arg: $1" +if [ "$1" != "campus" ] +then + echo "" +else + echo "!!!! campus settings !!!!" + sudo mkdir /mnt/kozos + #sudo mount -t drvfs '\\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása' /mnt/kozos + echo "\\\\\\\\fs-kab.eik.sze.hu\C100\kozos\GKNB_AUTM078_Autonóm_robotok_és_járművek_programozása /mnt/kozos drvfs defaults,uid=1000,gid=1000 0 0" | sudo tee -a /etc/fstab +fi + +echo "" +echo "++++ install script end ++++" +echo "" \ No newline at end of file diff --git a/telepites/ros_humble/index.html b/telepites/ros_humble/index.html new file mode 100644 index 0000000..a75be6c --- /dev/null +++ b/telepites/ros_humble/index.html @@ -0,0 +1,2701 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROS 2 humble telepítése - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

ROS 2 humble

+
+

Egyszerű telepítés

+

A telepítés lépésről-lépésre is végrehajtható, de készítettünk egy egyszerű shell script alapú telepítést is.

+
+

Ahogy abevezetőben írtuk, alapvetően négy lehetőség adott ROS 2 Humble telepítésére:

+
    +
  1. Dual boot, Windows mellé telepített natív Linux (leginkább Ubuntu) ✅ leírás
  2. +
  3. Windows WSL2, könnyűsúlyú Linux virtuális gép ✅ leírás
  4. +
  5. Virtuális gép Windowsra 🟠
  6. +
  7. Windows build 🟠
  8. +
+

Ebből a 4 lehetőségből az első kettőt ajánljuk, de telmészetesen a többi sem tiltott. A dual boot betekintést nyújt a Linux világba, ami egy mérnöknél hasznos tudást jelent manapság. Telepítésnél körültekintően kell eljárni, hiszen egy rossz beállítás adatvesztést okoz, így a biztonsági mentés is ajánlott. A WSL (Windows Subsystem for Linux) egy könnyűsúlyú kompatibilitási réteg Linux-alapú elemek futtatásához Windows 10, vagy Windows 11 alapú rendszereken. Ahogy a következő ábrán is látszik, a Linux kernel ugyanolyan egyszerűen érheti el a hardverelemeket (CPU, memória, GPU stb), mint a Windows kernel. Ehhez képest a virtuális gép (3. lehetőség) egy jóval lassabb, több absztrakciós réteget használó megoldás, annak ajánlott, akinek vagy nagyon modern, gyors gépe van, vagy már eleve telepített ilyen rendszereket. A natív Windows build (4. lehetőség) elvileg adott, de mivel a dokumenátió túlnyomó része Linuxra érhető el, így nagyon sok extra munkát fog jelenteni.

+

Az első három opció szemléltetése:

+

wsl áttekintés

+

Telepítés

+

A következő leírás Ubuntu 22.04 Jammyre vonatkozik. Megjegyzés, hogy más verziók is támogatottak, ezekre vonatkozó telepítés és leírások elérhetőek itt: docs.ros.org/en/humble/Installation/Alternatives.html

+

A következő leírás a docs.ros.org/en/humble/Installation.html alapszik.

+

Nyelv beállítása

+
+

Note

+

Ez a lépés általában kihagyható

+
+

Győződjön meg arról, hogy olyan területi beállítással rendelkezik, amely támogatja az UTF-8 szabványt.

+
locale # UTF-8 ellenőrzése
+
+sudo apt update && sudo apt install locales
+sudo locale-gen en_US en_US.UTF-8
+sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
+export LANG=en_US.UTF-8
+
+locale # beállítások ellenőrzése
+
+

Források beállítása

+

Hozzá kell adnia a ROS 2 apt tárolót a rendszeréhez.

+

Először győződjön meg arról, hogy az Ubuntu Universe adattár engedélyezve van.

+
sudo apt install software-properties-common
+sudo add-apt-repository universe
+
+

ROS 2 GPG kulcs hozzáadása, apt-vel.

+
sudo apt update && sudo apt install curl -y
+sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
+
+

Ezután következik a tároló hozzáadása a forráslistához.

+
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
+
+

ROS 2 csomagok telepítése

+

Frissítés:

+
sudo apt update
+
+

A ROS 2 csomagok gyakran frissített Ubuntu rendszerekre épülnek. Mindig ajánlott, hogy új csomagok telepítése előtt meggyőződni arról, hogy rendszere naprakész-e. +

sudo apt upgrade
+

+

Desktop telepítés: ROS, RViz, demók, oktatóanyagok telepítése: +

sudo apt install ros-humble-desktop
+

+

Fejlesztőeszközök, fordítók és egyéb eszközök ROS-csomagok készítéséhez: +

sudo apt install ros-dev-tools
+

+

Source

+

Állítsa be környezetét a következő fájl source-olásával:

+
source /opt/ros/humble/setup.bash
+
+

Tipp: ezt meg lehet tenni a .bashrc fájlban is echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc.

+

Telepítés ellenőrzése

+

Ellenőrizzük a telepítés helyességét, a ros2 topic list paranccsal.

+
$ ros2 topic list
+
+/parameter_events
+/rosout 
+
+

Ha minden rendben, akkor a fenti két topicnak kell megjelennie. Ezután lehet megismerni az egyszerű példa node-ok használatát: docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools.html

+

Telepítés utáni ajánlott beállítások

+

Konzol színek

+

Alapértelmezés szerint a konzol kimenet nem színezett, de ezt célszerű beállítani az RCUTILS_COLORIZED_OUTPUT környezeti változóval (akár bashrc-be írva). Például:

+
export RCUTILS_COLORIZED_OUTPUT=1 
+
+

RCUTILS_COLORIZED_OUTPUT

+

Részletek: docs.ros.org/en/humble/Tutorials/Demos/Logging-and-logger-configuration.html#id14

+

colcon_cd

+

Szintén célszerű beállítani a colcon_cd paranccsot, így gyorsan válthatunk munkakönyvtárát egy csomag könyvtárára. Példaként a colcon_cd some_ros_package parancsra gyorsan a ~/ros2_ws/src/some_ros_package könyvtárba ugorhatunk.

+

Részletek: docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Colcon-Tutorial.html#setup-colcon-cd

+

Otthoni / géptermi telepítés

+

Gépteremben a következő install_humble.sh fájlt (shell scriptet) futtatuk minden gépen.

+

wget https://raw.githubusercontent.com/sze-info/arj/main/docs/telepites/install_humble.sh
+
+
sudo chmod +x install_humble.sh
+

+

Otthon: +

./install_humble.sh
+
+Gépteremben: +
./install_humble.sh campus
+

+

Workspace reset

+

Ha szeretnénk a teljes ros2_ws-t törölni, majd újra klónozni és buildelni (~5 percig eltart), akkor a következő egyetlen hoszú paranccsal megtehetjük:

+
cd ~ ; rm ws_reset.sh; wget https://raw.githubusercontent.com/sze-info/arj/main/docs/telepites/ws_reset.sh; sudo chmod +x ws_reset.sh; ./ws_reset.sh
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/telepites/ubuntu/index.html b/telepites/ubuntu/index.html new file mode 100644 index 0000000..9a22686 --- /dev/null +++ b/telepites/ubuntu/index.html @@ -0,0 +1,2475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ubuntu dual boot - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Ubuntu dual boot

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/telepites/win10/index.html b/telepites/win10/index.html new file mode 100644 index 0000000..6c47e8a --- /dev/null +++ b/telepites/win10/index.html @@ -0,0 +1,2647 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Windows WSL2 - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Windows WSL2

+

wsl

+

A Windows Subsystem for Linux egy kompatibilitási réteg Linux-alapú elemek natív futtatásához Windows 10, vagy Windows 11 alapú rendszereken. Akkor érdemes választani a WSL használatát, ha nem szeretnétek natív Ubuntu-t (pl 18.04 / 22.04) telepíteni a számítógépeitekre. A tantárgyban használható rendszer többféle módon is létrehozható:

+
    +
  • WSL telepítése és Snapshot importálása link
  • +
  • WSL telepítése és ROS installálása Script segítségével link
  • +
+

WSL telepítése és Snapshot importálása

+

A telepítést bemutató videó:

+ + +

A videó lépései szövegesen:

+
    +
  1. WSL snapshot (backup fájl) letöltése: WSL snapshot letöltése ~2.5 GB
  2. +
  3. Snapshot kicsomagolása .zip >> .tar
  4. +
  5. Powershell (Admin) WSL feature bekapcsolása, majd WSL telepítése: +
    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    +
    +
    wsl --install --no-distribution
    +
  6. +
  7. Powershell, WSL Snapshot fájl (tar) importálás: +
    wsl --import ajr1 .\ajr1\ .\ajr24a.tar
    +
  8. +
  9. VS code és WSL kiegészítő telepítése:
  10. +
+

wsl03

+
+

Danger

+

A wsl -l -v parancs listázza a telepített WSL verziókat. A VERSION oszlopnak 2-nek kell lennie, különben a WSL elavult verzióját telepítettük. Példa helyes kimenetre: +

NAME            STATE           VERSION
+Ubuntu          Stopped         2
+Ubuntu-22.04    Stopped         2
+Ubuntu-24.04    Running         2
+ajr1            Stopped         2
+
+Amennyiben a VERSION oszlopban 1-es szerepel wsl --update paranccsal lehet a verziót frissíteni.

+
+

További ajánlott beállítások

+

A Windows Terminal programban ajánlott beállítani a Deafault Profile-t az ajr1-re, hogy mindig ezzel induljon a program. Továbbá az Open windows from previous session beállítás is hasznos lehet, hogy a legutóbbi állapotban induljon a program (pl. több panellel).s

+

wsl04

+

A paneleket ezután a Alt+Shift+minus vagy Alt+Shift+plus billentyűkombinációval lehet létrehozni. Ez szétosztja a terminál ablakot (Split pane) több részre vertikálisan vagy horizontálisan.

+

wsl05

+

WSL telepítése és ROS installálása Script segítségével

+

A WSL telepítését bemutató Windows 11-es videó (Windows 10 verzió lejjebb, de nagyrészt megegyező tartalommal):

+ + +

A videó lépései szövegesen:

+
    +
  • Rendszergazdaként futtatva nyissatok egy PowerShell ablakot.
  • +
  • Másoljátok be az alábbi parancsot. Ezzel engedélyezitek a WSL használatát. +
    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    +
  • +
  • Indítsátok újra a számítógépet az Y betű beírásával. (opcionális)
  • +
  • Nyissátok meg a Microsoft Store-t, és keressetek rá a Windows Subsystem for Linux Preview-ra. Telepítsétek.
  • +
  • Szintén a Microsoft Store-ban keressetek rá az Ubuntu 22.04-re, és telepítsétek, vagy PowerShell (Admin): +
    wsl --install -d Ubuntu-22.04
    +
  • +
  • A könnyebb kezelhetőség érdekében érdemes telepíteni a Windows Terminal programot is. Szintén a Microsoft Store-ban keressetek rá a Windows Terminal-ra, és telepítsétek.
  • +
  • Indítsátok el a Windows Terminal programot, és a Ctrl+, (Control és vessző) billentyűkombinációval nyissátok meg a beállításokat. A Default Profile beállítási sor legördülő listájából válasszátok az Ubuntu 22.04-et.
  • +
  • Indítsátok újra a Windows Terminal-t. Az első induláskor adjatok meg tetszőleges felhasználónevet és jelszót.
  • +
  • A megoldás kidolgozásához a VS Code szerkesztőt javasoljuk. Telepítsétek innen: code.visualstudio.com/download
  • +
  • Végül telepítsétek a VS Code Remote Development kiegészítőjét, hogy WSL használatával is elérhető legyen: marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack
  • +
+

A WSL telepítését bemutató Windows 10-es videó itt érhető el:

+ + +

A VS Code telepítéséhez itt találtok útmutatót:

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/telepites/ws_reset.sh b/telepites/ws_reset.sh new file mode 100644 index 0000000..d25546a --- /dev/null +++ b/telepites/ws_reset.sh @@ -0,0 +1,23 @@ +echo "++++ ros2_ws will be deleted, cloned (again) and built ++++" +echo "" +cd ~ + +# delete ros2_ws +rm -r ~/ros2_ws/ + +# create ros2_ws +mkdir -p ~/ros2_ws/src + +# clone arj_packages and some other packages +cd ~/ros2_ws/src +git clone https://github.com/sze-info/arj_packages +git clone https://github.com/jkk-research/wayp_plan_tools +git clone https://github.com/jkk-research/sim_wayp_plan_tools +git clone https://github.com/dottantgal/ros2_pid_library + +# build ros2_ws +cd ~/ros2_ws +colcon build +source ~/.bashrc + + diff --git a/telepites/wsl01.svg b/telepites/wsl01.svg new file mode 100644 index 0000000..4dff190 --- /dev/null +++ b/telepites/wsl01.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/telepites/wsl02.svg b/telepites/wsl02.svg new file mode 100644 index 0000000..8344a9d --- /dev/null +++ b/telepites/wsl02.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/telepites/wsl03.png b/telepites/wsl03.png new file mode 100644 index 0000000..444ddfe Binary files /dev/null and b/telepites/wsl03.png differ diff --git a/telepites/wsl04.png b/telepites/wsl04.png new file mode 100644 index 0000000..484dc06 Binary files /dev/null and b/telepites/wsl04.png differ diff --git a/telepites/wsl05.png b/telepites/wsl05.png new file mode 100644 index 0000000..f57a539 Binary files /dev/null and b/telepites/wsl05.png differ diff --git a/telepites/wsl_overview01.svg b/telepites/wsl_overview01.svg new file mode 100644 index 0000000..631df87 --- /dev/null +++ b/telepites/wsl_overview01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tervezes/WerlingOptimalTrajectoryGenerationforDynamicStreetScenariosinaFrenetFrame.pdf b/tervezes/WerlingOptimalTrajectoryGenerationforDynamicStreetScenariosinaFrenetFrame.pdf new file mode 100644 index 0000000..278f6fa Binary files /dev/null and b/tervezes/WerlingOptimalTrajectoryGenerationforDynamicStreetScenariosinaFrenetFrame.pdf differ diff --git a/tervezes/abrak/Frenet_frame.png b/tervezes/abrak/Frenet_frame.png new file mode 100644 index 0000000..726c35f Binary files /dev/null and b/tervezes/abrak/Frenet_frame.png differ diff --git a/tervezes/abrak/Multiple_polynomials.png b/tervezes/abrak/Multiple_polynomials.png new file mode 100644 index 0000000..66d43c9 Binary files /dev/null and b/tervezes/abrak/Multiple_polynomials.png differ diff --git a/tervezes/abrak/Planning_in_frenet.png b/tervezes/abrak/Planning_in_frenet.png new file mode 100644 index 0000000..4b293d2 Binary files /dev/null and b/tervezes/abrak/Planning_in_frenet.png differ diff --git a/tervezes/abrak/local_speed_planning.png b/tervezes/abrak/local_speed_planning.png new file mode 100644 index 0000000..1fd0948 Binary files /dev/null and b/tervezes/abrak/local_speed_planning.png differ diff --git a/tervezes/abrak/longitudinal_planning.png b/tervezes/abrak/longitudinal_planning.png new file mode 100644 index 0000000..48644cf Binary files /dev/null and b/tervezes/abrak/longitudinal_planning.png differ diff --git a/tervezes/abrak/polinomial_traj.PNG b/tervezes/abrak/polinomial_traj.PNG new file mode 100644 index 0000000..e261e28 Binary files /dev/null and b/tervezes/abrak/polinomial_traj.PNG differ diff --git a/tervezes/gazebo_turtlebot01.png b/tervezes/gazebo_turtlebot01.png new file mode 100644 index 0000000..b2119cc Binary files /dev/null and b/tervezes/gazebo_turtlebot01.png differ diff --git a/tervezes/index.html b/tervezes/index.html new file mode 100644 index 0000000..fc5edf8 --- /dev/null +++ b/tervezes/index.html @@ -0,0 +1,3156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Tervezés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Tervezés

+

Megkülönböztethetünk globális tervezés és lokális tervezést.

+

+

A tervezés mint fogalom arra a kérdésre ad választ, hogy hogyan jutunk el A-ból B pontba a megfelelő kritériumok mellett. A tervezésnek két alrésze van a pálya- vagy útvonaltervezés, amely megmondja hogy az adott szakaszon merre kell menni illetve a trajektóriatervezés, amely azt mondja meg hogy az adott szakaszon milyen sebességel kell haladnia az adott járműnek.

+

A tervezési feladat jellege szerint megkülönböztettünk globális és lokális tervezést. A két tervezési módszer különbségeit az alábbi táblázat foglalja össze:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Globális tervezésLokális tervezés
Térkép alapúSzenzor alapú
Ismert terep/munkaterületIsmeretlen terület
Az út tervezés előbb történik mint a mozgásAz út tervezés és a mozgás egyszerre történik
Nincs szigorú követelmény a számítási időreKövetelmény hogy valós időben működjön
+

A tervezés végeredménye mind lokális és globális esetben egy diszkrét pontokra osztott szakasz, amelynek minden pontja tartalmaz pozíció, orientáció és sebesség információkat, amit röviden trajektóriának hívunk: +trajektoria.

+
flowchart LR
+subgraph Plan [Tervezés]
+  G[Globális<br/>tervezés]:::red -->|útvonal| L[Lokális<br/>tervezés]:::red
+end
+subgraph Perception [Észlelés]
+  T[Térképezés<br/>/észlelés/]:::light 
+  H[Lokalizáció<br/>/észlelés/]:::light
+  P[Predikció<br/>/észlelés/]:::light 
+end
+T --->|térkép| L
+H --->|pose| L
+P --->|prediktált objektumok| L
+subgraph Control [Szabályozás]
+  L --> |trajektória| S[Szabályozás]:::light 
+end
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+

Globális tervezés

+

Bevezetés

+

Az alábbi német nyelvű, de angol PPT-t és feliratot tartalmazó videó a TU München tananyagának része, a témában jó összefoglaló:

+ + +

A Videóhoz tartozó PDF fájl elérhető itt

+

Ismertebb globális tervező algoritmusok:

+
    +
  • RRT (Rapidly exploring random tree): Az RRT egy mintavételezés alapú módszer bejárandó globális tér felderítésére és útvonalak tervezésére. Megjegyzés: bizonyos esetekben lokális tervezőként is használják. Az algoritmus random (véletlenszerű) módon választ ki pontokat és növekvő irányban kiterjeszti a fát azáltal, hogy a legközelebbi már meglévő pontokhoz kapcsolja az új pontokat. További információ: en.wikipedia.org/wiki/Rapidly_exploring_random_tree.
  • +
  • Informed-RRT: Az Informed-RRT az alap RRT kiterjesztése, amely heurisztikát használ a cél felé történő hatékonyabb felderítésre. Az algoritmus úgy tervezi az útvonalakat, hogy először a közelebbi területeket fedezze fel, majd a későbbi fázisokban elmozduljon a távolabbi területek felé.
  • +
  • A-star: Az A* algoritmus (ejtsd "A csillag") gráfbejáró és útvonalkeresési algoritmus, amelyet teljessége, hatékonysága miatt gyakran régen előszeretettel használtak. Az egyik fő gyakorlati hátránya az $$ O(b^{d}) $$ tárhelybonyolultsága, mivel az összes generált csomópontot eltárolja a memóriában. Így a gyakorlati útkereső rendszerekben általában jobban teljesítenek nála olyan algoritmusok, amelyek képesek a gráf előfeldolgozására a jobb teljesítmény érdekében. További információ: hu.wikipedia.org/wiki/A*_algoritmus.
  • +
  • D-star: A D algoritmus (ejtsd "D csillag") a "Dynamic A-star" rövidítése. Ez az algoritmus egy módosított változata az A algoritmusnak, amely dinamikus környezetekben használható. A Dynamic A-star algoritmus folyamatosan frissíti az útvonalat, miközben a robot halad az úton, hogy alkalmazkodjon a változó körülményekhez vagy akadályokhoz. További információ: en.wikipedia.org/wiki/D* .
  • +
  • Dijkstra: A Dijkstra algoritmus az egyik legismertebb és leggyakrabban használt algoritmus a legrövidebb út keresésére egy gráfban. Ez egy szélességi keresőalgoritmus, amely iteratívan bővíti a fát a kezdőpontból kiindulva, és kiválasztja a legközelebbi még nem látogatott csúcsot. További információ: en.wikipedia.org/wiki/Dijkstra's_algorithm.
  • +
+

Jó tudni, hogy a fenti algoritmusokanak számos változata, továbbfejlesztése ismert.

+

Utazó ügynök probléma

+

Az utazó ügynök probléma (TSP traveling salesman problem) egy jól ismert kombinatorikus optimalizációs probléma, amely a számítástudomány és a matematika területén jelent meg. A probléma lényege az, hogy az utazó ügynöknek egy adott városokból álló halmazt kell meglátogatnia, és vissza kell térnie a kiindulási városba a lehető legrövidebb úton úgy, hogy minden várost pontosan egyszer látogat meg. Tobábbi információ: hu.wikipedia.org/wiki/Az_utazó_ügynök_problémája.

+

Formálisan megfogalmazva, legyen adott egy irányított súlyozott gráf, ahol a csomópontok reprezentálják a városokat, az élek a városok közötti utakat jelölik, és a súlyok az élek hosszát jelölik. A cél az, hogy találjunk egy olyan Hamilton-kört (kör, amely minden csomópontot pontosan egyszer érint), amelynek összsúlya minimális. A probléma az NP-nehéz osztályba tartozik, ami azt jelenti, hogy nincs ismert hatékony algoritmus, amely mindig garantáltan megtalálja a legoptimálisabb megoldást polinomiális időben a városok számával arányosan.

+

Autonóm járművek és robotika vonatkozásában legtöbbször nem a klasszikus TSP probléma merül fel, hanem annak derivátuma, hiszen például egy autonóm jármű esetében pontosan tudjuk honnan indulunk és hova érkezünk. Ez a klasszikus utazó ügynök probléma esetén nem ismert feltétel.

+

Lokális tervezés

+

Bevezetés

+

Az alábbi német nyelvű, de angol PPT-t és feliratot tartalmazó videó a TU München tananyagának része, a témában jó összefoglaló:

+ + +

A Videóhoz tartozó PDF fájl elérhető itt.

+

Motiváció

+

A lokális tervezés voltaképp a valós időben mért, dinamikusan változó körülményekre adott tervezési válasz. Mit értünk ez alatt? A legegyszerűbb példa, ha a globális tervezést gyakorlatilag egy útvonal megtervezéséhez (pl. hogyan jussak el A-ból B-be) hasonlítjuk, a lokális tervezést pedig az adott sávban, adott forgalmi helyzetben történő feladathoz hasonlítjuk. Azonban láthatjuk, hogy egy tervezési szint "lokális" és "globális" mivoltja nem mindig különül el 100%-ban egymástól. Pl. megtervezzük, hogy az M1-es autópályán szeretnénk haladni. Ezen belül több sáv is van, így melyiket válasszuk? Alapból a külső sávot választjuk, ezt tekinhetjük a globális trajektóriának. Ugyanakkor menetközben sávot kell váltanunk, és így a belső sávot követjük. Ezt egy út során többször megtesszük. A teljes útra vetítve így a követni kívánt sáv időnként a belső, időnként a külső sáv lesz. Ezt előre nem tudjuk megmondani, így a legelső globális trajektória definíciót nem elégítjük ki. Tekinthetjük lokális tervezési problémának, viszont az, hogy a belső vagy külső sávot követjük, nem függ külső tényezőktől, kizárólag a döntés maga függ attól (pl. sávot váltunk egy előttünk haladó autó miatt), viszont ha már sávot váltottunk, az új sáv által kijelölt útvonal megintcsak nem függ dinamikus tényezőktől. +Ezeket az ellentmondásokat többféleképpen is feloldhatjuk:

+
    +
  • egy előre eltervezett útvonalat tekintünk globálisnak (ez esetben ez a külső sáv), mind módosítás lokális, vagy
  • +
  • magát az autópályán haladást tekintjük globális útvonalnak, ami így nem függ a sávoktól, bevezetünk egy középső szintet, nevezzük globális trajektóriának, amely ez esetben két alternatív útvonalat jelent (külső vagy belső sáv), és egy lokális trajektóriát, ami ennek a módosítása valós idejű információk alapján, vagy
  • +
  • a globális trajektória sem fix, hanem időben változhat, de csak ritkán, ha erre külső trigger jelt ad (pl. sávváltás).
  • +
+

Ebben a fejezetben a lokális trajektória megtervezéséhéz szükséges alapokat vesszük át, így a következőkben kizárólag erre a szintre koncentrálunk. A fenti példában szereplő lokális tervezési feladatról mind elmondható, hogy:

+
    +
  • adott hozzá valamilyen globális útvonal (pl. sáv), amit alapul veszünk,
  • +
  • figyelembe kell venni a valósidejű változókat (pl. más járművek),
  • +
  • mindig a jármű által befutható útvonalat kell tervezni, azaz a lekövető szabályzás szempontjából stabil, az utasok számára pedig komfortos; ezt röviden mondhatjuk "kinetikailag jól kondicionált" útvonalnak is,
  • +
  • az útvonal legyen biztonságos, azaz ne sértsen határokat illetve kellő távolságot tartson más objektumoktól.
  • +
+

Ahhoz, hogy ezeket a célokat teljesíteni tudjuk, tudni kell, pontosan a globális útvonalat, mérni kell a dinamikus változókat, ismernünk kell a járművet illetve tudnunk kell, pontosan mit jelent az utasok számára a "komfort". +Emellett fontos kiemelni, hogy a lokális útvonal a legtöbbször nem kizárólag pontok halmaza. A trajektória reprezentálására valamilyen modellt használunk, azaz geometriailag kompakt formában írjuk le. Ez a gyakorlatban jelenthet pl. polinomiális formát, Euler-görbét, Spline-t...stb. Ezek a görbe leírások mind véges számú paraméterrel írnak le egy görbét. Ahhoz, hogy a görbe egy pontját megkapjuk, a görbét leíró függvényt kiértékeljük egy adott X távolságon. Ez a megközelítés azért hasznos, mert így hosszú görbéket is kevés paraméter segítségével tudunk leírni, és így a megvalósítás során memóriát és futásidőt spórolunk. Továbbá az egyenlet deriváltjai további mennyiségeket (pl. orientáció, görbület) adnak meg, és így a szabályzás számára ezeket könnyen elő tudjuk állítani.

+

Lokális tervező algoritmusok

+

A lokális megoldásokat, ahogy a bevezető videóban is láthattuk nehéz csoportosítani, rendszerezni, a megoldások gyakran nem tiszán egy módszertant használnak. Példa erre a State Lattice tervező, ami grid-szerű rács szerkezeten dolgozik, de gráf-szerű keresést használ. Ide többnyire olyan ismertebb lokális tervező algoritmusokat, algoritmuscsaládokat sorolunk fel, amiknek van nyílt forrás kódú implementációjuk:

+
    +
  • DWA (Dynamic Window Approach): A robotikai / autonóm mozgástervezésben a DWA megközelítés egy online ütközés elkerülési stratégia, útvonaltervezéséhez és navigációjához dinamikus környezetben. Ahogy a neve is mutatja az előrehaladás során egy dinamikus ablakot tol maga előtt a robot / jármű. Több lehetséges irányt (pontosabban trajaktóriát) vesz számba, majd ebből azt az állapotot választásztja, amit a lekisebb költségűnek ítél. További információ: en.wikipedia.org/wiki/Dynamic_window_approach.
  • +
  • TEB (Timed Elastic Band): Szintén online, mozgó robotok trajektóriájának tervezésére és követésére szolgál dinamikus környezetben. A TEB algoritmus különösen hasznos nem-holonóm robotok (mint például az autók) számára, amelyeknek korlátozott a mozgási szabadságuk. A módszer lokálisan optimalizálja a robot pályáját a pályafutási idő, az akadályoktól való elválasztás és a futás közbeni kinodinamikai korlátok betartása tekintetében. Neve az gumi / elasztikus szalagra utal, ami könnyedén hajtogatható a megfeleő irányba. További információ: github.com/rst-tu-dortmund/teb_local_planner.
  • +
  • State Lattice: A robot / jármű kinodinamikai korlátai az állapotrács gráfban vannak kódolva, és ebben a gráfban bármely útvonal megvalósítható. A gráf felépítése után bármilyen gráfkereső algoritmus használható a tervezéshez. navigation.ros.org/configuration/packages/smac/configuring-smac-lattice.html
  • +
  • RRT (Rapidly exploring random tree): RRT-ről már volt szó a globális tervezéskor is, de lokális módszereknél is használják.
  • +
+

Algroitmuscsaládok:

+
    +
  • Gráf alapú megoldások: A folytonos térben gráf segítségével kereső megoldások tartoznak ide. Gyakran segítségképpen valamilyen lokális térképmodellt használnak, mint a Lanelet2. Ide tartozik pl. az Autoware obstacle_avoidance_planner.
  • +
  • Grid alapú megoldások: A folytonos tér rácsszerű diszkretizálásával keletkező grid-et használó algoritmusok tartoznak ide. Gyakran használjuk a voxel grid, illetve az occupancy grid (foglatsági rács) kifejezést a diszkrét tér leírására. Előnye, hogy bizonyos algoritmusok könnyebben További információ: github.com/jkk-research/pointcloud_to_grid, https://github.com/ANYbotics/grid_map. Bizonyos DWA megoldások ebbe családba tartoznak.
  • +
  • Potential field alapú megoldások: A potenciáltér alapú tervezés (APF) során a robotot vonzó és taszító erőkkel modellezik a környezetben lévő objektumoktól. A grid alapú módszerekkel ellentétben itt maga a mező mondja meg, hogy milyen távol kerüljünk egy objektumot, míg a grid alapon a tervező határozza ezt meg. Másik különbség, hogy a potenciáltér folytonos (nincs diszkretizálás), míg a grid tér diszkrét. További információ: en.wikipedia.org/wiki/Motion_planning#Artificial_potential_fields, illetve itt is található egy APF (artificial potential field) alapú megoldás.
  • +
  • Frenét rendszer alapú megoldások: A Frenét-koordinátarendszerben a robot állapota két dimenzióban van megadva: a hosszanti és a laterális pozíció. A hosszanti tengelyen a robot aktuális helyzete és sebessége található, míg a laterális tengelyen a robot pozíciója az útvonalhoz képest. További információ: roboticsknowledgebase.com/wiki/planning/frenet-frame-planning/
  • +
+

Megjegyzés: TU München tananyaga hasonlóképpen, de más hangsúlyokkal osztja fel a lokális tervező algoritmusokak: Graph-Based methods, Variational methods, Incremental Methods, Hybrid Methods.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MódszerekTulajdonságokKorlátok
Inkrementális módszerek (pl. DWA)Valószínűleg teljesA véges időn belüli megoldás nem garantált
Variációs módszerek (pl. APF)Nincs diszkretizálásHelyi optimumot talál
Alacsony számítási időKöltségfüggő solver
Gráf alapú módszerek (pl Lanelet2-alapú)Megtalálja a globális optimumotA dimenzionalitás átka
Rugalmas költségfüggvényDiskretizált megoldás
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodsPropertiesLimitations
Incremental Methods (eg. DWA)Probabilistically completeSolution in finite time not guaranteed
Variational Methods (eg. APF)No discretizationFinds local optimum
Low computation timeCost dependent solver
Graph-Based Methods (eg. pl Lanelet2-based)Finds global optimumCurse of dimensionality
Flexible cost functionDiscretized solution
+

Tervezési példa

+

Az ebben a fejezetben szereplő példát Werling és mtsai. munkájából vettük [1]. Ez a példa egy általános tervezési problémát mutat be, amely tartalmazza fenti szempontok legtöbbjét. Két fontos dologra hívjuk fel a figyelmet: +- a kereszt- illetve hosszirányú tervezési problémát szétválasztjuk, illetve +- a keresztirányú tervezés az ún. Frenét-rendszerben történik.

+

Keresztirányú tervezés

+

A keresztirányú tervezés az útvonal görbéjének megtervezését jelenti. Először a Frenét-rendszer fogalmát vezetjük be. Az illusztárciója az 1. ábrán látható. A Frenét-rendszer egy olyan koordinátarendszer, amely egy tetszőleges görbén (ez esetben pl. a sávközép, vagy a globális trajektória) fut végig az \(\(s(t)\)\) paraméter függvényében. +A tetszőleges görbét nevezzük referencia vonalnak. A Frenét-rendszerben a referencia görbe koordinátája csupa zérus (önmagához képest vett eltérése nulla). Egy tervezett trajektória pontjait ebben a koordinátarendszerben értelmezve könnyű kifejezni azt, ha a trajektóriát egyelővé szeretnénk tenni a referencia görbével. Pl. ha egy tervezett trajektóriát szeretnénk, ha a referencia útvonalban végződne, ebben az esetben a végpontja \(\([0; 0]\)\), a Frenét-rendszerben. A nem zérus távolság a referencia vonaltól vett távolságot adja meg. Pl. ha a sávközépet tekintjük referenciának, az ettől vett eltérés lett a Frenét-rendszerben vett távolság, amely egy jó intuitív megközelítés is, hiszen az ember maga is sokszor tekinti a sáv közepét referenciának, az attól való eltérést pedig mérvadó mennyiségnek.

+


+1. Ábra: a Frenet frame illusztrálása a tervezett trajektória mentén, forrás: [1]

+

A kereszirányú tervezés problémáját kizárólag magas (>30-40kph) sebességekre vizsgáljuk. Erre az esetre Werling és mtsai. egy optimalizációs problémaként tekintenek. A lényeg, hogy a mindenkori állapotban meghatározunk egy polinomot, amelynek a költsége a legkisebb. A költségek illetve súlyok megválasztásával lehet különféle trajektóriákat megtervezni. A tervezés két lehetséges kimenetelét a Frenét-rendszerben a 2. ábra mutatja. Tegyük fel, hogy a szagatott vonal a sáv közepe, ez lesz a referencia vonal, vagyis a globális trajektória. A vastag vonal a lokálisan tervezett trajektória, aminek a célja, hogy rávezesse a járművet a globális trajektóriára. A kezdőpont lehet egy tetszőlegesen választott pont (pl. a jármű pozíciója, vagy a legutóbbi érvényes lokális trajektória utolsó pontja...stb.). A vízszintes irány testesíti meg a független változót. Ennek értéke 0 és egy maximális érték között változik, ezt a tartományt tekinthetjük a görbét leíró egyenlet értelmezési tartományának. Mi számunkra a fontos a görbe megtervezésénél? Egyrészt, hogy a kezdőpontban kezdődjön és a végpontban érjen véget (meglepő módon). Emellett feltételként kezelhetjük azt is, hogy a kezdeti is végorientáció legyen egy adott érték (pl. a kezdeti orientáció egyezzen meg a jármű orientációjával, a végorientáció a referencia vonal orientációjával). A kezdeti és végfeltételeket nevezzük peremfeltételeknek. Szükség esetén további peremfeltételeket szabhatunk meg.

+


+2. Ábra: tervezés lehetséges kimenetei a Frenét-rendszerben, forrás: [1]

+

A polinom illesztés során olyan polinomokat keresünk, amelyek kielégítek a peremfeltételeket. A 2. ábrán láthatjuk, hogy egyszerre több polinom is kielégítheti ezeket a feltételeket. A 3. ábra ilyen lehetséges polinomokat mutat. Látható, hogy nem mindegyik görbe éri el ugyanott a referencia vonalat (a vízszintes tengelyt), tehát a hossz függvényében különböztethetünk más-más alakú görbéket. Ezek mindegyike kielégíti a peremfeltételeket, ugyanakkor más alakjuk miatt ezen végigvezetve az autót más kinematikai tulajdonságokat fognak eredményezni. Ahhoz, hogy eldöntsük, melyik a számunkra legjobb görbe, bevezetjük az ún. költségfüggvényt. A költségfüggvény egy olyan függvény, amely szabadon választott szempontjaink szerint eldönti, hogy az adott szempont szerint mennyire jó az adott görbe. A költségeket összegezzük. Azonban nem mindegyik szempont egyformán fontos, így a költsége sem egyformán releváns. Így súlyokat használunk hogy eldöntsük, melyek a legjelentősebb, és melyek a legkevésbé érdekes szempontok. Az összes lehetséges görbére meghatározzuk az összköltséget, majd kiválasztjuk a legkisebb költségű görbét. Ez lesz a végső trajektóriánk, amely így a probléma optimális megoldása (optimális, azaz nem nulla költségű, de a körülményeket figyelembe véve a legkisebb költségű megoldás). A folyamatot optimalizációnak, a trajektória hosszát az optimalizáció változójának nevezzük.

+


+3. Ábra: tervezés lehetséges kimenetei a Frenét-rendszerben, forrás: [1]

+

Az, hogy mit tekintünk optimálisnak, a költségfüggvénytől függ. Ebben általában egymásnak ellentmondó tagok szerepelnek: a trajektória hossza legyen minél kisebb (minél gyorsabban érjük el a célt), de a kialakuló oldalirányú járműgyorsulás legyen minél kisebb (komfort feltétel). Ezek egymásnak ellentmondanak, így egy köztes jó, azaz optimális trajektória fog születni. További költségeket vezethetünk be, pl. a túllendülés mértéke (a sáv másik oldalára való áttérés mértéke), a kezdeti rántás, a beállás gyorsasága stb. A súlyok változtatásával más-más preferenciát valósíthatunk meg. Pl. agresszív manőver vagy kényelmes manőver. Ezen kívül kizárjuk azokat a trajektóriákat, amelyek nem felelnek meg a biztonsági követelményeknek, pl. áttérnek a másik sávba.

+

Werling és mtsai. ötödfokú polinomot határoztak meg, ez írja le a görbét. A Frenét-rendszerben így a görbe egyenlete:

+
\[ x(s) = c_{0} + c_{1}s + c_{2}s^{2}+c_{3}s^{3}+c_{4}s^{4}+c_{5}s^{5} \]
+

Láthatjuk, hogy a görbét 6 db paraméter adja meg, a 6 együttható c0-tól c5-ig. Ahhoz, hogy az összes együtthatót meg tudjuk határozni, 6 peremfeltételre van szükségünk: +- a kezdeti és végpont eltérése a referencia vonaltól, +- a kezdeti és végpont orientációjának eltésére a referencia vonaltól, +- illetve a kezdeti és végpontban a tervezett trajektória görbülete.

+

Ezeket vektoros formába rendezve: +$$ [d_{0}\ d_{1}\ \theta_{0}\ \theta_{1}\ \kappa_{0}\ \kappa_{1}]$$

+

Ezeket tetszőlegesen megválaszthatjuk. A fenti magyarázat alapján legyen: +\(\([d_{0}\ d_{1}\ \theta_{0}\ \theta_{1}\ \kappa_{0}\ \kappa_{1}]=[d_{0}\ 0\ \theta_{0}\ 0\ 0\ 0]\)\) +azaz a kezdeti pontban a jármű helyzete a referenciavonaltól, a végpontban a referencia vonal, a görbületek pedig nullák, azaz a referencia vonal görbületei a kezdeti és végpontban. +A peremfeltételek segítségével felírható egy 6 ismeretlent és 6 egyenletet tartalmazó egyenletrendszer: +$$ x(s=0) = c_{0} = d_{0}$$ +$$ x'(s=0) = c_{1} = \theta_{1}$$ +$$ x''(s=0) = 2c_{2} = \kappa_{1}$$ +$$ x(s=s_{1}) = c_{0} + c_{1}s + c_{2}s_{1}^{2}+c_{3}s_{1}^{3}+c_{4}s_{1}^{4}+c_{5}s_{1}^{5} $$ +$$ x'(s=s_{1}) = c_{1}s + 2c_{2}s_{1}+3c_{3}s_{1}^{2}+4c_{4}s_{1}^{3}+5c_{5}s_{1}^{4} $$ +$$ x''(s=s_{1}) = 2c_{2}+6c_{3}s_{1}+12c_{4}s_{1}^{2}+20c_{5}s_{1}^{3} $$

+

ahol \(s_{1}\) a végpont távolsága. Ez lesz a fenti optimalizációs probléma változója. Ezt a mennyiséget tetszőleges tartományon variálva (pl. \(s_{1,max}\) és \(s_{1,min}\) között) keressük azt az együttható halmazt, amelyre \(\(J\)\) költségfüggvény a legkisebb. +Hogyan válasszuk meg a \(J\) függvényt? Erre Werling és mtsai. a következő formulát ajánlják:

+
\[ C_{d} = k_{j}J_{t}(d(t)) + k_{t}T + k_{d}(d_{1})^{2} \]
+

Ahol \(T = \dfrac{s_{1}}{v_{x}}\) a trajektória hossza időben kifejezve, \(J_{t}\) az ún. jerk (magyarul rántás) az oldalirányú gyorsulás deriváltja, \(d_{1}\) a végső pontban a távolság a referencia vonaltól. Mi ezt \(d_{1}=0\) értékre választottuk, így ez a tag kiesik.

+

Hosszirányú tervezés

+

A hosszirányú tervezés hasonlóan működhet, mint a keresztirányú. Ebben az esetben a globális trajektória felfogható úgy, mint célsebességek sorozata az útvonal mentén. Ezzel szemben a lokális trajektória a helyi viszonyoknak megfelelő tényleges sebesség megtervezése. Figyelembe vesszük másik objektumok mozgását, a cél járműkinetikát, a sebességhatárokat...stb. Ennek szemléltetése látható a 4. ábrán. Látható, hogy normál esetben a maximális sebességet tartjuk. Amikor pl. utolérünk egy másik járművet ami előttünk halad, fékezünk, és felvesszük ennek a járműnek a sebességét. A fékezés során olyan sebességprofilt tervezünk, hogy biztosan kellő távolságot tudjunk tartani a másik járműtől, ne fékezzünk hirtelen de ne is túl hamar. Majd a másik járművet úgy követjük, hogy ezt a távolságot (bizonyos határon belül) tartsuk. Amikor ennél is lassabb járművet látunk (pl. biciklis) tovább csökkentjük a sebességet, ha ez az akadály eltűnt előlünk, visszagyorsítunk a megengedett sebességre. Mindig figyelembe vesszük a saját gyorsítási és lassítási preferenciánkiat.

+


+4. Ábra: lokális sebességtrajektória szemléltetése

+

Látható, hogy a keresztirányú tervezéshez hasonló feltételek között kell a lehető legjobb profilt megtervezni. Ez szintén egy optimalizációs probléma. Werling és mtsai. ebben az eseben is egy ötödfokú polinomot ajánlanak a célsebesség függvényére, azaz:

+
\[ v(s(t)) = c_{0} + c_{1}s + c_{2}s^2+c_3s^3+c_4s^4+c_5s^5 \]
+

A mechanizmus ugyanaz: 6 peremfeltételt fogalmazunk meg és ezek segítségével trajektóriákat tervezünk. A legkisebb költségűt választjuk ki. Másik jármű követése esetében a végfeltételek a következők:

+
\[ [s_1\ \dot{s_1}\ \ddot{s_1}\ T] = [(s_{target}(T_j)+\delta s_i),\ \dot{s}_{target}(T_j),\ {\ddot{s}}_{target}(T_j),\ T_j] \]
+

A kezdeti feltételek pedig:

+
\[ [s_0\ \dot{s_0}\ \ddot{s_0}\ T] = [s_{target}(0),\ \dot{s}_{ego}(0),\ {\ddot{s}}_{ego}(0),\ 0] \]
+

Azaz a kezdeti feltételek adottak az objektum távolságából, illetve a saját járművünk sebességéből és gyorsulásából. Egy ilyen tervezési ciklus összes trajektóriája az 5. ábrán látható. A feketék az érvényes trajektóriák, a szürkék az érvénytelenek (pl. túl nagy gyorsulás), a kék az objektum mozgása, a zöld az optimális trajektória. A költség függvény lehet a következő:

+
\[ C_t = k_jJ_t + k_tT+k_s[s_1-s_d]^2 \]
+

Ahol \(J_t\) a trajektória befutása során tapasztalt átlagos jerk (azaz rántás), \(T\) a trajektória hossza időben \(s_1-s_d\) a trajektória végén a távolság az objektumtól. A \(k\) tényezők a súlyok.

+


+5. Ábra: sebességtrajektória tervezése, forrás: [1]

+

ROS 2 megoldások

+ +

A Nav2 az ROS Navigation Stack támogatott szellemi utódja, amely ugyanazt a technológiát alkalmazza, amely például a mobil robotikára, autonóm járművekre alkalmazható, optimalizált és átdolgozott megoldások gyűjteménye. A Nav2 projekt arra törekszik, hogy megtalálja a biztonságos módot arra, hogy egy mobil robot bonyolult feladatokat hajtson végre sokféle környezeten és robotkinematikai osztályon keresztül. Nemcsak mozoghat A pontból B pontba, de lehetnek közbenső pózok (pozíció + orientáció) is, és más típusú feladatokat is képviselhet, például objektumkövetést, teljes lefedettség-navigációt stb. A Nav2 egy gyártási szintű és jó minőségű navigációs keretrendszer, amelyben világszerte több mint 50 vállalat bízik meg.

+

A Nav2 architektúra áttekintése:

+

+

Autoware tervező

+

Szintén ROS 2 támogatott az Autoware keretrendszer tervező (planning) komponense. Az Autoware tervezés komponens fő funkciója, hogy létrehozza azt a trajektóriát, amelyre a Szabályzás (control) komponens feliratkozik a Lokalizáció (Localization) és az Észlelés (Perception) komponensekből kapott környezeti állapot alapján.

+

+

Irodalomjegyzék

+
    +
  • [1] Moritz Werling, Julius Ziegler, Sören Kammel, and Sebastian Thrun: Optimal Trajectory Generation for Dynamic Street Scenarios in a +Frenét Frame, 2010 IEEE International Conference on Robotics and Automation, Anchorage Convention District, May 3-8, 2010, Anchorage, Alaska, USA, pp. 987-993
  • +
  • [2] github.com/ai-winter/ros_motion_planning: ROS 1, de tervezetten ROS 2 Globális tervezők: Dijkstra, A-star, D-star, RRT, Informed-RRT, GBFS Lokális tervezők: LQR (Linear–quadratic regulator), DWA (Dynamic Window Approach), APF, RPP, TEB (Timed Elastic Band)
  • +
+

További cikkek

+

A bemutatott algoritmusokhoz tartozó cikkek és python_motion_planning repository-ból kigyűjtött cikkek gyűteménye:

+

Globális tervezők

+
    +
  • A* - A-star: A Formal Basis for the heuristic Determination of Minimum Cost Paths
  • +
  • Modified A-Star: Efficient and optimal penetration path planning for stealth unmanned aerial vehicle using minimal radar cross-section tactics and modified A-Star algorithm
  • +
  • Lifelong Planning A*: Lifelong Planning A*
  • +
  • D* - D-star: Optimal and Efficient Path Planning for Partially-Known Environments
  • +
  • D* Lite: D* Lite
  • +
  • JPS: Online Graph Pruning for Pathfinding On Grid Maps
  • +
  • Theta*: Theta*: Any-Angle Path Planning on Grids
  • +
  • Lazy Theta*: Lazy Theta*: Any-Angle Path Planning and Path Length Analysis in 3D
  • +
  • S-Theta*: S-Theta*: low steering path-planning algorithm
  • +
  • RRT: Rapidly-Exploring Random Trees: A New Tool for Path Planning
  • +
  • RRT-Connect: RRT-Connect: An Efficient Approach to Single-Query Path Planning
  • +
  • RRT*: Sampling-based algorithms for optimal motion planning
  • +
  • Informed RRT*: Optimal Sampling-based Path Planning Focused via Direct Sampling of an Admissible Ellipsoidal heuristic
  • +
  • ACO: Ant Colony Optimization: A New Meta-Heuristic
  • +
+

Lokális tervezők

+
    +
  • DWA: The Dynamic Window Approach to Collision Avoidance
  • +
  • APF:Real-time obstacle avoidance for manipulators and mobile robots
  • +
  • RPP:Regulated Pure Pursuit for Robot Path Tracking
  • +
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tervezes/params_en01.svg b/tervezes/params_en01.svg new file mode 100644 index 0000000..80b5ed0 --- /dev/null +++ b/tervezes/params_en01.svg @@ -0,0 +1 @@ +Avoidance directionLeftRightDistance deltaLateral offsetAvoid lengthDetour lengthReturn length diff --git a/tervezes/planning_control_diagram/index.html b/tervezes/planning_control_diagram/index.html new file mode 100644 index 0000000..10257bb --- /dev/null +++ b/tervezes/planning_control_diagram/index.html @@ -0,0 +1,2559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Planning control diagram - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Planning control diagram

+ +
flowchart LR
+
+GP1[Global planning
+  Inputs:
+  - Driver/User selection
+  -Mapdata
+  Output:
+  -Routeplan
+  Goal: to plan a global 
+  route which leads from A
+  to B, considering e.g., 
+  trafficdata,fuel
+  consumption… etc.]:::light 
+GP2[I want to get 
+  from address A 
+  to address B 
+  with a robotaxi]:::dark
+
+BP1[Behavior planning
+    Inputs:
+    -Route plan
+    -Perception info of
+    the surroundings
+    Output:
+    -Behavior strategy 
+    Goal: 
+    plan how the 
+    vehicle should 
+    behave in terms of 
+    decisions and motion 
+    characteristics
+]:::light 
+
+BP2[I want to follow the
+middle lane then
+ change to the inner
+ lane smoothly]:::dark
+
+LP1[
+    Local planning
+    Inputs:
+    -Behavior strategy
+    -Planning constraints
+    Output:
+    -Local trajectory
+    Goal: plan a 
+    kinematicly feasible,
+    safe and preferred
+    trajectory]:::light 
+LP2[I plan a trajectory
+within the lane to be
+safe and then a
+smooth trajectory to
+the inner lane]:::dark
+
+
+VC1[ Vehicle Control 
+    High level control
+    Inputs:
+    -Local trajectory
+    -Vehicle state variables
+    -Localization info 
+    Outputs:
+    -Vehicle level target 
+    quantities
+    -Control constraints 
+    Goal: calculate the
+    vehicle target state to 
+    be controlled by the
+    low level controllers]:::light 
+VC2[ I calculate the
+ necessary speed and 
+ yaw rate of the 
+ vehicle to follow the 
+ local trajectory]:::dark
+
+
+AC1[ Actuator Control
+Low  level control
+Inputs:
+-Vehicle level target 
+quantities
+-Control constraints
+-Actuator state variables
+Output:
+-Actuator target states 
+Goal: realize vehicle 
+motion through 
+controlling the 
+actuators]:::light 
+AC2[ I calculate the 
+necessary engine 
+torque and steering
+angle to realize the 
+planned motion’]:::dark
+
+
+subgraph Plan [Planning]
+  GP1
+  BP1
+  LP1
+end
+subgraph Control [Control]
+  VC1
+  AC1
+end
+GP1-->BP1-->LP1-->VC1-->AC1
+GP2-.-BP2-.-LP2-.-VC2-.-AC2
+
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+
+ + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tervezes/practice/index.html b/tervezes/practice/index.html new file mode 100644 index 0000000..24e3b3c --- /dev/null +++ b/tervezes/practice/index.html @@ -0,0 +1,2662 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Tervezés - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

1. feladat

+

Ebben a feladatban az elméleti órán bemutatott polinom alapú lokális tervező megvalósítását fogjuk bemutatni. +Ehhez elsőként frissítsük az arj_packages repository-t!

+

Clone és build

+

cd ~/ros2_ws/src/arj_packages/
+
+
git pull
+
+Ezek után buildeljük az arj_local_planner nevű package-t!

+

cd ~/ros2_ws
+
+
colcon build --packages-select arj_local_planner
+

+

Futtatás

+

Ezek után futtassuk a planner-t a launch fájl segítségével, source-olás után.

+

source ~/ros2_ws/install/setup.bash
+
+
ros2 launch arj_local_planner run_all.launch.py
+

+

Nézzük meg, milyen topicok jöttek létre (új terminálban)!

+
ros2 topic list
+
+

Létrejött a /goal_pose topic illetve a /planner/trajectory topic. A goal_pose az a célpozíció, amelyre a tervező tervez, a planner/trajectory pedig a waypoint list, maga a tervezett trajektória. +Indítsünk egy rviz-t!

+
ros2 run rviz2 rviz2
+
+

Válasszuk ki a map frame-t, illetve adjuk hozzá a /planner/trajectory topicot. Ezek után a fenti sávból a 2D Goal Pose opciót használva vegyünk fel egy goal pose-t a griden úgy, hogy az a pozitív koordináták irányában helyezkedjen el! Ekkor a tervező automatikusan ráilleszt egy polinomot a célpozícióra.

+

+

Ezt az egyszerű tervezőt használhatjuk pl. mozgó célpontra (másik jármű, sáv közepe, globális trajektória egy pontja...stb) illetve statikus célpontra (pl. parkolóhely).

+

2. feladat

+

A második feladat a ROS 2 Navigation stack-jének beüzemelése szimulátorban, üres pályán. Részletes dokumentáció a navigation.ros.org oldalon.

+ + +

Clone és build

+

cd ~/ros2_ws/src
+
+
git clone https://github.com/rosblox/nav2_outdoor_example
+

+

cd ~/ros2_ws
+
+
rosdep install -y --from-paths src --ignore-src --rosdistro $ROS_DISTRO
+

+

cd ~/ros2_ws
+
+
colcon build --packages-select nav2_outdoor_example
+

+

Futtatás

+

source ~/ros2_ws/install/setup.bash
+
+
ros2 launch nav2_outdoor_example bringup.launch.py
+

+

3. feladat

+

A harmadik feladat a ROS 2 Navigation stack-jének beüzemelése szimulátorban, a turlebot egyik pályáján. Részletes dokumentáció a navigation.ros.org oldalon.

+ + +

Videó direkt link

+

Megjegyzés: előfordulhat, hogy az ign_ros_control package másik feladatban is buildelt package, ha ez már létezik, akkor a build / apt install kihagyható. A helyek, ahol ez lehetséges, hogy megtalálható: +

ros2_ws/src/gz_ros2_control/ign_ros2_control
+ros2_ws/src/navigation2_ignition_gazebo_example/src/gz_ros2_control/ign_ros2_control
+/opt/ros/humble/share/ign_ros2_control
+

+

Clone és build

+
sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup ros-humble-turtlebot3-gazebo
+
+

cd ~/ros2_ws/src
+
+
git clone https://github.com/ros-controls/gz_ros2_control
+
+
git clone https://github.com/art-e-fact/navigation2_ignition_gazebo_example
+
+
cd ~/ros2_ws/src/gz_ros2_control
+
+
git checkout humble
+
+
cd ~/ros2_ws
+
+
rosdep install -y --from-paths src --ignore-src --rosdistro humble
+

+

cd ~/ros2_ws
+
+
colcon build --packages-select sam_bot_nav2_gz
+

+

Futtatás

+

Gazebo, RViz2 és Navigation2 +

source ~/ros2_ws/install/setup.bash
+
+
ros2 launch sam_bot_nav2_gz complete_navigation.launch.py
+

+

Célpont kijelölése RViz2-ben: +

source ~/ros2_ws/install/setup.bash
+
+
ros2 run sam_bot_nav2_gz follow_waypoints.py
+
+
source ~/ros2_ws/install/setup.bash
+
+
ros2 run sam_bot_nav2_gz reach_goal.py
+

+

+

+

+ +

+

+

+

+

Sources

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transzformaciok/frames01.svg b/transzformaciok/frames01.svg new file mode 100644 index 0000000..6caf2d4 --- /dev/null +++ b/transzformaciok/frames01.svg @@ -0,0 +1,473 @@ + + +Qt SVG Document +Generated with Qt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/transzformaciok/gps_utm.ipynb b/transzformaciok/gps_utm.ipynb new file mode 100644 index 0000000..42b17f8 --- /dev/null +++ b/transzformaciok/gps_utm.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import utm" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(46.894188434576925, 16.834861347101725)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "utm.to_latlon(639770.000, 5195040.000, 33, 'T')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ZalaZone\n", + "https://www.google.hu/maps/@46.894188434576925,16.834861347101725m/data=!3m1!1e3?entry=ttu\n", + "https://www.openstreetmap.org/#map=19/46.894188434576925/16.834861347101725\n", + "Campus\n", + "https://www.google.hu/maps/@47.69405596312653,17.62866888484998m/data=!3m1!1e3?entry=ttu\n", + "https://www.openstreetmap.org/#map=19/47.69405596312653/17.62866888484998\n" + ] + } + ], + "source": [ + "lat, lon = utm.to_latlon(639770.000, 5195040.000, 33, 'T') # Zala Zone\n", + "print(\"ZalaZone\")\n", + "print(\"https://www.google.hu/maps/@\" + str(lat) + \",\" + str(lon) + \"m/data=!3m1!1e3?entry=ttu\")\n", + "print(\"https://www.openstreetmap.org/#map=19/\" + str(lat) + \"/\" + str(lon))\n", + "\n", + "\n", + "\n", + "lat, lon = utm.to_latlon(697237.000, 5285644.00, 33, 'T') # Campus Győr\n", + "print(\"Campus\")\n", + "print(\"https://www.google.hu/maps/@\" + str(lat) + \",\" + str(lon) + \"m/data=!3m1!1e3?entry=ttu\")\n", + "print(\"https://www.openstreetmap.org/#map=19/\" + str(lat) + \"/\" + str(lon))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(697237.0000192814, 5285644.004006204, 33, 'T')\n" + ] + } + ], + "source": [ + "print(utm.from_latlon(47.69405596312653, 17.62866888484998))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ros2 run tf2_ros static_transform_publisher --x 640152.0282826852 --y 5193647.979721197 --z 0.0 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id map --child-frame-id map_point_0\n", + "ros2 run tf2_ros static_transform_publisher --x 382.02828268520534 --y -1392.0202788030729 --z 0.0 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id map_zala_0 --child-frame-id map_point_0\n" + ] + } + ], + "source": [ + "map_gyor_0_x = 697237.0\n", + "map_gyor_0_y = 5285644.0\n", + "map_zala_0_x = 639770.0\n", + "map_zala_0_y = 5195040.0\n", + "\n", + "x1, y1, _, _ = utm.from_latlon(46.88158771091701, 16.839445659615887)\n", + "\n", + "print(\"ros2 run tf2_ros static_transform_publisher --x \" + str(x1) + \" --y \" + str(y1) + \" --z 0.0 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id map --child-frame-id map_point_0\")\n", + "print(\"ros2 run tf2_ros static_transform_publisher --x \" + str(x1 - map_zala_0_x) + \" --y \" + str(y1 - map_zala_0_y) + \" --z 0.0 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id map_zala_0 --child-frame-id map_point_0\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/transzformaciok/index.html b/transzformaciok/index.html new file mode 100644 index 0000000..e19a6e7 --- /dev/null +++ b/transzformaciok/index.html @@ -0,0 +1,2967 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Elmélet - Transzformációk - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + +

Ellenőrző kérdések

+
    +
  • Mik a launch fájlok és mire használjuk őket?
  • +
  • Milyen nyelven írjuk a launch fájlokat?
  • +
  • Mit jelenít meg az rqt_tf_tree, az rviz és az rqt_graph?
  • +
  • Mit értünk pose (vagy póz / helyzet) alatt? (robotikában)
  • +
+

Bevezetés

+

ROS-ben (és álatalában robotikában) a transformok határozzák meg a hogy, mi merre található az adott vonatkozatási ponttól (frame). Több transzform leírhatja például egy robotkar mozgását vagy épp egy jármű és szenzorai helyzetét a térben.

+

Merev test mozgása

+

Merevnek tekinthető az a test, mely pontjainak távolsága mozgás során nem változik, vagyis bármely két pontjának távolsága időben állandó.

+
    +
  • Merev test alakja, térfogata állandó.
  • +
  • Merev test térbeli helyzete megadható bármely 3 nem egy egyenesbe eső pontjának helyzetével.
  • +
  • A test helyzetét szemléletesebben megadhatjuk egy tetszőleges pontjának 3 koordinátájával (pozíció) és a test orientációjával.
  • +
  • Merev testek mozgásai két elemi mozgásfajtából tevődnek össze: haladó mozgás (transzláció) és tengely körüli forgás (rotáció)
  • +
  • Transzlációs mozgás során a test minden pontja egymással párhuzamos, egybevágó pályát ír le, a test orientációja pedig nem változik.
  • +
  • Rotáció során a forgástengelyen lévő pontok pozíciója nem változik, a test többi pontja pedig a forgástengelyre merőleges síkokban körpályán mozog.
  • +
+

+

Rotáció szemléltetése Forrás: University of Illinois

+

Az alábbiakban egy rövid (~9 perc), de hasznos videó látható a témáról:

+ + +

Transzformációk

+

A pose (póz) a pozíció (elhelyezkedés) és orientáció (irány) összessége. Amennyiben egy térbeli pose-t transzformálunk (mozgatunk és forgatunk) egy másik pose keletkezik. Ez a két pose egymáshoz képest két transzformációs frame. Ilyen transzformációs frame-k írják le a teljes robotikai rendszert.

+
    +
  • Pozíció: 3 elemű offszet vektor (x, y és z 3D-ben).
  • +
  • Orientáció: több reprezentációt használhatunk:
      +
    • 4 elemű quaternion (erről később)
    • +
    • 3 elemű Euler-szögek: roll (dőlés, gurulás, ψ): pitch (bólintás, θ), yaw (legyezőmozgás, φ) wolfram alpha
    • +
    • 3 x 3 elemű rotációs matrix
    • +
    +
  • +
+

Például a Nissan Leaf base_link framejéhez képest a következő fontosabb framek találhatóak meg:

+

img +Frame-k a járművön

+

Például a járműves és mobil robotos környezetben gyakran szeretnénk tartani magunkat ahhoz a konvencióhoz, hogy a globális térképet map frame-nek, a jármű / robot hátsó tengelyét base_link-nek hívjuk. A map és a base_link közötti megfeleltetés történehet GPS, NDT matching, Kálmán filter, odometria és számos további módon. Ezt a követező példa szemlélteti:

+

+graph TD
+    %% Define first column
+        direction TB
+        map1([  /map]):::light
+        gps([ /gps]):::light
+        base_link1([ /base_link]):::light
+        velodyne_left([ /velodyne_left]):::light
+        zed_front([ /zed_front]):::light
+        laser([ /laser]):::light
+
+        %% Connections for the first column
+        map1 -.->|dynamic| gps
+        gps -->|static| base_link1
+        base_link1 -->|static| velodyne_left
+        base_link1 -->|static| zed_front
+        base_link1 -->|static| laser
+
+    %% Define second column
+        direction TB
+        map2([ /map]):::light
+        ndt_map([ ndt_map]):::light
+        base_link2([ base_link]):::light
+        sensor_a([ sensor_a]):::light
+        sensor_b([ sensor_b]):::light
+
+        %% Additional sensors can be represented by dots
+        dots2([ ...]):::light
+
+        %% Connections for the second column
+        map2 -.->|dynamic| ndt_map
+        ndt_map --> base_link2
+        base_link2 --> sensor_a
+        base_link2 --> sensor_b
+        base_link2 --> dots2
+
+    %% Define third column
+        direction TB
+        map3([ lexus3/map]):::light
+        kalman_f([ lexus3/kalman_f]):::light
+        base_link3([ lexus3/base_link]):::light
+
+        %% Representing additional connections with dots
+        dots3a([ lexus3/...]):::light
+        dots3b([ lexus3/...]):::light
+        dots3c([ lexus3/...]):::light
+        dots3d([ lexus3/...]):::light
+
+        %% Connections for the third column
+        map3 -.->|dynamic| kalman_f
+        kalman_f --> base_link3
+        base_link3 --> dots3a
+        base_link3 --> dots3b
+        base_link3 --> dots3c
+        dots3c --> dots3d
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

img +Példa TF tree

+

GPS használata esetén nagyvonalakban a következő példa alapján kell elképzelni a frameket. A map a globális térkép, viszont a gps helyzetét is tudjuk ehhez képest. (Megjegyzés: a 2020.A senzor összeállításban 2 GPS is van, ezek kölönböző helyen találhatóak, mérni tudnak párhuzamosan, de csak egy transzform határozhatja meg a base_link helyzetét. Ezt az 1. ábrán a szaggatott nyilak jelzik.) Innen már egy további (statikus) transzformációval kapható a base_link (a hátsó tengely). További statikus transzformációkkal kaphatók a szenzorok a példában a left_os1/os1_sensor látható.

+

img +A TF tree 2d koordinátarendszerben, vizuális példa

+

A transformok a tf topicaban hirdetődnek, azonban például az MPC szabályzó egy current_pose nevű topicot használ a szabályzás megvalósításához. Ezt úgy oldottuk meg, hogy a base_link frame értékeit current_pose topic-ként is hirdetjük. A frame transzlációja a topic pozícója, illetve a frame rotációja a topic orientációja.

+

Nagy transzformoknál az RVIZ megjelenítője nem működik pontosan (https://github.com/ros-visualization/rviz/issues/502). Mivel az ROS SI mértékegységeket használ, így métert is, a GPS esetén célszerű az UTM (wikipedia-utm) koordinátarendszer használata. Ez értelemszerűen nagy értékű koorinátákkal számol. Ahhoz, hogy ezt az ellentmondást feloldjuk célszerű kisebb traszformokat megjeleníteni. Így például Győrhöz (map_gyor_0) és Zalához (map_zala_0) egy fix statikus transformot, hirdetni, amihez képest már szépen működik az RVIZ megjelenítője. A következő ábra ezt szemlélteti, illetve egy kicsit részletesebb szenzorrendszert mutat be.

+
graph TB
+    %% Define main components
+    map([ map]):::red
+    map_gyor_0([ map_gyor_0]):::dark
+    map_zala_0([ map_zala_0]):::dark
+    gps([ gps]):::light
+    base_link([ base_link]):::red
+
+    %% Define sensors and other components
+    velodyne_left([ velodyne_left]):::light
+    velodyne_right([ velodyne_right]):::light
+    laser([ laser]):::light
+    zed_camera_front([ zed_camera_front]):::light
+    duro_gps_imu([ duro_gps_imu]):::light
+
+    %% OS1 sensors and their subcomponents
+    left_os1_sensor([ left_os1/os1_sensor]):::light
+    left_os1_lidar([ left_os1/os1_lidar]):::light
+    left_os1_imu([ left_os1/os1_imu]):::light
+
+    right_os1_sensor([ right_os1/os1_sensor]):::light
+    right_os1_lidar([ ...]):::light
+    right_os1_imu([ ...]):::light
+
+    %% Connections among main components
+    map --> map_gyor_0
+    map --> map_zala_0
+    map ---> gps
+    gps --> base_link
+
+    %% Connections from base_link to sensors
+    base_link ---> velodyne_left
+    base_link ---> velodyne_right
+    base_link ---> laser
+    base_link --> zed_camera_front
+    base_link --> duro_gps_imu
+    base_link ----> left_os1_sensor
+    base_link ----> right_os1_sensor
+
+    %% Connections for OS1 sensors
+    left_os1_sensor --> left_os1_lidar
+    left_os1_sensor --> left_os1_imu
+
+    right_os1_sensor --> right_os1_lidar
+    right_os1_sensor --> right_os1_imu
+
+
+classDef light fill:#34aec5,stroke:#152742,stroke-width:2px,color:#152742  
+classDef dark fill:#152742,stroke:#34aec5,stroke-width:2px,color:#34aec5
+classDef white fill:#ffffff,stroke:#152742,stroke-width:2px,color:#152742
+classDef red fill:#ef4638,stroke:#152742,stroke-width:2px,color:#fff
+

img +Az rqt_tf_tree által megjelenített TF fa

+

Az ábrán csak a map gps transzform változó, a többi statikus. Statikus transzformot hirdetni launch fájlban például a /base_link és a left_os1/os1_sensor következőképp lehet (lásd 3. ábra)

+
+
+
+
Node(
+    package='tf2_ros',
+    executable='static_transform_publisher',
+    name='ouster_left_tf_publisher',
+    output='screen',
+    arguments=[
+        '--x',  '1.769',
+        '--y',  '0.58',
+        '--z',  '1.278',
+        '--roll', '3.1415926535', # or use math.pi
+        '--pitch', '0.0',
+        '--yaw', '0.0',
+        '--frame-id',      '/base_link',
+        '--child-frame-id','left_os1/os1_sensor'
+    ],
+),
+
+
+
+
<node 
+  args="1.769 0.58 1.278 3.1415926535 0.0 0.0 /base_link left_os1/os1_sensor 50"
+  name="ouster_left_tf_publisher" 
+  pkg="tf" 
+  type="static_transform_publisher"
+/> 
+
+
+
+
+

Ugyanezek parancsként kiadva terminálból:

+
+
+
+
ros2 run tf2_ros static_transform_publisher \
+--x 1.769 --y 0.58 --z 1.278 \
+--roll 0.0 --pitch 0.0 --yaw 3.1415926535 \
+--frame-id left_os1/os1_sensor --child-frame-id base_link
+
+
+
+
rosrun tf static_transform_publisher \
+1.769 0.58 1.278 \
+3.1415926535 0.0 0.0 \
+/base_link left_os1/os1_sensor 50  
+
+
+
+
+

Itt az utolsó argumentum ROS 1-nél 50 ms, tehát 20 Hz-en hirdette a ugyanazt a transzformációt. Ez nem a legszerencsésebb, az ROS 2 ebben is fejlődött, ott elég egyszer hirdetni ugyanezt.

+

Példa a statikus transzform launch fájlra: tf_static.launch

+

Mátrix szorzás

+

A 3D transzformáció (de természetesen a 2D is) egy mátrix segítségével, egész pontosan mátrisx szorzással írható le. Például, ha egy objektumot elmozdítunk egy adott távolságra, akkor azt egy forgatómátrix segítségével írhatjuk le. A forgatómátrix 3 dimenzióban egy 3x3-as mátrix, amely a forgatás irányát és mértékét határozza meg.

+

Forrás: Robotic Systems, University of Illinois

+

matrixmultiplication.xyz

+

Python notebook

+
+

Danger

+

A python notebook-ot és a mátrixszozás vizualizációt oktatási céllal linkeltük. ROS 2-ben rengeteg funkciót ad a tf2 és kapcsolódó megoldásai, így nem kell "kézzel" transzlációt és rotációt írni. Transzformációkat például le lehet kérdezni 2 frame között anélkül is, hogy tudnánk pontosan hány frame-n kereszül kapcsolódnak. Az ROS 2 ezt kényelmesen biztosítja. Erről bővebben itt lehet olvasni

+
+

Homogén koordináták

+

A homogén koordináták kényelmes reprezentációt nyújtanak a merevtest transzformációkhoz, mint a lineáris transzformációk egy kibővítéseként a térben. Ráadásul kompaktan reprezentálják a helyzetfüggő és irányfüggő mennyiségek közötti különbséget. Az ötlet az, hogy minden pontot kiegészítünk egy további homogén koordinátával, amely 1, ha helyzetfüggő, és 0, ha irányfüggő. Ezt az műveletet a "hat" (kalap) operátorral (^) jelöljük.

+

Quaternion (kvaterniók)

+

A roll pitch yaw (Euler szögek) alternatívája, a komplex számokhoz hasonló kiterjesztéssel.

+

Demonstáció: www.quaternions.online

+

Előnyei:

+
    +
  • Numerikus stabilitás: A lebegőpontos reprezentációból adódó kis numerikus hibák sokszor ismétlődve egyre nagyobb hibákhoz vezethetnek Euler szögek esetén. Például egy forgatás pár század fokos pontatlansága ezrez vagy tízezres ismétléssel komoly hibává adódhat össze. Quaternion-oknál ez a komlex reprezentáció és a normált alak miatt sokkal kisebb.
  • +
  • Gyors számítás: A kvaterniók hatékonyan reprezentálják a 3D térbeli forgatásokat, és sokszor gyorsabbak és stabilabbak lehetnek, mint más reprezentációs módszerek, például Euler-szögek.
  • +
  • +

    Pontosság:

    +
      +
    • Nem érzékeny a "Gimbal lock" problémára: Az Euler-szögek esetében előfordulhat egy olyan helyzet, amikor a rotációk szenzitívekké válnak bizonyos irányokban, ami korlátozhatja a számítások pontosságát. A kvaterniók ezt a problémát elkerülik.
    • +
    • Könnyen interpolálhatók: A kvaterniók segítségével könnyen lehet interpolálni a két rotációt közöttük, ami fontos az animációk simaságának megőrzése szempontjából. Sőt nem lineáris interpolációkhoz is használhatók. A kvaterniók lehetővé teszik a nem lineáris interpolációkat is, ami olyan animációk létrehozásához hasznos, ahol a rotáció nem lineárisan változik az időben.
    • +
    +
  • +
+

Hátrány:

+
    +
  • Nem intuitív az ember számára: Nehezebben érthetők, mint például az Euler-szögek, amiket megszoktunk a 3 tengely körüli forgatásra.
  • +
+
\[tan(\frac{\pi}{2}) = \infty \]
+

ROS 2-ben például így lehet átalakítani roll, pitch, yaw értékeket quaternion-ra.

+
#include <tf2_geometry_msgs/tf2_geometry_msgs.hpp>
+tf2::Quaternion tf2_quat;
+tf2_quat.setRPY(roll, pitch, yaw);
+
+

További információ erről itt olvasható.

+ + +

Konvenciók

+

rh +va

+

Koordinátarendszerek (GPS/GNSS)

+

A WGS84 vagy World Geodetic System 1984 egy globális referencia rendszer a térképészetben, geolokációban, navigációban és a GPS (Global Positioning System) rendszerben történő használatra. Ez egy szabványos koordináta rendszer, amelyet a földrajzi szélesség, hosszúság és tengerszint feletti magasság megadására használnak. A földrajzi szélességi (latitude) körök vízszintesen futnak, és fokokban adják meg egy pont helyét a Föld felszínén az egyenlítőtől (0 fok szélesség) északra vagy délre. A hosszúsági körök (longitude) függőlegesen futnak, és fokokban adják meg egy pont helyét a Föld felszínén a keleti vagy nyugati nullameridiántól (0 fok hosszúság). A nullameridián a 0 fok hosszúságánál található, és Londonon Greenwich városrészén keresztül halad. A hosszúsági értékek -180 foktól +180 fokig terjednek, az 180 foknál pedig az Északi és Dél-Keleti hosszúságok összekapcsolódnak. A mérésadat fájl navsatfix topicja (sensor_msgs/msg/NavSatFix) ebben a formátumban került mentésre. +Ennek alternatívája az UTM vetületi rendszer, amely nem fokokban, hanem méterekben számol. Az UTM, vagyis az Egyesített Térképi Projekció (Universal Transverse Mercator), egy térképi projekciós rendszer, amelyet a térképek készítésére és a navigációhoz használnak. A világ különböző zónáit egy sor speciális hengertérképen ábrázolják, ahol a hosszúsági és szélességi vonalak egyenesek. Ahogy lejjebb látható, Magyarország 4 UTM zónába esik: 33U, 34U, 33T és 34T. Az UTM zónák 6 fokos szélességi sávokra oszlanak szét, ahol minden sávban az ábrázolás egy transzverzális Merkátor-projekción alapuló hengertérképen történik. Az UTM rendszer előnye, hogy egyszerű koordináta-rendszert biztosít, ami kis torzulással rendelkezik a zónákon belül. Ezért sokszor használják katonai térképek, topográfiai térképek, navigációs rendszerek és más térképkészítési alkalmazásoknál. Például a mérésadatoknál a jellemzően current_pose végződésű topicja (geometry_msgs/msg/PoseStamped) ebben a formátumban érkező adat.

+

utm

+

Források

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transzformaciok/leaf_tf01.png b/transzformaciok/leaf_tf01.png new file mode 100644 index 0000000..4ff2eed Binary files /dev/null and b/transzformaciok/leaf_tf01.png differ diff --git a/transzformaciok/practice/index.html b/transzformaciok/practice/index.html new file mode 100644 index 0000000..07dce88 --- /dev/null +++ b/transzformaciok/practice/index.html @@ -0,0 +1,2906 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Gyakorlat - Transzformációk - Autonóm járművek és robotok programozása + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + +

Gyakorlat - Transzformációk

+ +

Gyakorlat

+

A következő gyakorlat a transzformációk ROS2-ben történő kezelését szemlélteti, C++-ban.

+
+

Python megfelelője

+

A C++ kód python verziója szintén elérhető a github.com/sze-info/arj_packages címen. Érdemes összehasonlítani a C++ és a python kódokat.

+
+

Frissítsük a legújabb verzióra az arj_packages repo-t. Ha frissül, vagy Already up to date. üzenetet kapunk, akkor nem kell klónoznunk. Ha a cd ~/ros2_ws/src/arj_packages parancs után a ~/ros2_ws/src/arj_packages: No such file or directory üzenetetet kaptuk, akkor klónozzuk a repo-t.

+

cd ~/ros2_ws/src/arj_packages
+
+
git pull
+

+

Amennyiben a No such file or directory üzenetetet kaptuk, klónozzuk a következő parancsokkal:

+
+

Warning

+

A következő két parancs csak nem létező arj_packages esetén kell:

+
+

cd ~/ros2_ws/src
+
+
git clone https://github.com/sze-info/arj_packages
+

+

Ha már létezik, akkor az előző lépés helyett, csak frissítsük.

+

cd ~/ros2_ws/src/arj_packages/
+
+
git status
+
+A git checkout -- .: Minden nem staged (unstaged) változás elvetése lokálisan. VS code-ban kb ez a "discard all changes" parancs lenne. +
git checkout -- .
+
+
git pull
+

+

Ezután már buildelhetünk is:

+

cd ~/ros2_ws
+
+
colcon build --packages-select arj_transforms_cpp --symlink-install
+

+

Célszerű új terminalban source-olni, majd futtatni:

+

source ~/ros2_ws/install/setup.bash
+
+
ros2 run arj_transforms_cpp pub_transforms
+

+

Vizsgáljuk meg, nyers adatként milyen kimenetet kapunk:

+
ros2 topic echo /tf
+
+

Erre a válasz hasonló lesz:

+

transforms:
+- header:
+    stamp:
+      sec: 1693475112
+      nanosec: 95339579
+    frame_id: orbit1
+  child_frame_id: orbit2
+  transform:
+    translation:
+      x: -2.487199068069458
+      y: 0.25266680121421814
+      z: 0.0
+    rotation:
+      x: 0.0
+      y: 0.0
+      z: 0.0
+      w: 1.0
+---
+transforms:
+- header:
+    stamp:
+      sec: 1693475112
+      nanosec: 145005518
+    frame_id: map
+  child_frame_id: orbit1
+  transform:
+    translation:
+      x: -4.109088897705078
+      y: 2.8487515449523926
+      z: 0.0
+    rotation:
+      x: 0.0
+      y: 0.0
+      z: -0.46381551598382736
+      w: 0.8859318072699817
+
+Ahogy láthatjuk a map frame child_frame_id-ja orbit1. Az orbit1 frame child_frame_id-ja pedig az orbit2. Tehát, ha a map-et naygszülőnek tekintjük, akkor az orbit2 az unoka. Szemléletesebb ezt az rqt_tf_tree segítségével megvizsgálni.

+
ros2 run rqt_tf_tree rqt_tf_tree
+
+

frames01

+

Ha esetleg nem működne a fenti parancs, akkor telepíthető a sudo apt install ros-humble-rqt-tf-tree segítségével. Géptermi gépeken erre elvileg nincs szükség.

+

Nézzük meg RVIZ2 segítségével, így fog kinézni:

+
ros2 launch arj_transforms_cpp rviz1.launch.py
+
+

transforms01

+

Vizsgáljuk meg a pub_transforms.cpp fájlt. (Python esetén a _py package-ben a transforms.py fájlt.)

+
cd ~/ros2_ws/src/arj_packages/arj_transforms_cpp
+
+
code .
+
+

A legérdekesebb most talán a loop függvény. Pitagorasz tétele értelmében tr1.transform.translation.x és y a színusz és a koszinusz szögfüggvények miatt mindig egy körön fog elhelyezkedni. A loop_count_ változó folyamatosan növekszik, így a kört az x és az y óramutató járásának megfelelően teszi meg. Ez a speed1 értékének megfeleően gyorsítható rqt_reconfigure segítségével (ezt később megnézzük). A kör nagysága, az origo-tól való távolsága pedig a distance1 segítségével növelhető. Hasonló a helyzet a tr2.transform esetében is, ami az orbit1 -> orbit2 transzfomot adja. A tr1.transform egy plusz forgatást is jelent, quaternion segítségével. A roll, pitch, yaw értékekből csak az utóbbinál forgatunk, tehát csak Z tengely szerint.

+
void loop()
+{
+    // Publish transforms
+    tr1.header.stamp = this->get_clock()->now();
+    tr1.header.frame_id = "map";
+    tr1.child_frame_id = "orbit1";
+    tr1.transform.translation.x = sin(loop_count_ * speed1) * distance1;
+    tr1.transform.translation.y = cos(loop_count_ * speed1) * distance1;
+    tf2::Quaternion quaternion1;
+    quaternion1.setRPY(0.0, 0.0, loop_count_ * speed1);
+    quaternion1=quaternion1.normalize();
+    tr1.transform.rotation.x = quaternion1.x();
+    tr1.transform.rotation.y = quaternion1.y();
+    tr1.transform.rotation.z = quaternion1.z();
+    tr1.transform.rotation.w = quaternion1.w();
+    tf_broadcaster_->sendTransform(tr1);
+    tr2.header.stamp = this->get_clock()->now();
+    tr2.header.frame_id = "orbit1";
+    tr2.child_frame_id = "orbit2";
+    tr2.transform.translation.x = sin(loop_count_ * speed2) * distance2;
+    tr2.transform.translation.y = cos(loop_count_ * speed2) * distance2;
+    tf_broadcaster_->sendTransform(tr2);
+    loop_count_++;
+}
+
+

Bővítsük orbit3 statikus transformmal:

+
ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3
+
+

Állítsuk a sebességeket és a távolságokat:

+
ros2 run rqt_reconfigure rqt_reconfigure
+
+

+

Hirdessünk egy markert, majd adjuk hozzá RVIZ2-ben. Ez a parancs orbit2-re hirdet egy zöld kockát:

+
ros2 topic pub --rate 40 --print 40 /marker_topic2 visualization_msgs/msg/Marker '{header: {frame_id: "orbit2"}, ns: "markers2", id: 2, type: 1, action: 0, pose: {position: {x: 0.0, y: 0.0, z: 0.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}, scale: {x: 1.0, y: 1.0, z: 1.0}, color: {r: 0.2, g: 0.4, b: 0.3, a: 1.0}}'
+
+

Ez a parancs orbit1-re hirdet egy piros nyilat:

+
ros2 topic pub --rate 40 --print 40 /marker_topic3 visualization_msgs/msg/Marker '{header: {frame_id: "orbit1"}, ns: "markers3", id: 3, type: 0, action: 0, pose: {position: {x: 0.0, y: 0.0, z: 0.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}, scale: {x: 1.8, y: 0.4, z: 0.4}, color: {r: 0.8, g: 0.2, b: 0.2, a: 1.0}}'
+
+

A Marker üzenet tpye attribútuma adja meg, hogy a marker pl ARROW=0 vagy CUBE=1:

+
ros2 interface show  visualization_msgs/msg/Marker
+
+...
+type:
+int32 ARROW=0
+int32 CUBE=1
+int32 SPHERE=2
+int32 CYLINDER=3
+int32 LINE_STRIP=4
+int32 LINE_LIST=5
+int32 CUBE_LIST=6
+int32 SPHERE_LIST=7
+int32 POINTS=8
+int32 TEXT_VIEW_FACING=9
+int32 MESH_RESOURCE=10
+int32 TRIANGLE_LIST=11
+
+...
+
+

További színekre példa lejjebb, színekről pedig bővebben: github.com/jkk-research/colors.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
...
0.96 0.26 0.21
0.53 0.05 0.31
0.19 0.11 0.57
0.73 0.87 0.98
0.13 0.59 0.95
0.00 0.59 0.53
0.78 0.90 0.79
0.30 0.69 0.31
0.80 0.86 0.22
1.00 0.93 0.70
1.00 0.76 0.03
1.00 0.44 0.00
0.84 0.80 0.78
0.47 0.33 0.28
0.24 0.15 0.14
0.96 0.96 0.96
0.62 0.62 0.62
0.13 0.13 0.13
+

Önálló feladat

+

Önálló feladatként készítsünk egy my_launch_pkg nevű package-t, amiben egy run_transforms_and_markers.launch.py elindítja a:

+
    +
  • node-ot, ami a map, orbit1 és orbit2 frame-ket publikálja (ros2 run arj_transforms_cpp pub_transforms)
  • +
  • az rqt_reconfigure-t (ros2 run rqt_reconfigure rqt_reconfigure)
  • +
  • a statikus orbit3 frame-et (ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3)
  • +
  • és az Rviz2-t indító launch-t is (ros2 launch arj_transforms_cpp rviz1.launch.py)
  • +
+

Ellenőrizzük rviz2-ben a helyes működést.

+

Tehát indítható legyen az önálló feladat végén a következő paranccsal:

+
ros2 launch my_launch_pkg run_transforms_and_markers.launch.py
+
+

Megoldás: elérhető az önálló feladatok között

+

Segítség az önálló feladathoz

+

A ros2 run tf2_ros static_transform_publisher --x 1.0 --y 0.2 --z 1.4 --qx 0.0 --qy 0.0 --qz 0.0 --qw 1.0 --frame-id orbit2 --child-frame-id orbit3 az előző órák alapján könnyen összeállítható:

+
Node(
+    package='tf2_ros',
+    executable='static_transform_publisher',
+    arguments=['1.0', '0.2', '1.4','0', '0', '0', '1', 'orbit2','orbit3'],
+),     
+
+
+

Warning

+

Nehezebb dolgunk van az Rviz2-vel, ugyanis ott egy launch fájlt kell meghívni nem egy node-ot.

+
+

Első, de kevésbé szép opció, hogy bemásoljuk az eredeti launch fájlt és azt egészítjük ki:

+
from launch import LaunchDescription
+from launch_ros.actions import Node
+import os
+from ament_index_python.packages import get_package_share_directory
+
+
+def generate_launch_description():
+
+    pkg_name = 'arj_transforms_cpp'
+    pkg_dir = get_package_share_directory(pkg_name)
+
+
+    return LaunchDescription([
+        Node(
+            package='rviz2',
+            namespace='',
+            executable='rviz2',
+            name='rviz2',
+            arguments=['-d', [os.path.join(pkg_dir, 'rviz', 'rviz1.rviz')]]
+        )
+    ])
+
+

Második, sokkal szebb opció, hogy a launch fájlt include-oljuk a launch fájlba:

+
from launch import LaunchDescription
+from launch_ros.actions import Node
+from launch.actions import IncludeLaunchDescription
+from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch_ros.substitutions import FindPackageShare
+
+
+def generate_launch_description():
+    return LaunchDescription([
+        # ros2 launch arj_transforms_cpp rviz1.launch.py
+        IncludeLaunchDescription(
+            PythonLaunchDescriptionSource([
+                FindPackageShare("arj_transforms_cpp"), '/launch/', 'rviz1.launch.py'])
+        ),
+    ])
+
+

Házi feladat

+
+

Házi feladat

+

Készítsünk ROS 2 package-t (mindegy, hogy python vagy C++), ami a map frame-re hirdet egy CUBE típusú markert. A marker színe legyen a md_blue_500 (0.13 0.59 0.95) és a mérete 1.0. A marker pozíciója legyen a map frame-ben (r1, r2, 0.0). AZ r1, r2 két véletlenszám 0 és 2 közötti intervallumon. Hirdesse a topicot 5 Hz-en. A marker id-ja legyen 1. A marker üzenetet a /marker_topic topic-ra hirdessük. A package neve legyen my_cool_marker_pkg.

+
+

További

+

Python notebook transform

+

Python notebook quaternion

+

gps_utm.ipynb

+ + +

rh

+

lexus 3d

+

Olvasnivaló

+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/transzformaciok/quaternion.ipynb b/transzformaciok/quaternion.ipynb new file mode 100644 index 0000000..4d0e9e8 --- /dev/null +++ b/transzformaciok/quaternion.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# without ROS 2\n", + "\n", + "import math\n", + "import numpy as np\n", + "\n", + "def quaternion_to_euler(q0: float, q1: float, q2: float, q3: float) -> tuple:\n", + " roll = math.atan2(2 * ((q2 * q3) + (q0 * q1)), q0**2 - q1**2 - q2**2 + q3**2)\n", + " pitch = math.asin(2 * ((q1 * q3) - (q0 * q2)))\n", + " yaw = math.atan2(2 * ((q1 * q2) + (q0 * q3)), q0**2 + q1**2 - q2**2 - q3**2)\n", + " return (roll, pitch, yaw)\n", + "\n", + "\n", + "def quaternion_from_euler(ai, aj, ak):\n", + " ai /= 2.0\n", + " aj /= 2.0\n", + " ak /= 2.0\n", + " ci = math.cos(ai)\n", + " si = math.sin(ai)\n", + " cj = math.cos(aj)\n", + " sj = math.sin(aj)\n", + " ck = math.cos(ak)\n", + " sk = math.sin(ak)\n", + " cc = ci*ck\n", + " cs = ci*sk\n", + " sc = si*ck\n", + " ss = si*sk\n", + "\n", + " q = np.empty((4, ))\n", + " q[0] = cj*sc - sj*cs\n", + " q[1] = cj*ss + sj*cc\n", + " q[2] = cj*cs - sj*sc\n", + " q[3] = cj*cc + sj*ss\n", + "\n", + " return q\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "geometry_msgs.msg.Quaternion(x=0.0, y=1.0, z=0.0, w=0.0)\n" + ] + } + ], + "source": [ + "import geometry_msgs.msg\n", + "\n", + "my_quat = geometry_msgs.msg.Quaternion()\n", + "my_quat.x = 0.0\n", + "my_quat.y = 1.0\n", + "my_quat.z = 0.0\n", + "my_quat.w = 0.0\n", + "\n", + "# Print my_quat\n", + "print(my_quat)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "geometry_msgs.msg.Quaternion(x=0.0, y=1.0, z=0.0, w=0.0)\n" + ] + } + ], + "source": [ + "from geometry_msgs.msg import Quaternion\n", + "\n", + "# Create a list of floats, which is compatible with tf2\n", + "# Quaternion methods\n", + "quat_tf = [0.0, 1.0, 0.0, 0.0]\n", + "\n", + "# Convert a list to geometry_msgs.msg.Quaternion\n", + "msg_quat = Quaternion(x=quat_tf[0], y=quat_tf[1], z=quat_tf[2], w=quat_tf[3])\n", + "\n", + "print(msg_quat)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(3.141592653589793, 0.0, 3.141592653589793)\n" + ] + } + ], + "source": [ + "# convert geometry_msgs.msg.Quaternion to euler angles\n", + "eulers = quaternion_to_euler(msg_quat.w, msg_quat.x, msg_quat.y, msg_quat.z)\n", + "print(eulers)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0. 0. 0.70710678 0.70710678]\n" + ] + } + ], + "source": [ + "q1 = quaternion_from_euler(0, 0, np.pi/2)\n", + "\n", + "print(q1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/transzformaciok/right_hand_rule01.svg b/transzformaciok/right_hand_rule01.svg new file mode 100644 index 0000000..b957035 --- /dev/null +++ b/transzformaciok/right_hand_rule01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/transzformaciok/rotation3d.svg b/transzformaciok/rotation3d.svg new file mode 100644 index 0000000..64457b3 --- /dev/null +++ b/transzformaciok/rotation3d.svg @@ -0,0 +1,446 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/transzformaciok/rqt_reconf01.png b/transzformaciok/rqt_reconf01.png new file mode 100644 index 0000000..8c9f0f6 Binary files /dev/null and b/transzformaciok/rqt_reconf01.png differ diff --git a/transzformaciok/tf_examples01.svg b/transzformaciok/tf_examples01.svg new file mode 100644 index 0000000..0aa3c2b --- /dev/null +++ b/transzformaciok/tf_examples01.svg @@ -0,0 +1,192 @@ + + + + + +map + + + + + + + + + +gps + + + + + + + + + +base_link + +velodyne_left + +zed_front + +laser + + + + + + + + + + + + + + + + + + + + + + + + + +map + + + + + + + + + +ndt_map + + + + + + + + + +base_link + +sensor_a + +sensor_b + +... + + + + + + + + + + + + + + + + + + + + + + + + + +Examples + +map + + + + + + + + + +kalman_f + + + + + + + + + +base_link + +... + + + + + + + + + + + + + + + + + + + + + + + + + +... + +... + +... + + + + + + + + + +... + + + + + + + + + + diff --git a/transzformaciok/tf_examples02.svg b/transzformaciok/tf_examples02.svg new file mode 100644 index 0000000..5dcc9da --- /dev/null +++ b/transzformaciok/tf_examples02.svg @@ -0,0 +1,5677 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +X +Y + +Z +map + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + base_link + base_link + base_link + +(697210, 5285720) + + left_os1/os1_sensor + left_os1/os1_sensor + left_os1/os1_sensor + + + + + + + + + + + + + + + + + + + gps + gps + gps + + + + + + (-1.33, -0.408) + (-1.33, -0.408) + (-1.33, -0.408) + + + (1.769, 0.58) + (1.769, 0.58) + (1.769, 0.58) + + diff --git a/transzformaciok/tf_examples03.svg b/transzformaciok/tf_examples03.svg new file mode 100644 index 0000000..2899817 --- /dev/null +++ b/transzformaciok/tf_examples03.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/transzformaciok/utm01.svg b/transzformaciok/utm01.svg new file mode 100644 index 0000000..e51d582 --- /dev/null +++ b/transzformaciok/utm01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/transzformaciok/vehicle_axes01.svg b/transzformaciok/vehicle_axes01.svg new file mode 100644 index 0000000..85c1a23 --- /dev/null +++ b/transzformaciok/vehicle_axes01.svg @@ -0,0 +1 @@ + \ No newline at end of file

GitHub Copilot beszerzése SZE hallgatóknak