{"id":386023,"date":"2024-06-29T06:28:09","date_gmt":"2024-06-29T06:28:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=386023"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=386023","title":{"rendered":"<span>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u043e\u0431\u043e\u0442\u0430\u043c\u0438 \u0438\u0437 VR<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 \u0445\u043e\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f, \u043d\u043e \u043f\u043e \u043e\u0431\u044a\u0435\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u043d\u0435 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f. \u0420\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 9 \u0447\u0430\u0441\u0442\u0435\u0439, 6 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b \u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u044b \u0432 3 \u0441\u0442\u0430\u0442\u044c\u0438. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043d\u0442\u0441\u043a\u0440\u0438\u043d\u043e\u0432 \u0438 \u043a\u0443\u0441\u043a\u043e\u0432 \u043a\u043e\u0434\u0430(\u0432\u0441\u0435 \u0443\u0431\u0440\u0430\u043d\u043e \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u044b). \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u043f\u0443\u0449\u0443 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0434\u0435\u0442\u0430\u043b\u0438 \u2013 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0438\u0437\u0432\u0438\u043d\u044f\u044e\u0441\u044c, \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043b\u0438\u0447\u043a\u0443 \u0438\u043b\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0433 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u0441\u0430\u043c\u043e \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u0443\u043c\u0435\u044e\u0449\u0435\u0435\u0441\u044f \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043b\u0435\u0442\u0435\u043b\u043e \u0438\u0437 \u0433\u043e\u043b\u043e\u0432\u044b.<\/p>\n<p>\u0427\u0430\u0441\u0442\u0438 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438: <\/p>\n<ol>\n<li>\n<p><strong>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Websocket (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 WebRTC Connection + DataChannel (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 WebRTC Media streaming (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u043c\u0435\u0440\u043e\u0439 (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u043d\u0430 ROS (<em>\u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0431\u043e\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 (<em>\u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f (<em>\u043d\u0435 \u0432\u0437\u044f\u0442\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<\/ol>\n<p>\u0410 \u0432\u043e\u0442 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043a \u043a\u043e\u043d\u0446\u0443 6 \u0447\u0430\u0441\u0442\u0438:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64492718cf7e13dfb3c342ed\" data-style=\"\" id=\"64492718cf7e13dfb3c342ed\" width=\"\"><\/div>\n<blockquote>\n<p><strong>Disclaimer 1.<\/strong><\/p>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0430 \u0443 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439, \u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u043a \u044d\u0442\u0438\u043c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c, \u0442\u0430\u043a \u043a\u0430\u043a: <\/p>\n<p>1. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u2013 \u044d\u0442\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Proof of Concept, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438\u0441\u044c, \u0434\u0430\u0431\u044b \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<p>2. Unity\/C#\/Python \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435, \u0430 \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0432\u0435\u0449\u0430\u043c\u0438, \u043a\u0430\u043a \u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c\u0438 \u0432 python \u0438 c#, \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u043b\u044e\u0434\u0430.<\/p>\n<p>3. \u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 4-\u043c\u044f \u042f\u041f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u044f\u0436\u043a\u043e \u0434\u043b\u044f \u043c\u043e\u0435\u0439 \u0441\u043a\u043e\u0440\u043e\u0432\u0430\u0440\u043a\u0438, \u043c\u043d\u0435 \u0438 \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u043b\u0430\u043a\u0430\u0442\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043e\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u043d\u0430\u0434\u0435\u043b\u0430\u043b, \u043d\u043e \u0441 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u044f \u0443\u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043c\u043e\u0433 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u043f\u0440\u043e\u0441\u0442\u0438\u0442\u0435.<\/p>\n<\/blockquote>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f<\/h2>\n<p>\u041f\u0440\u043e\u0432\u0435\u0434\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0430\u0443\u0434\u0438\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u0438 \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438, \u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0441 \u0440\u043e\u0431\u043e\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0440\u0443\u043a\u043e\u0439-\u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0439 \u043a RPI3B+, \u0438 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u043e\u043a\u0440\u0443\u0433 \u0438\u0434\u0435\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u043c \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u0438\u0437 VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0438, \u043d\u043e \u0438 \u0447\u0435\u0440\u0435\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442.<\/p>\n<p>\u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0432 \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043c\u0438\u043d\u0443\u0441 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 VR \u0438 \u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0435\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebRTC \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f P2P \u0442\u0440\u0430\u0444\u0438\u043a\u0430, \u0438 Websocket \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 WebRTC, \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043f\u043b\u044e\u0441 WebRTC \u2013 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0440\u043e\u0445\u043e\u0434\u0430 \u0437\u0430 NAT \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e stun\/turn-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<p>\u0412 WebRTC \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 DataChannel, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u044b \u0438 MediaStreams \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432\u0438\u0434\u0435\u043e\/\u0430\u0443\u0434\u0438\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430, \u0447\u0442\u043e \u043c\u044b \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 USB-\u043a\u0430\u043c\u0435\u0440\u044b \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>Websocket \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 WebRTC-\u043f\u0438\u0440\u0430\u043c\u0438, \u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 REST \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u043d\u043e \u043c\u0438\u043d\u0443\u0441 REST \u2013 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0440\u043e\u0441\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u0422.\u0435. \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u0443, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0436\u0434\u0430\u0442\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u043e\u043f\u0440\u043e\u0441\u0430 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c WebRTC.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0438\u0437 3-\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u2013 <strong>\u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/strong> \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c WebRTC, <strong>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 (RPI-\u0445\u043e\u0441\u0442)<\/strong> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u043e\u0432 \u0438 \u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a, \u0438 <strong>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442(VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435)<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a, \u0438 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 RPI-\u0445\u043e\u0441\u0442. \u0422\u0430\u043a \u0436\u0435, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e HTML\/JS, \u043e\u043d \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432 \u043f\u043e\u044d\u0442\u0430\u043f\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0435.<\/p>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SpringBoot, \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043d\u0430 RPI \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Python, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Unity XR, \u0442\u0430\u043a \u0436\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u0432\u0435\u0431 \u2013 html-bootstrap-js-jquery.<\/p>\n<blockquote>\n<p><strong>Disclaimer 2<\/strong><\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u0432\u0441\u0435 \u0447\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0431\u043e\u0442\u043e\u0442\u0435\u0445\u043d\u0438\u043a\u0438 \u043d\u0443\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c ROS \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043d\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0443 \u043f\u043e\u043f\u0440\u043e\u0449\u0435, \u0430 \u0443\u0436\u0435 \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043d\u0430 ROS. \u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u2013 \u0432\u0441\u0435 \u043f\u043e\u0437\u043d\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438.<\/p>\n<\/blockquote>\n<p><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/strong><\/p>\n<ul>\n<li>\n<p>VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438, \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Oculus Quest 2.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0431\u0435\u043b\u044c USB Type-C 1-2\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u044b \u043a Unity \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>Raspberry Pi 3B+ \u0441 \u0411\u041f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0442\u0430 PCA9685, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043e\u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f I2C \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0441 RPI \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c 16-\u044e \u0428\u0418\u041c \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0440\u043e\u043d\u0448\u0442\u0435\u0439\u043d-\u043f\u043e\u0434\u0432\u0435\u0441 \u0434\u043b\u044f SG90 \u0438 2 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u0430 SG90, \u0434\u043b\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0432\u0435\u0441\u0430 \u043a\u0430\u043c\u0435\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>USB-\u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u0430, \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0432\u0438\u0434\u0435\u043e \u0432 VR.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440(6Dof Arm MG996R\/YF-6125MG \u0443 \u043c\u0435\u043d\u044f <a href=\"https:\/\/aliexpress.ru\/item\/32844805357.html?sku_id=10000014000036636\" rel=\"noopener noreferrer nofollow\">\u0442\u0430\u043a\u043e\u0439<\/a>), \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0442\u043e\u0442 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0437 VR.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u043e\u0434\u043e\u0432 \u041c\u0430\u043c\u0430-\u041f\u0430\u043f\u0430(40\u0441\u043c.). \u0423 \u043c\u043e\u0438\u0445 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u043e\u0432 \u0441\u0442\u043e\u043a\u043e\u0432\u044b\u0435 \u043a\u0430\u0431\u0435\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u0438 \u0438 \u0438\u0445 \u043d\u0435 \u0434\u043e\u0442\u044f\u043d\u0443\u0442\u044c \u0434\u043e \u043f\u043b\u0430\u0442\u044b PCA9685.<\/p>\n<\/li>\n<li>\n<p>\u0411\u043b\u043e\u043a \u043f\u0438\u0442\u0430\u043d\u0438\u044f 220V \u2013 5V. \u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 (\u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440, RPI, \u0411\u041f, \u043f\u043e\u0434\u0432\u0435\u0441 \u0434\u043b\u044f \u043a\u0430\u043c\u0435\u0440\u044b), \u0443 \u043c\u0435\u043d\u044f \u044d\u0442\u043e \u043b\u0438\u0448\u043d\u044f\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u043b\u0430\u0441\u0442\u0438\u043a\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043b\u043b\u0430\u0436\u0430, \u043a\u0443\u0434\u0430 \u0441\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>(\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e) \u0420\u043e\u0443\u0442\u0435\u0440 \u043d\u0430 OWRT, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043f\u043e RTT\/Jitter.<\/p>\n<\/li>\n<li>\n<p>(\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e) \u0411\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u043f\u0440\u044f\u043c\u044b\u0435 \u0440\u0443\u043a\u0438, \u043d\u043e \u0438 \u0441 &#171;\u043d\u0435 \u043e\u0447\u0435\u043d\u044c&#187; \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0422\u0440\u0435\u0431\u0443\u0435\u043c\u0430\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u0430:<\/strong><\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Linux.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Python.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Java \u0438 SpringBoot.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Unity \u0438 C#.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e HTML\/Bootstrap\/JS\/JQuery.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Websocket \u0438 WebRTC.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/strong> \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043f\u043e\u0434 Win10, \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044f\u0441\u044c \u043d\u0430 Ubuntu WSL \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 RPI. \u041d\u0430 Win10 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b:<\/p>\n<ul>\n<li>\n<p>Eclipse IDE, \u0434\u043b\u044f SpringBoot.<\/p>\n<\/li>\n<li>\n<p>Unity + MS Visual Studio, \u0434\u043b\u044f VR \u0447\u0430\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>Oculus Client, \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f Oculus Link.(\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u044b ADB \u0434\u043b\u044f Oculus, \u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u043e\u043d\u0438 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u0440\u0430\u043d\u0435\u0435).<\/p>\n<\/li>\n<\/ul>\n<h3>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u2013 \u043f\u043e\u0434\u0432\u0435\u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u0441 SG90 \u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u0441 \u043f\u043b\u0430\u0442\u043e\u0439 PCA9685(\u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b \u0441\u0432\u043e\u044e USB-\u043a\u0430\u043c\u0435\u0440\u0443, \u0442.\u043a. \u043a\u043e\u0440\u043f\u0443\u0441 \u0431\u044b\u043b \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u0439).<\/p>\n<p>\u0412 \u043f\u043b\u0430\u0442\u0443 PCA9685 \u0441\u0435\u0440\u0432\u044b SG90 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432 \u043f\u043e\u0440\u0442\u044b 0 \u0438 1. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u0440\u043e\u0442\u0430\u0446\u0438\u044e \u043a\u0430\u043c\u0435\u0440\u044b \u043f\u043e \u043e\u0441\u044f\u043c(\u043f\u043e\u0432\u043e\u0440\u043e\u0442 \u0433\u043e\u043b\u043e\u0432\u044b \u0432 VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u0435). \u0414\u0430\u043b\u0435\u0435 \u0434\u0435\u043b\u0430\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043a\u0430\u043c\u0435\u0440\u044b \u043d\u0430 \u043a\u0440\u043e\u043d\u0448\u0442\u0435\u0439\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u0430 \u043c\u0435\u0441\u0442\u043e\u043c, \u0433\u0434\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440. \u041a\u0430\u0431\u0435\u043b\u0438 \u043e\u0442 \u0440\u0430\u0437\u044a\u0435\u043c\u043e\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0430 \u0443\u0434\u043b\u0438\u043d\u044f\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u0430\u0431\u0435\u043b\u0435\u0439 \u00ab\u041f\u0430\u043f\u0430-\u041c\u0430\u043c\u0430\u00bb.<\/p>\n<details class=\"spoiler\">\n<summary>\u043f\u043e\u0434\u0432\u0435\u0441:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/5d9\/a3b\/86e\/5d9a3b86e80577ecffc1f88b56879d6f.jpg\" width=\"1868\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d9\/a3b\/86e\/5d9a3b86e80577ecffc1f88b56879d6f.jpg\" data-blurred=\"true\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u0442\u044b PCA9685 \u0438 RPI3B+:<\/p>\n<pre><code> GND - Pin-6  SCL - GPIO-3(Pin5)  SDA - GPIO-2(Pin3)  VCC - Pin1  V+  - Pin4<\/code><\/pre>\n<p>\u041f\u0438\u0442\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043b\u0435\u043c\u043c\u0443 \u043d\u0430 PCA9685, \u043d\u043e \u0434\u043e 6 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e 2 \u0441\u0435\u0440\u0432\u043e SG90 \u0438 \u0431\u0440\u0430\u0442\u044c \u043f\u0438\u0442\u0430\u043d\u0438\u0435 \u0441 RPI \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.  <\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a RPI \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b RPI \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 (Pin 39-40) (\u043a\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u043c\u0438\u0433\u0430\u043d\u0438\u044f \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434\u043e\u043c).<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c RPI, \u0437\u0430\u043b\u0438\u0432\u0430\u0435\u043c \u041e\u0421 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e RPI Imager(RPI OS Light x64). \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0437\u0430\u043b\u0438\u0432\u043a\u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0430\u043f\u0434\u0435\u0439\u0442\/\u0430\u043f\u0433\u0440\u0435\u0439\u0434 apt \u0438 \u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b(ssh-\u043a\u043b\u044e\u0447\u0438, samba \u0438 \u0442.\u0434.). <\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c I2C \u0432 RPI \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043f\u0430\u043a\u0435\u0442 \u043f\u0430\u043a\u0435\u0442 \u0441 i2c-tools:<\/p>\n<p> <code>sudo apt install i2c-tools -y<\/code><\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 raspi \u043a\u043e\u043d\u0444\u0438\u0433 \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 I2C:<\/p>\n<p> <code>sudo raspi-config<\/code><\/p>\n<p> <code>Interface Options \u2192 &lt;Enable I2C><\/code><\/p>\n<p> <code>reboot<\/code><\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c I2C:<\/p>\n<p><code>i2cdetect -y 1<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0435:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 00:                         -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: 70 -- -- -- -- -- -- \u2013<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u0441\u0435 \u043d\u043e\u0440\u043c \u0438 \u043f\u043b\u0430\u0442\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0430.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0440\u0432\u043e \u0447\u0435\u0440\u0435\u0437 PCA9685 \u0438\u0437 Python \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f pip3-\u043f\u0430\u043a\u0435\u0442\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0442\u0430\u0432\u0438\u043c pip3:<\/p>\n<p><code>sudo apt-get install python3-pip<\/code><\/p>\n<p> \u0418 \u0441\u0442\u0430\u0432\u0438\u043c \u0441\u0430\u043c\u0438 \u043f\u0430\u043a\u0435\u0442\u044b:<\/p>\n<p><code>pip3 install adafruit-circuitpython-pca9685<\/code><\/p>\n<p><code>pip3 install adafruit-circuitpython-motorkit<\/code><\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043f\u043b\u043e\u0445\u043e\u0439 \u0442\u043e\u043d, \u043d\u043e \u0442\u0443\u0442 \u043c\u044b \u0441\u0440\u0435\u0436\u0435\u043c \u0443\u0433\u043b\u044b, \u0442.\u00a0\u043a. \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430 ROS.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c:<\/p>\n<p><code>nano \/home\/pi3\/shared\/testpi3b\/part0.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>part0.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import RPi.GPIO as GPIO import time import busio from board import SCL, SDA from adafruit_motor import servo from adafruit_pca9685 import PCA9685  GPIO.setmode(GPIO.BCM) GPIO.setup(21, GPIO.OUT) i2c = busio.I2C(SCL, SDA) pca = PCA9685(i2c) pca.frequency = 50 servoX = servo.Servo(pca.channels[0], min_pulse=500, max_pulse=2400)      print(\"Simple testing\")  try:     for i in range(3):         print(\"Blink\")         GPIO.output(21,True)         servoX.angle = 0         time.sleep(1)         GPIO.output(21,False)         servoX.angle = 180         time.sleep(1) except KeyboardInterrupt:     GPIO.cleanup()  print(\"Test done\") GPIO.cleanup()<\/code><\/pre>\n<p>PS: \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u0435\u0440\u0432\u043e \u043f\u043e \u0428\u0418\u041c \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0447\u0430\u0441\u0438\u043a \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043f\u043e \u0442\u0435\u043c\u0435.<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e &#8212; \u0442\u043e \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434 \u043c\u043e\u0440\u0433\u043d\u0435\u0442 3 \u0440\u0430\u0437\u0430 \u0438 \u0441\u0435\u0440\u0432\u043e\u043c\u043e\u0442\u043e\u0440 \u0432 0-\u043f\u043e\u0440\u0442\u0443 PCA9685 3 \u0440\u0430\u0437\u0430 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u043e\u0432\u043e\u0440\u043e\u0442 0-180 \u0433\u0440\u0430\u0434\u0443\u0441\u043e\u0432. \u041f\u043e \u0434\u0435\u0442\u0430\u043b\u044f\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0437 Python \u0441 PCA9685 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/learn.adafruit.com\/16-channel-pwm-servo-driver\/overview\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>, \u0441 Rpi.GPIO <a href=\"https:\/\/pypi.org\/project\/RPi.GPIO\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>. \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441 RPI-\u0445\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430.<\/p>\n<h3>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/h3>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0443\u043d\u043a\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 SSL \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b websocket-over-ssl (\u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 SSL, \u043d\u043e \u043c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0440\u0430\u0437\u0443 \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435).<\/p>\n<p>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0441\u0430\u043c\u043e\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442(\u044f \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u044e \u0438\u0437 \u043f\u043e\u0434 WSL Ubuntu 20):<\/p>\n<p><code>sudo openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout .\/ssl\/ssl-selfsigned.key -out .\/ssl\/ssl-selfsigned.crt<\/code><\/p>\n<p> &#8230; \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u043d\u0430 \u0432\u0441\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c IP-\u0445\u043e\u0441\u0442\u0430 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440. \u0418 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 PKS#12:<\/p>\n<p><code>openssl pkcs12 -export -in .\/ssl\/ssl-selfsigned.crt -inkey .\/ssl\/ssl-selfsigned.key -out .\/ssl\/ssl-selfsigned.p12<\/code><\/p>\n<p>\u0424\u0430\u0439\u043b\u044b \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0430 Win10, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u043d\u0430 Win10.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u0435\u043b\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 SpringBoot \u043f\u0440\u043e\u0435\u043a\u0442 \u0447\u0435\u0440\u0435\u0437 Spring Initializr \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'org.webjars:webjars-locator-core' implementation 'org.webjars:sockjs-client:1.0.2' implementation 'org.webjars:bootstrap:3.3.7' implementation 'org.webjars:jquery:3.1.1-1' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test'<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 9000 \u0441 \u043d\u0430\u0448\u0438\u043c \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>application.yml:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">server:   port: 9000   ssl:     key-store: classpath:ssl-selfsigned.p12     key-store-password:     keyStoreType: PKCS12<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0434\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e\/\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SecurityFilterChain:<\/p>\n<details class=\"spoiler\">\n<summary>SecurityConfiguration.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Configuration public class SecurityConfiguration{ @Bean SecurityFilterChain securityFilterChain(HttpSecurity http)      throws Exception {     http     .authorizeHttpRequests((requests) -> requests     .requestMatchers(\"\/\", \"\/**\", \"\/main\", \"\/main\/**\")             .permitAll()     ); return http.build(); } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u043b\u044f HTML \u0438 JS-\u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<details class=\"spoiler\">\n<summary>SimpleController.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>@Controller public class SimpleController { @GetMapping(\"\/main\") public String roboPage() { return \"main\"; } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>main.html<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" xmlns:th=\"http:\/\/www.thymeleaf.org\"> &lt;head> &lt;meta charset=\"UTF-8\"> &lt;title>Robo WS+RTC:&lt;\/title> &lt;!-- Head bootstrap as a fragment --> &lt;div th:insert=\"~{fragments :: bootstraphead}\">&lt;\/div> &lt;script src=\"\/robo.js\">&lt;\/script> &lt;\/head>   &lt;body>     &lt;div id=\"main-content\" class=\"container\">       &lt;div class=\"row-md-6\">       &lt;p>Part 0&lt;\/p>       &lt;\/div>     &lt;\/div>   &lt;\/body> &lt;\/html><\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>fragments.html<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html xmlns:th=\"http:\/\/www.thymeleaf.org\"> &lt;body> &lt;!-- Bootstraphead CSS -->   &lt;div th:fragment=\"bootstraphead\">      &lt;meta charset=\"utf-8\">     &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">        &lt;link rel=\"stylesheet\" href=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@4.4.1\/dist\/css\/bootstrap.min.css\"        integrity=\"sha384-Vkoo8x4CGsO3+Hhxv8T\/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh\" crossorigin=\"anonymous\">     &lt;script src=\"https:\/\/code.jquery.com\/jquery-3.4.1.slim.min.js\"        integrity=\"sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n\" crossorigin=\"anonymous\">&lt;\/script>     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@5.2.3\/dist\/js\/bootstrap.bundle.min.js\"        integrity=\"sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK\/7HAuoJl+0I4\" crossorigin=\"anonymous\">&lt;\/script>     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@popperjs\/core@2.11.6\/dist\/umd\/popper.min.js\"        integrity=\"sha384-oBqDVmMz9ATKxIep9tiCxS\/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh\/jp3\" crossorigin=\"anonymous\">&lt;\/script>     &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@5.2.3\/dist\/js\/bootstrap.min.js\"        integrity=\"sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V\" crossorigin=\"anonymous\">&lt;\/script>   &lt;\/div> &lt;\/body> &lt;\/html><\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0424\u0430\u0439\u043b robo.js &#8212; \u043f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u0432\u0438\u043c \u043f\u0443\u0441\u0442\u043e\u0439, \u043e\u043d \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/120\/291\/043\/12029104379e23fe4b7bab04eead65b1.png\" width=\"294\" height=\"448\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/120\/291\/043\/12029104379e23fe4b7bab04eead65b1.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 HTTPS \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u0438\u043d\u0430\/\u043f\u0430\u0440\u043e\u043b\u044f \u043f\u0440\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0438(\u043d\u0430\u043c \u044d\u0442\u043e \u043f\u043e\u043a\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f). \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0432 BootDashboard \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435(https:\/\/&lt;ip>:9000\/main), \u0447\u0442\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0447\u0435\u0440\u0435\u0437 https.<\/p>\n<h3>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442(Unity VR)<\/h3>\n<p>\u0418 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u0442\u0430\u043f &#8212; \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 Unity. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443 \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d Unity Hub, Oculus Client, \u0438 IDE \u0434\u043b\u044f C#. \u0427\u0435\u0440\u0435\u0437 Unity Hub \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Editor (2021.3.19f1). \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 (3D Core). \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c XR Plugin Managment \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f XR:<\/p>\n<details class=\"spoiler\">\n<summary>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438(\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043d\u0442\u0441\u043a\u0440\u0438\u043d\u043e\u0432):<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a50\/770\/58e\/a5077058eea67eb57e79ad89af113226.png\" width=\"639\" height=\"555\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a50\/770\/58e\/a5077058eea67eb57e79ad89af113226.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8f4\/eb5\/af2\/8f4eb5af208648c3ef59a1ff36285f7c.png\" width=\"638\" height=\"400\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8f4\/eb5\/af2\/8f4eb5af208648c3ef59a1ff36285f7c.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c40\/6ef\/ac5\/c406efac55f4f9c8e0bed4757b4d6e3f.png\" width=\"626\" height=\"456\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c40\/6ef\/ac5\/c406efac55f4f9c8e0bed4757b4d6e3f.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ef8\/ad9\/cf5\/ef8ad9cf503df6fbee617616eec09c5f.png\" width=\"649\" height=\"475\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ef8\/ad9\/cf5\/ef8ad9cf503df6fbee617616eec09c5f.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b59\/26c\/752\/b5926c7528f73162d2ef0fe0166ab3ac.png\" width=\"638\" height=\"428\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b59\/26c\/752\/b5926c7528f73162d2ef0fe0166ab3ac.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u044c\u0448\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 &#8212; XR Interaction Toolkit, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0441\u0446\u0435\u043d\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0448\u043b\u0435\u043c\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>XR Interaction Toolkit<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/843\/e4b\/628\/843e4b6283c27a4acf726b028272a08a.png\" alt=\"Window -> Package Manager -> Unity Registry -> XR Interaction Toolkit -> Install&#187; title=&#187;Window -> Package Manager -> Unity Registry -> XR Interaction Toolkit -> Install&#187; width=&#187;643&#8243; height=&#187;461&#8243; data-src=&#187;https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/843\/e4b\/628\/843e4b6283c27a4acf726b028272a08a.png&#187;\/><\/p>\n<div><figcaption>Window -> Package Manager -> Unity Registry -> XR Interaction Toolkit -> Install<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d18\/511\/141\/d18511141431701b4c7ef783de2787d5.png\" width=\"653\" height=\"493\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d18\/511\/141\/d18511141431701b4c7ef783de2787d5.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c Starter Assets, \u044d\u0442\u043e\u0442 \u0430\u0441\u0441\u0435\u0442 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0438 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0441\u0446\u0435\u043d\u044b, \u0442\u0430\u043c \u0435\u0441\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u043f\u0440\u0435\u0444\u0430\u0431\u044b \u0438 DemoScene \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u0435\u0441\u0435\u0442\u044b \u0438\u0437 XR Interaction Toolkit \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u0439\u0434\u0435\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e Samples \u2192  XR Interaction Toolkit \u2192 2.2.0 \u2192 Starter Assets \u0438 \u0443\u0432\u0438\u0434\u0438\u043c \u0442\u0430\u043c 8 \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u0440\u0435\u0441\u0435\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f Scene, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0438\u0445 \u0432\u0441\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0435\u0441\u0435\u0442\u044b:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/12e\/be7\/d02\/12ebe7d029b22c53f8a3509365a6516e.png\" width=\"794\" height=\"821\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/12e\/be7\/d02\/12ebe7d029b22c53f8a3509365a6516e.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0441\u0446\u0435\u043d\u0443-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Panel Ground. \u0412 \u043d\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Teleportation Area, \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441 \u0446\u0432\u0435\u0442\u043e\u043c \u043d\u0430 \u043d\u0430\u0448 \u043f\u043e\u043b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/933\/120\/e5d\/933120e5df605e5c5bfdecd5e3c36132.png\" alt=\"\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Interaction Manager \u2192 Add Input Action Manager \u2192 XRI Default Input Actions:\" title=\"\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Interaction Manager \u2192 Add Input Action Manager \u2192 XRI Default Input Actions:\" width=\"756\" height=\"458\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/933\/120\/e5d\/933120e5df605e5c5bfdecd5e3c36132.png\"\/><\/p>\n<div><figcaption>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Interaction Manager \u2192 Add Input Action Manager \u2192 XRI Default Input Actions:<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/127\/c7d\/60e\/127c7d60ea53b0c9aa1a1dd27e8f572a.png\" alt=\"\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Origin:\" title=\"\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Origin:\" width=\"749\" height=\"491\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/127\/c7d\/60e\/127c7d60ea53b0c9aa1a1dd27e8f572a.png\"\/><\/p>\n<div><figcaption>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c XR Origin:<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c 2 Empty \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0434\u043b\u044f \u043f\u0440\u0435\u0444\u0430\u0431\u043e\u0432 \u043b\u0435\u0432\u043e\u0433\u043e \u0438 \u043f\u0440\u0430\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u043d\u0430 180 \u043f\u043e \u00abY\u00bb, \u0438 \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0435\u0444\u0430\u0431 \u043c\u043e\u0434\u0435\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0438\u0437 Samples.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/572\/069\/f3a\/572069f3a6225e0208cae23bc70a616f.png\" alt=\"\u041a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b:\" title=\"\u041a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b:\" width=\"756\" height=\"470\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/572\/069\/f3a\/572069f3a6225e0208cae23bc70a616f.png\"\/><\/p>\n<div><figcaption>\u041a\u0430\u0436\u0434\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b:<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c Quest2 \u043f\u043e USB \u043a \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u0441\u044f \u043a Oculus Link. \u0422\u0435\u043f\u0435\u0440\u044c \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432 Unity \u043f\u0440\u043e\u0435\u043a\u0442 (Play) \u043f\u043e \u0438\u0434\u0435\u0435 \u0432\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442\u0435 \u0432 \u043d\u0430\u0448\u0443 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u0443\u044e \u0441\u0446\u0435\u043d\u0443, \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u043e\u0439 \u0432 \u043e\u043a\u0443\u043b\u0443\u0441\u0435, \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e ground, \u0432\u0438\u0434\u0435\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0441 \u043a\u0440\u0430\u0441\u043d\u044b\u043c\u0438 \u043b\u0430\u0437\u0435\u0440\u0430\u043c\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/26c\/1cf\/b03\/26c1cfb03c7b9806f0e614fd1b196a9e.png\" width=\"642\" height=\"332\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/26c\/1cf\/b03\/26c1cfb03c7b9806f0e614fd1b196a9e.png\"\/><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c\u0441\u044f \u0441 Unity XR, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0432\u0438\u0434\u0435\u043e \u0442\u0443\u0442(<a href=\"https:\/\/www.youtube.com\/watch?v=yxMzAw2Sg5w\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a>).<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430, \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0441 \u043f\u043e\u0434\u0432\u0435\u0441\u043e\u043c \u043a\u0430\u043c\u0435\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0437 \u0432\u0435\u0431.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 (RPI-\u0445\u043e\u0441\u0442\u0430).<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 (VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f).<\/p>\n<\/li>\n<\/ol>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 2. \u0421\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Websocket<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u044e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438: <\/p>\n<ul>\n<li>\n<p>userId\/toUserId \u2013 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439(RPI-\u0445\u043e\u0441\u0442, VR-\u043a\u043b\u0438\u0435\u043d\u0442, \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442).  <\/p>\n<\/li>\n<li>\n<p>\u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f WebRTC\u2192 <strong><em>OFFER<\/em><\/strong>, <strong><em>ANSWER, ICE <\/em><\/strong> <\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0448\u0438 \u0442\u0438\u043f\u044b \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u2192 <strong><em>LOGIN, NEWMEMBER<\/em><\/strong><\/p>\n<\/li>\n<li>\n<p>data \u2013 \u0434\u043e\u043f. \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f UUID.<\/p>\n<\/li>\n<li>\n<p>payload \u2013 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0430\u043c\u0438 offer\/answer\/ice \u0438\u0437 WebRTC \u0432 \u0432\u0438\u0434\u0435 json.<\/p>\n<\/li>\n<\/ul>\n<h3>C\u0435\u0440\u0432\u0435\u0440 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e Websocket \u0441 WebRTC \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>SignalData.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Data public class SignalData {   private String userId;   private SignalType type;   private String data;   private JsonNode payload;   private String toUserId; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>SignalType.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum SignalType {   LOGIN,   USERID,   OFFER,   ANSWER,   ICE,   NEWMEMBER }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>SignalingConfiguration.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Configuration @EnableWebSocket public class SignalingConfiguration implements WebSocketConfigurer{   @Override   public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {     registry.addHandler(new SignalingHandler(), \"\/robopi_webrtc\");   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0438 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0441\u0430\u043c\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>SignalingHandler.java<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Slf4j public class SignalingHandler extends TextWebSocketHandler {   final ObjectMapper mapper = new ObjectMapper();   List&lt;WebSocketSession> sessions = new LinkedList&lt;WebSocketSession>();   ConcurrentHashMap&lt;String,WebSocketSession> sessionMap = new ConcurrentHashMap&lt;String,WebSocketSession>();      @Override   protected void handleTextMessage(WebSocketSession session,                                    TextMessage message) throws Exception {     mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);     final String msg = message.getPayload();     SignalData sigData = mapper.readValue(msg, SignalData.class);          if(sigData.getType().equals(SignalType.LOGIN)){       var sigResp = new SignalData();       var userId = UUID.randomUUID().toString();       sigResp.setUserId(\"SIGNALLING_SERVER\");       sigResp.setType(SignalType.USERID);       sigResp.setData(userId);       sessionMap.put(userId, session);       session.sendMessage(new TextMessage(mapper.writeValueAsString(sigResp)));       return ;     }     else if(sigData.getType().equals(SignalType.NEWMEMBER)) {       sessionMap.values().forEach(a -> {         var sigResp =new SignalData();         sigResp.setUserId(sigData.getUserId());         sigResp.setType(SignalType.NEWMEMBER);            try {             if(a.isOpen()) a.sendMessage(               new TextMessage(mapper.writeValueAsString(sigResp))             );           }           catch(Exception e) {             log.info(\"Error Sending message:\", e);           }       });       return ;     }     else if(sigData.getType().equals(SignalType.OFFER)) {       var sigResp = new SignalData();       sigResp.setUserId(sigData.getUserId());       sigResp.setType(SignalType.OFFER);       sigResp.setData(sigData.getData());       sigResp.setPayload(sigData.getPayload());       sigResp.setToUserId(sigData.getToUserId());       sessionMap.get(sigData.getToUserId()).sendMessage(         new TextMessage(mapper.writeValueAsString(sigResp))       );     }     else if(sigData.getType().equals(SignalType.ANSWER)) {       var sigResp = new SignalData();       sigResp.setUserId(sigData.getUserId());       sigResp.setType(SignalType.ANSWER);       sigResp.setData(sigData.getData());       sigResp.setPayload(sigData.getPayload());       sigResp.setToUserId(sigData.getToUserId());       sessionMap.get(sigData.getToUserId()).sendMessage(         new TextMessage(mapper.writeValueAsString(sigResp))       );     }     else if(sigData.getType().equals(SignalType.ICE)) {       var sigResp = new SignalData();       sigResp.setUserId(sigData.getUserId());       sigResp.setType(SignalType.ICE);       sigResp.setData(sigData.getData());       sigResp.setPayload(sigData.getPayload());       sigResp.setToUserId(sigData.getToUserId());       sessionMap.get(sigData.getToUserId()).sendMessage(         new TextMessage(mapper.writeValueAsString(sigResp))       );       }   }      @Override   public void afterConnectionEstablished(WebSocketSession session)      throws Exception {     sessions.add(session);     super.afterConnectionEstablished(session);   }      @Override   public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus)      throws Exception {     sessions.remove(session);     super.afterConnectionClosed(session, closeStatus);     }   }<\/code><\/pre>\n<p>PS \u2013 \u0432  \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u0443\u0447\u0448\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 websocket, \u044d\u0442\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442 \u0442\u0440\u0435\u0439\u0441 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u2013 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043d\u0430\u0448 main.html \u043d\u043e\u0432\u044b\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438: \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 websocket-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 UUID, \u0438 NEWMEMBER Info:<\/p>\n<details class=\"spoiler\">\n<summary>main.html<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"xml\">&lt;!DOCTYPE html> &lt;html xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" xmlns:th=\"http:\/\/www.thymeleaf.org\"> &lt;head>   &lt;meta charset=\"UTF-8\">   &lt;title>Robo WS+RTC:&lt;\/title>   &lt;link rel=\"icon\" href=\"data:;base64,iVBORw0KGgo=\">   &lt;!-- Head bootstrap as a fragment -->   &lt;div th:insert=\"~{fragments :: bootstraphead}\">&lt;\/div>   &lt;script src=\"\/robo.js\">&lt;\/script> &lt;\/head> &lt;body>   &lt;div id=\"main-content\" class=\"container\">     &lt;div class=\"row-md-6\">       &lt;label for=\"username\">User id:&lt;\/label>       &lt;span id=\"username\">unknown&lt;\/span>     &lt;\/div>     &lt;div class=\"row-md-6\">       &lt;form class=\"form-inline\">         &lt;div class=\"form-group\">           &lt;label for=\"connect\">WebSocket connection:&lt;\/label>           &lt;button id=\"connect\" class=\"btn btn-primary\" type=\"submit\">Connect&lt;\/button>           &lt;button id=\"disconnect\" class=\"btn btn-secondary\" type=\"submit\">Connect&lt;\/button>         &lt;\/div>       &lt;\/form>     &lt;\/div>     &lt;div class=\"row-md-6\">       &lt;form class=\"form-inline\">         &lt;button id=\"login\" class=\"btn btn-primary\" type=\"submit\">Login&lt;\/button>       &lt;\/form>     &lt;\/div>     &lt;div class=\"row-md-6\">       &lt;form class=\"form-inline\">         &lt;button id=\"newmember\" class=\"btn btn-primary\" type=\"submit\">New member info&lt;\/button>       &lt;\/form>     &lt;\/div>   &lt;\/div> &lt;\/body> &lt;\/html><\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442 robo.js \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>robo.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">var connection; var userId = 'unknown';  function connect(){   connection = new WebSocket('wss:\/\/' + window.location.host + '\/robopi_webrtc');   console.log(\"Connsection sucsess\");      connection.onmessage = function(msg) {     var resp = JSON.parse(msg.data);     if(resp.type == 'USERID'){       console.log();       userId = resp.data;       document.getElementById(\"username\").textContent = userId;     }     if(resp.type == 'NEWMEMBER'){       if(userId != resp.userId){         console.log(resp);       }     }     if(resp.type == 'OFFER'){       if(userId != resp.userId){         console.log(resp);       }     }     if(resp.type == 'ICE'){       if(userId != resp.userId){         console.log(resp);       }     }     if(resp.type == 'ANSWER'){       if(userId != resp.userId){         console.log(resp);       }     }   } }  function login() {   connection.send(JSON.stringify({'userId' : '', 'type' : 'LOGIN', 'data' : '' , 'toUserId' : ''})); }  function newmember() {   connection.send(JSON.stringify({'userId' : userId, 'type' : 'NEWMEMBER', 'data' : '' , 'toUserId' : ''})); }  $(function () {   $(\"form\").on('submit', function (e) {     e.preventDefault();   });  $( \"#connect\" ).click(function() { connect(); }); $( \"#login\" ).click(function() { login(); }); $( \"#newmember\" ).click(function() { newmember(); }); });<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 https:\/\/&lt;ip>:9000\/main c \u0440\u0430\u0437\u043d\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c:<\/p>\n<details class=\"spoiler\">\n<summary>\u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0442\u0430\u043a:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/195\/945\/724\/1959457246cc6d304e807960a474b1e8.png\" width=\"794\" height=\"344\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/195\/945\/724\/1959457246cc6d304e807960a474b1e8.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h3>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442(Python-\u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 RPI)<\/h3>\n<p>\u0412 Python \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <strong>websockets<\/strong>,<\/p>\n<p><code>pip3 install websockets<\/code><\/p>\n<p>\u0430 \u0442\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f <strong>asynco, ssl<\/strong> \u0438 <strong>json<\/strong> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>part1.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import asyncio import websockets import json import ssl from websockets import WebSocketClientProtocol   async def wsconsume(wsurl: str) -> None:     ssl_context = ssl.SSLContext()     async with websockets.connect(wsurl, ssl=ssl_context) as websocket:         await websocket.send(json.dumps({\"userId\": \"\", \"type\": \"LOGIN\", \"data\": \"\", \"payload\": \"\", \"toUserId\": \"\"}))         await wsconsumer_handler(websocket)   async def wsconsumer_handler(websocket: WebSocketClientProtocol) -> None:     local_user_id = \"\"          async for message in websocket:          msg = json.loads(message)          if msg.get(\"type\") == 'USERID' and local_user_id != msg.get(\"userId\"):             local_user_id = msg.get(\"data\")             print(\"SET UID: \" + local_user_id)             await websocket.send(json.dumps({\"userId\": local_user_id, \"type\": \"NEWMEMBER\", \"data\": \"\",                                              \"payload\": \"\", \"toUserId\": \"\"}))          if msg.get(\"type\") == 'OFFER' and local_user_id == msg.get(\"toUserId\"):             print(\"Handling offer: \" + str(msg.get(\"payload\")))           if msg.get(\"type\") == 'ICE' and local_user_id == msg.get(\"toUserId\"):             print(\"ICE INCOMING\")          if msg.get(\"type\") == 'ANSWER' and local_user_id == msg.get(\"toUserId\"):             print(\"ANSWER INCOMING\")   async def main():     task = asyncio.create_task(wsconsume('wss:\/\/192.168.10.146:9000\/robopi_webrtc'))     await task   if __name__ == '__main__':     loop = asyncio.get_event_loop()     try:         loop.run_until_complete(main())     except KeyboardInterrupt:         loop.stop()         pass<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u0438 \u0438\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0438\u0437 RPI \u0438 \u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c NEWMEMBER \u0438\u043d\u0444\u043e \u043c\u0435\u0436\u0434\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u0438 Python, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u043b\u043e\u0433\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c4e\/80c\/b81\/c4e80cb812f694b6f85069515cc1b0a4.png\" alt=\"RPI \u0441\u0442\u043e\u0440\u043e\u043d\u0430\" title=\"RPI \u0441\u0442\u043e\u0440\u043e\u043d\u0430\" width=\"434\" height=\"161\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c4e\/80c\/b81\/c4e80cb812f694b6f85069515cc1b0a4.png\"\/><\/p>\n<div><figcaption>RPI \u0441\u0442\u043e\u0440\u043e\u043d\u0430<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/43f\/5f8\/55a\/43f5f855aa23e49ffaf9c896259cb7de.png\" alt=\"\u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\" title=\"\u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\" width=\"794\" height=\"307\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/43f\/5f8\/55a\/43f5f855aa23e49ffaf9c896259cb7de.png\"\/><\/p>\n<div><figcaption>\u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b7b\/917\/8a7\/b7b9178a79dce630ab23bd9b0ad6d7f8.png\" alt=\"\u043b\u043e\u0433 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435\" title=\"\u043b\u043e\u0433 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435\" width=\"794\" height=\"175\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b7b\/917\/8a7\/b7b9178a79dce630ab23bd9b0ad6d7f8.png\"\/><\/p>\n<div><figcaption>\u043b\u043e\u0433 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/figcaption><\/div>\n<\/figure>\n<\/div>\n<\/details>\n<h2>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442(Unity VR)<\/h2>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u043e\u043c \u0438\u0437 Unity \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 WebSocketSharp, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043c <a href=\"https:\/\/github.com\/GlitchEnzo\/NuGetForUnity.git?path=\/src\/NuGetForUnity\" rel=\"noopener noreferrer nofollow\">NuGetForUnity<\/a>, \u0430 \u043f\u043e\u0442\u043e\u043c \u043e\u0442\u0442\u0443\u0434\u0430 \u0434\u0435\u043b\u0430\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 WebSocketSharp.<\/p>\n<details class=\"spoiler\">\n<summary>\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d06\/ba3\/13d\/d06ba313d37a1deb5fc3c00029788850.png\" width=\"616\" height=\"437\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d06\/ba3\/13d\/d06ba313d37a1deb5fc3c00029788850.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 UI: c\u043e\u0437\u0434\u0430\u0435\u043c Empty Object \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Connection Panel, \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b Rect Transform \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b Rect Transform \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/10d\/113\/e4e\/10d113e4ef3a9fdf57eaedf94d72d550.png\" width=\"296\" height=\"604\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/10d\/113\/e4e\/10d113e4ef3a9fdf57eaedf94d72d550.png\"\/><\/figure>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6e0\/971\/92a\/6e097192a0b6a4e5c09bb622d475f401.png\" width=\"297\" height=\"289\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6e0\/971\/92a\/6e097192a0b6a4e5c09bb622d475f401.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u0432 Connection Panel \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<details class=\"spoiler\">\n<summary>\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>Text   \u2192 \"WS Header\" Text   \u2192 \"UUID\" (\u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u044d\u0433 - \u00abuuid\u00bb) Button \u2192 \"Connect WS\" Button \u2192 \"Disonnect WS\" Button \u2192 \"Login\" Button \u2192 \"Newmember\" \u0422\u0430\u043a \u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c Empty \u043e\u0431\u044a\u0435\u043a\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0434\u043b\u044f \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u2192 \"Connection handler\"<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c04\/14e\/3e9\/c0414e3e91d1ec0ae3e71c91e5d6dd96.png\" width=\"718\" height=\"363\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c04\/14e\/3e9\/c0414e3e91d1ec0ae3e71c91e5d6dd96.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 C# \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u044f\u0434\u0440\u043e\u043c \u043d\u0430\u0448\u0438\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 websocket \u0438 webrtc:<\/p>\n<details class=\"spoiler\">\n<summary>Connection.cs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"cs\">using System; using System.Collections.Concurrent; using UnityEngine; using WebSocketSharp;  public class Connection : MonoBehaviour {      private GameObject uuid;     private WebSocket ws;     private ConcurrentQueue&lt;string> incomingWebsocketMessages;     private string userId = \"unknown\";      void Start()     {         uuid = GameObject.FindGameObjectWithTag(\"uuid\");         incomingWebsocketMessages = new ConcurrentQueue&lt;string>();          ws = new WebSocket(\"wss:\/\/192.168.10.146:9000\/robopi_webrtc\");         ws.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;          ws.OnOpen += (sender, e) =>         {             Debug.Log(\"OPEN WEBSOCKET\");         };          ws.OnMessage += (sender, e) =>         {             if (e.IsText)             {                 incomingWebsocketMessages.Enqueue(e.Data);                 Debug.Log(\"Incoming websocket message:\" + e.Data);             }         };          ws.OnClose += (sender, e) => {             Debug.Log(\"CLOSE WEBSOCKET:\" + e.Reason);         };     }      void Update()     {         if (incomingWebsocketMessages.TryDequeue(out var wsmessage))         {             var answer = JsonUtility.FromJson&lt;WSMessage&lt;string>>(wsmessage);              if (answer.type.Equals(\"USERID\") &amp;&amp; !answer.data.Equals(userId))             {                 userId = answer.data;                 SetUserId(userId);             }             else if (answer.type.Equals(\"NEWMEMBER\") &amp;&amp; !answer.userId.Equals(userId))             {              }             else if (answer.type.Equals(\"OFFER\") &amp;&amp; !answer.userId.Equals(userId))             {              }             else if (answer.type.Equals(\"ICE\") &amp;&amp; !answer.userId.Equals(userId))             {              }             else if (answer.type.Equals(\"ANSWER\") &amp;&amp; !answer.userId.Equals(userId))             {              }         }     }      public void ConnectWebsocket()     {         ws.Connect();     }      public void DisconnectWebsocket()     {         ws.Close();     }      public void LoginWebsocket()     {         var hello = new WSMessage&lt;string>         {             userId = \"\",             type = \"LOGIN\",             data = \"\",             payload = \"\",             toUserId = \"\"         };         ws.Send(JsonUtility.ToJson(hello));     }      public void SendNewmember()     {         var newmember = new WSMessage&lt;string>         {             userId = userId,             type = \"NEWMEMBER\",             data = \"\",             payload = \"\",             toUserId = \"\"         };          ws.Send(JsonUtility.ToJson(newmember));     }      void SetUserId(string userId)     {         uuid.GetComponent&lt;UnityEngine.UI.Text>().text = userId;     }  }  [Serializable] public class WSMessage&lt;T> {     public string userId;     public string type;     public string data;     public T payload;     public string toUserId; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0413\u043e\u0442\u043e\u0432\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0430\u0442\u0442\u0430\u0447\u0438\u043c \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 Connection handler, \u0430 \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 Button, \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u0442\u0430\u043a:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/054\/d42\/2e4\/054d422e4eece861d9ba2a5192d0c50d.png\" width=\"718\" height=\"478\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/054\/d42\/2e4\/054d422e4eece861d9ba2a5192d0c50d.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430\/\u043f\u0440\u0438\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439(+ \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 Debug console \u0432 Unity)!<\/p>\n<h4>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/h4>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c Unity \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u043f\u043e\u0442\u043e\u043c \u0438 \u0441 Python \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0442\u0435\u0441\u0442\u044b c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7e0\/41f\/1bc\/7e041f1bcbc91cd91c61256eff9c159b.png\" width=\"449\" height=\"224\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7e0\/41f\/1bc\/7e041f1bcbc91cd91c61256eff9c159b.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/767\/1c4\/933\/7671c49335ce06559fc7a56ccc06f241.png\" width=\"718\" height=\"166\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/767\/1c4\/933\/7671c49335ce06559fc7a56ccc06f241.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/217\/2a1\/404\/2172a1404ff81365b3b4ff47b1c11ab9.png\" width=\"794\" height=\"352\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/217\/2a1\/404\/2172a1404ff81365b3b4ff47b1c11ab9.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u0438\u0434\u0438\u043c \u043d\u0430 \u0432\u0441\u0435\u0445 3\u0445 \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u0445, \u0447\u0442\u043e \u043e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u043c\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0438 \u0427\u0430\u0441\u0442\u044c 2.<\/p>\n<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u2013 <a href=\"https:\/\/habr.com\/ru\/articles\/730450\/\" rel=\"noopener noreferrer nofollow\">\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u043e\u0431\u043e\u0442\u0430\u043c\u0438 \u0438\u0437 VR. \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 1<\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/730164\/\"> https:\/\/habr.com\/ru\/articles\/730164\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0417\u0430\u0434\u0430\u0447\u0430 \u0445\u043e\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f, \u043d\u043e \u043f\u043e \u043e\u0431\u044a\u0435\u043c\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u043d\u0435 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f. \u0420\u0430\u0437\u0431\u0438\u0442\u0430 \u043d\u0430 9 \u0447\u0430\u0441\u0442\u0435\u0439, 6 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b \u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u044b \u0432 3 \u0441\u0442\u0430\u0442\u044c\u0438. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043d\u0442\u0441\u043a\u0440\u0438\u043d\u043e\u0432 \u0438 \u043a\u0443\u0441\u043a\u043e\u0432 \u043a\u043e\u0434\u0430(\u0432\u0441\u0435 \u0443\u0431\u0440\u0430\u043d\u043e \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u044b). \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u043f\u0443\u0449\u0443 \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0434\u0435\u0442\u0430\u043b\u0438 \u2013 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0438\u0437\u0432\u0438\u043d\u044f\u044e\u0441\u044c, \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043b\u0438\u0447\u043a\u0443 \u0438\u043b\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0433 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u0430\u043a \u0441\u0430\u043c\u043e \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u0443\u043c\u0435\u044e\u0449\u0435\u0435\u0441\u044f \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043b\u0435\u0442\u0435\u043b\u043e \u0438\u0437 \u0433\u043e\u043b\u043e\u0432\u044b.<\/p>\n<p>\u0427\u0430\u0441\u0442\u0438 \u0438 \u0441\u0442\u0430\u0442\u0443\u0441\u044b \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438: <\/p>\n<ol>\n<li>\n<p><strong>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Websocket (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 WebRTC Connection + DataChannel (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 WebRTC Media streaming (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u043c\u0435\u0440\u043e\u0439 (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c (<em>\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u043d\u0430 ROS (<em>\u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0430\u0431\u043e\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 (<em>\u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435<\/em>).<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f (<em>\u043d\u0435 \u0432\u0437\u044f\u0442\u0430<\/em>).<\/strong><\/p>\n<\/li>\n<\/ol>\n<p>\u0410 \u0432\u043e\u0442 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043a \u043a\u043e\u043d\u0446\u0443 6 \u0447\u0430\u0441\u0442\u0438:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64492718cf7e13dfb3c342ed\" data-style=\"\" id=\"64492718cf7e13dfb3c342ed\" width=\"\"><\/div>\n<blockquote>\n<p><strong>Disclaimer 1.<\/strong><\/p>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0447\u0430\u0441\u0442\u043a\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0430 \u0443 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439, \u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u043a \u044d\u0442\u0438\u043c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c, \u0442\u0430\u043a \u043a\u0430\u043a: <\/p>\n<p>1. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u2013 \u044d\u0442\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Proof of Concept, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438\u0441\u044c, \u0434\u0430\u0431\u044b \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u044a\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<p>2. Unity\/C#\/Python \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435, \u0430 \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0432\u0435\u0449\u0430\u043c\u0438, \u043a\u0430\u043a \u0441 \u043a\u043e\u0440\u0443\u0442\u0438\u043d\u0430\u043c\u0438 \u0432 python \u0438 c#, \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u043b\u044e\u0434\u0430.<\/p>\n<p>3. \u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 4-\u043c\u044f \u042f\u041f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u044f\u0436\u043a\u043e \u0434\u043b\u044f \u043c\u043e\u0435\u0439 \u0441\u043a\u043e\u0440\u043e\u0432\u0430\u0440\u043a\u0438, \u043c\u043d\u0435 \u0438 \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u043b\u0430\u043a\u0430\u0442\u044c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043e\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u043d\u0430\u0434\u0435\u043b\u0430\u043b, \u043d\u043e \u0441 \u043a\u0430\u043a\u043e\u0433\u043e-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u044f \u0443\u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043c\u043e\u0433 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u043f\u0440\u043e\u0441\u0442\u0438\u0442\u0435.<\/p>\n<\/blockquote>\n<hr\/>\n<h2>\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f<\/h2>\n<p>\u041f\u0440\u043e\u0432\u0435\u0434\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0430\u0443\u0434\u0438\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u0438 \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438, \u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u0441 \u0440\u043e\u0431\u043e\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0440\u0443\u043a\u043e\u0439-\u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0439 \u043a RPI3B+, \u0438 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u043e\u043a\u0440\u0443\u0433 \u0438\u0434\u0435\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u043c \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u0438\u0437 VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0438, \u043d\u043e \u0438 \u0447\u0435\u0440\u0435\u0437 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442.<\/p>\n<p>\u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0432 \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043c\u0438\u043d\u0443\u0441 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043a\u043e\u043d\u0441\u043e\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 VR \u0438 \u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0435\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebRTC \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f P2P \u0442\u0440\u0430\u0444\u0438\u043a\u0430, \u0438 Websocket \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 WebRTC, \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043f\u043b\u044e\u0441 WebRTC \u2013 \u044d\u043b\u0435\u0433\u0430\u043d\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0440\u043e\u0445\u043e\u0434\u0430 \u0437\u0430 NAT \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e stun\/turn-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<p>\u0412 WebRTC \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 DataChannel, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u044b \u0438 MediaStreams \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432\u0438\u0434\u0435\u043e\/\u0430\u0443\u0434\u0438\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430, \u0447\u0442\u043e \u043c\u044b \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 USB-\u043a\u0430\u043c\u0435\u0440\u044b \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>Websocket \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 WebRTC-\u043f\u0438\u0440\u0430\u043c\u0438, \u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 REST \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u043d\u043e \u043c\u0438\u043d\u0443\u0441 REST \u2013 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0440\u043e\u0441\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u0422.\u0435. \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u0443, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0436\u0434\u0430\u0442\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u043e\u043f\u0440\u043e\u0441\u0430 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c WebRTC.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0438\u0437 3-\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u2013 <strong>\u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/strong> \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c WebRTC, <strong>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 (RPI-\u0445\u043e\u0441\u0442)<\/strong> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u043e\u0432 \u0438 \u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a, \u0438 <strong>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442(VR-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435)<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a, \u0438 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440\u043e\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 RPI-\u0445\u043e\u0441\u0442. \u0422\u0430\u043a \u0436\u0435, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e HTML\/JS, \u043e\u043d \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432 \u043f\u043e\u044d\u0442\u0430\u043f\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0435.<\/p>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SpringBoot, \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043d\u0430 RPI \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 Python, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Unity XR, \u0442\u0430\u043a \u0436\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 \u0432\u0435\u0431 \u2013 html-bootstrap-js-jquery.<\/p>\n<blockquote>\n<p><strong>Disclaimer 2<\/strong><\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u0432\u0441\u0435 \u0447\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0431\u043e\u0442\u043e\u0442\u0435\u0445\u043d\u0438\u043a\u0438 \u043d\u0443\u0436\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c ROS \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043d\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0443 \u043f\u043e\u043f\u0440\u043e\u0449\u0435, \u0430 \u0443\u0436\u0435 \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043d\u0430 ROS. \u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u2013 \u0432\u0441\u0435 \u043f\u043e\u0437\u043d\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438.<\/p>\n<\/blockquote>\n<p><strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/strong><\/p>\n<ul>\n<li>\n<p>VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438, \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Oculus Quest 2.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0431\u0435\u043b\u044c USB Type-C 1-2\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u044b \u043a Unity \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>Raspberry Pi 3B+ \u0441 \u0411\u041f.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0442\u0430 PCA9685, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f, \u043e\u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f I2C \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0441 RPI \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c 16-\u044e \u0428\u0418\u041c \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0440\u043e\u043d\u0448\u0442\u0435\u0439\u043d-\u043f\u043e\u0434\u0432\u0435\u0441 \u0434\u043b\u044f SG90 \u0438 2 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u0430 SG90, \u0434\u043b\u044f \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0432\u0435\u0441\u0430 \u043a\u0430\u043c\u0435\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>USB-\u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u0430, \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438 \u0432\u0438\u0434\u0435\u043e \u0432 VR.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440(6Dof Arm MG996R\/YF-6125MG \u0443 \u043c\u0435\u043d\u044f <a href=\"https:\/\/aliexpress.ru\/item\/32844805357.html?sku_id=10000014000036636\" rel=\"noopener noreferrer nofollow\">\u0442\u0430\u043a\u043e\u0439<\/a>), \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0442\u043e\u0442 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0437 VR.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u043e\u0434\u043e\u0432 \u041c\u0430\u043c\u0430-\u041f\u0430\u043f\u0430(40\u0441\u043c.). \u0423 \u043c\u043e\u0438\u0445 \u0441\u0435\u0440\u0432\u043e\u043f\u0440\u0438\u0432\u043e\u0434\u043e\u0432 \u0441\u0442\u043e\u043a\u043e\u0432\u044b\u0435 \u043a\u0430\u0431\u0435\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u0438 \u0438 \u0438\u0445 \u043d\u0435 \u0434\u043e\u0442\u044f\u043d\u0443\u0442\u044c \u0434\u043e \u043f\u043b\u0430\u0442\u044b PCA9685.<\/p>\n<\/li>\n<li>\n<p>\u0411\u043b\u043e\u043a \u043f\u0438\u0442\u0430\u043d\u0438\u044f 220V \u2013 5V. \u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 (\u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440, RPI, \u0411\u041f, \u043f\u043e\u0434\u0432\u0435\u0441 \u0434\u043b\u044f \u043a\u0430\u043c\u0435\u0440\u044b), \u0443 \u043c\u0435\u043d\u044f \u044d\u0442\u043e \u043b\u0438\u0448\u043d\u044f\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u043b\u0430\u0441\u0442\u0438\u043a\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u043b\u043b\u0430\u0436\u0430, \u043a\u0443\u0434\u0430 \u0441\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>(\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e) \u0420\u043e\u0443\u0442\u0435\u0440 \u043d\u0430 OWRT, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043f\u043e RTT\/Jitter.<\/p>\n<\/li>\n<li>\n<p>(\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e) \u0411\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u043f\u0440\u044f\u043c\u044b\u0435 \u0440\u0443\u043a\u0438, \u043d\u043e \u0438 \u0441 &#171;\u043d\u0435 \u043e\u0447\u0435\u043d\u044c&#187; \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0422\u0440\u0435\u0431\u0443\u0435\u043c\u0430\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u0430:<\/strong><\/p>\n<ul>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Linux.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Python.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Java \u0438 SpringBoot.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Unity \u0438 C#.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e HTML\/Bootstrap\/JS\/JQuery.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f \u043f\u043e Websocket \u0438 WebRTC.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/strong> \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043f\u043e\u0434 Win10, \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044f\u0441\u044c \u043d\u0430 Ubuntu WSL \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 RPI. \u041d\u0430 Win10 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b:<\/p>\n<ul>\n<li>\n<p>Eclipse IDE, \u0434\u043b\u044f SpringBoot.<\/p>\n<\/li>\n<li>\n<p>Unity + MS Visual Studio, \u0434\u043b\u044f VR \u0447\u0430\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>Oculus Client, \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f Oculus Link.(\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u044b ADB \u0434\u043b\u044f Oculus, \u043d\u043e \u0443 \u043c\u0435\u043d\u044f \u043e\u043d\u0438 \u0443\u0436\u0435 \u0431\u044b\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u0440\u0430\u043d\u0435\u0435).<\/p>\n<\/li>\n<\/ul>\n<h3>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u2013 \u043f\u043e\u0434\u0432\u0435\u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u0441 SG90 \u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0435\u0433\u043e \u0441 \u043f\u043b\u0430\u0442\u043e\u0439 PCA9685(\u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b \u0441\u0432\u043e\u044e USB-\u043a\u0430\u043c\u0435\u0440\u0443, \u0442.\u043a. \u043a\u043e\u0440\u043f\u0443\u0441 \u0431\u044b\u043b \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u0439).<\/p>\n<p>\u0412 \u043f\u043b\u0430\u0442\u0443 PCA9685 \u0441\u0435\u0440\u0432\u044b SG90 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432 \u043f\u043e\u0440\u0442\u044b 0 \u0438 1. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u0440\u043e\u0442\u0430\u0446\u0438\u044e \u043a\u0430\u043c\u0435\u0440\u044b \u043f\u043e \u043e\u0441\u044f\u043c(\u043f\u043e\u0432\u043e\u0440\u043e\u0442 \u0433\u043e\u043b\u043e\u0432\u044b \u0432 VR-\u0433\u0430\u0440\u043d\u0438\u0442\u0443\u0440\u0435). \u0414\u0430\u043b\u0435\u0435 \u0434\u0435\u043b\u0430\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u043a\u0430\u043c\u0435\u0440\u044b \u043d\u0430 \u043a\u0440\u043e\u043d\u0448\u0442\u0435\u0439\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u0430 \u043c\u0435\u0441\u0442\u043e\u043c, \u0433\u0434\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0442\u043e\u0440. \u041a\u0430\u0431\u0435\u043b\u0438 \u043e\u0442 \u0440\u0430\u0437\u044a\u0435\u043c\u043e\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0430 \u0443\u0434\u043b\u0438\u043d\u044f\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043a\u0430\u0431\u0435\u043b\u0435\u0439 \u00ab\u041f\u0430\u043f\u0430-\u041c\u0430\u043c\u0430\u00bb.<\/p>\n<details class=\"spoiler\">\n<summary>\u043f\u043e\u0434\u0432\u0435\u0441:<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043f\u043b\u0430\u0442\u044b PCA9685 \u0438 RPI3B+:<\/p>\n<pre><code> GND - Pin-6  SCL - GPIO-3(Pin5)  SDA - GPIO-2(Pin3)  VCC - Pin1  V+  - Pin4<\/code><\/pre>\n<p>\u041f\u0438\u0442\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0438\u0434\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043b\u0435\u043c\u043c\u0443 \u043d\u0430 PCA9685, \u043d\u043e \u0434\u043e 6 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e 2 \u0441\u0435\u0440\u0432\u043e SG90 \u0438 \u0431\u0440\u0430\u0442\u044c \u043f\u0438\u0442\u0430\u043d\u0438\u0435 \u0441 RPI \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.  <\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a RPI \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b RPI \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 (Pin 39-40) (\u043a\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u043c\u0438\u0433\u0430\u043d\u0438\u044f \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434\u043e\u043c).<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c RPI, \u0437\u0430\u043b\u0438\u0432\u0430\u0435\u043c \u041e\u0421 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e RPI Imager(RPI OS Light x64). \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0437\u0430\u043b\u0438\u0432\u043a\u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0430\u043f\u0434\u0435\u0439\u0442\/\u0430\u043f\u0433\u0440\u0435\u0439\u0434 apt \u0438 \u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b(ssh-\u043a\u043b\u044e\u0447\u0438, samba \u0438 \u0442.\u0434.). <\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c I2C \u0432 RPI \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043f\u0430\u043a\u0435\u0442 \u043f\u0430\u043a\u0435\u0442 \u0441 i2c-tools:<\/p>\n<p> <code>sudo apt install i2c-tools -y<\/code><\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 raspi \u043a\u043e\u043d\u0444\u0438\u0433 \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 I2C:<\/p>\n<p> <code>sudo raspi-config<\/code><\/p>\n<p> <code>Interface Options \u2192 &lt;Enable I2C><\/code><\/p>\n<p> <code>reboot<\/code><\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c I2C:<\/p>\n<p><code>i2cdetect -y 1<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u0414\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0435:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 00:                         -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: 70 -- -- -- -- -- -- \u2013<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u0432\u0441\u0435 \u043d\u043e\u0440\u043c \u0438 \u043f\u043b\u0430\u0442\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0430.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0440\u0432\u043e \u0447\u0435\u0440\u0435\u0437 PCA9685 \u0438\u0437 Python \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f pip3-\u043f\u0430\u043a\u0435\u0442\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0442\u0430\u0432\u0438\u043c pip3:<\/p>\n<p><code>sudo apt-get install python3-pip<\/code><\/p>\n<p> \u0418 \u0441\u0442\u0430\u0432\u0438\u043c \u0441\u0430\u043c\u0438 \u043f\u0430\u043a\u0435\u0442\u044b:<\/p>\n<p><code>pip3 install adafruit-circuitpython-pca9685<\/code><\/p>\n<p><code>pip3 install adafruit-circuitpython-motorkit<\/code><\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043f\u043b\u043e\u0445\u043e\u0439 \u0442\u043e\u043d, \u043d\u043e \u0442\u0443\u0442 \u043c\u044b \u0441\u0440\u0435\u0436\u0435\u043c \u0443\u0433\u043b\u044b, \u0442.\u00a0\u043a. \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430 ROS.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u043c:<\/p>\n<p><code>nano \/home\/pi3\/shared\/testpi3b\/part0.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>part0.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import RPi.GPIO as GPIO import time import busio from board import SCL, SDA from adafruit_motor import servo from adafruit_pca9685 import PCA9685  GPIO.setmode(GPIO.BCM) GPIO.setup(21, GPIO.OUT) i2c = busio.I2C(SCL, SDA) pca = PCA9685(i2c) pca.frequency = 50 servoX = servo.Servo(pca.channels[0], min_pulse=500, max_pulse=2400)      print(\"Simple testing\")  try:     for i in range(3):         print(\"Blink\")         GPIO.output(21,True)         servoX.angle = 0         time.sleep(1)         GPIO.output(21,False)         servoX.angle = 180         time.sleep(1) except KeyboardInterrupt:     GPIO.cleanup()  print(\"Test done\") GPIO.cleanup()<\/code><\/pre>\n<p>PS: \u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u0435\u0440\u0432\u043e \u043f\u043e \u0428\u0418\u041c \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0447\u0430\u0441\u0438\u043a \u043d\u0430 \u0447\u0442\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043f\u043e \u0442\u0435\u043c\u0435.<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e &#8212; \u0442\u043e \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434 \u043c\u043e\u0440\u0433\u043d\u0435\u0442 3 \u0440\u0430\u0437\u0430 \u0438 \u0441\u0435\u0440\u0432\u043e\u043c\u043e\u0442\u043e\u0440 \u0432 0-\u043f\u043e\u0440\u0442\u0443 PCA9685 3 \u0440\u0430\u0437\u0430 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u043e\u0432\u043e\u0440\u043e\u0442 0-180 \u0433\u0440\u0430\u0434\u0443\u0441\u043e\u0432. \u041f\u043e \u0434\u0435\u0442\u0430\u043b\u044f\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0438\u0437 Python \u0441 PCA9685 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/learn.adafruit.com\/16-channel-pwm-servo-driver\/overview\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>, \u0441 Rpi.GPIO <a href=\"https:\/\/pypi.org\/project\/RPi.GPIO\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>. \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441 RPI-\u0445\u043e\u0441\u0442\u043e\u043c \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u0430.<\/p>\n<h3>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/h3>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0443\u043d\u043a\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 SSL \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b websocket-over-ssl (\u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 SSL, \u043d\u043e \u043c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0440\u0430\u0437\u0443 \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435).<\/p>\n<p>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0441\u0430\u043c\u043e\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442(\u044f \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u044e \u0438\u0437 \u043f\u043e\u0434 WSL Ubuntu 20):<\/p>\n<p><code>sudo openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout .\/ssl\/ssl-selfsigned.key -out .\/ssl\/ssl-selfsigned.crt<\/code><\/p>\n<p> &#8230; \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u043d\u0430 \u0432\u0441\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c IP-\u0445\u043e\u0441\u0442\u0430 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043a\u0440\u0443\u0442\u0438\u0442\u044c\u0441\u044f \u0441\u0435\u0440\u0432\u0435\u0440. \u0418 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 PKS#12:<\/p>\n<p><code>openssl pkcs12 -export -in .\/ssl\/ssl-selfsigned.crt -inkey .\/ssl\/ssl-selfsigned.key -out .\/ssl\/ssl-selfsigned.p12<\/code><\/p>\n<p>\u0424\u0430\u0439\u043b\u044b \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0430 Win10, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u043d\u0430 Win10.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u0435\u043b\u0430\u0435\u043c<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-386023","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/386023","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=386023"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/386023\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=386023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=386023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=386023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}