From 8e2574102570b9fca95b4e264fb8de7cf4ac40c1 Mon Sep 17 00:00:00 2001 From: Hemal Shah Date: Wed, 11 Aug 2021 11:50:27 -0700 Subject: [PATCH] Isaac ROS v0.9.0 (EA1) --- .gitattributes | 16 + .gitignore | 2 + LICENSE | 130 ++++++++ README.md | 4 +- docker/Dockerfile.aarch64.base | 107 +++++++ docker/Dockerfile.x86_64.base | 141 +++++++++ docker/scripts/workspace-entrypoint.sh | 18 ++ .../vpi-dev-1.1.11-cuda11-x86_64-linux.deb | 3 + .../vpi-lib-1.1.11-cuda11-x86_64-linux.deb | 3 + giistr-cla.md | 58 ++++ isaac_ros_common/CMakeLists.txt | 49 +++ .../isaac_ros_common/vpi_utilities.hpp | 48 +++ isaac_ros_common/package.xml | 35 ++ isaac_ros_common/src/vpi_utilities.cpp | 84 +++++ isaac_ros_test/isaac_ros_test/__init__.py | 21 ++ isaac_ros_test/isaac_ros_test/cpu_profiler.py | 94 ++++++ .../isaac_ros_talker_comparison_test.py | 92 ++++++ .../examples/isaac_ros_talker_test.py | 67 ++++ .../isaac_ros_test/isaac_ros_base_test.py | 299 ++++++++++++++++++ .../isaac_ros_test/json_conversion.py | 197 ++++++++++++ isaac_ros_test/isaac_ros_test/profiler.py | 69 ++++ .../isaac_ros_test/tegrastats_profiler.py | 110 +++++++ isaac_ros_test/package.xml | 33 ++ isaac_ros_test/resource/isaac_ros_test | 0 isaac_ros_test/setup.cfg | 4 + isaac_ros_test/setup.py | 25 ++ isaac_ros_test/test/test_flake8.py | 25 ++ isaac_ros_test/test/test_pep257.py | 23 ++ scripts/README.md | 6 + scripts/run_dev.sh | 98 ++++++ scripts/utils/print_color.sh | 27 ++ 31 files changed, 1887 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 docker/Dockerfile.aarch64.base create mode 100644 docker/Dockerfile.x86_64.base create mode 100755 docker/scripts/workspace-entrypoint.sh create mode 100755 docker/vpi/vpi-dev-1.1.11-cuda11-x86_64-linux.deb create mode 100755 docker/vpi/vpi-lib-1.1.11-cuda11-x86_64-linux.deb create mode 100644 giistr-cla.md create mode 100644 isaac_ros_common/CMakeLists.txt create mode 100644 isaac_ros_common/include/isaac_ros_common/vpi_utilities.hpp create mode 100644 isaac_ros_common/package.xml create mode 100644 isaac_ros_common/src/vpi_utilities.cpp create mode 100644 isaac_ros_test/isaac_ros_test/__init__.py create mode 100644 isaac_ros_test/isaac_ros_test/cpu_profiler.py create mode 100644 isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_comparison_test.py create mode 100644 isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_test.py create mode 100644 isaac_ros_test/isaac_ros_test/isaac_ros_base_test.py create mode 100644 isaac_ros_test/isaac_ros_test/json_conversion.py create mode 100644 isaac_ros_test/isaac_ros_test/profiler.py create mode 100644 isaac_ros_test/isaac_ros_test/tegrastats_profiler.py create mode 100644 isaac_ros_test/package.xml create mode 100644 isaac_ros_test/resource/isaac_ros_test create mode 100644 isaac_ros_test/setup.cfg create mode 100644 isaac_ros_test/setup.py create mode 100644 isaac_ros_test/test/test_flake8.py create mode 100644 isaac_ros_test/test/test_pep257.py create mode 100644 scripts/README.md create mode 100755 scripts/run_dev.sh create mode 100644 scripts/utils/print_color.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..90698d5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,16 @@ +# Images +*.gif filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.psd filter=lfs diff=lfs merge=lfs -text + +# Archives +*.gz filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +# Documents +*.pdf filter=lfs diff=lfs merge=lfs -text +# Numpy data +*.npy filter=lfs diff=lfs merge=lfs -text +# Debian package +*.deb filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b793570 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore all pycache files +**/__pycache__/** diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bea32dc --- /dev/null +++ b/LICENSE @@ -0,0 +1,130 @@ +1. Copyright & License Notices + + +1.1. NVIDIA CORPORATION +1.1.1. NVIDIA SOFTWARE LICENSE AGREEMENT +IMPORTANT – READ BEFORE DOWNLOADING, INSTALLING, COPYING OR USING THE LICENSED SOFTWARE + +This Software License Agreement ("SLA”), made and entered into as of the time and date of click through action (“Effective Date”), is a legal agreement between you and NVIDIA Corporation ("NVIDIA") and governs the use of the NVIDIA computer software and the documentation made available for use with such NVIDIA software. By downloading, installing, copying, or otherwise using the NVIDIA software and/or documentation, you agree to be bound by the terms of this SLA. If you do not agree to the terms of this SLA, do not download, install, copy or use the NVIDIA software or documentation. IF YOU ARE ENTERING INTO THIS SLA ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU REPRESENT THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THE ENTITY TO THIS SLA, IN WHICH CASE “YOU” WILL MEAN THE ENTITY YOU REPRESENT. IF YOU DON’T HAVE SUCH AUTHORITY, OR IF YOU DON’T ACCEPT ALL THE TERMS AND CONDITIONS OF THIS SLA, THEN NVIDIA DOES NOT AGREE TO LICENSE THE LICENSED SOFTWARE TO YOU, AND YOU MAY NOT DOWNLOAD, INSTALL, COPY OR USE IT. + +1. LICENSE. + +1.1 License Grant. Subject to the terms of the AGREEMENT, NVIDIA hereby grants you a non-exclusive, non-transferable license, without the right to sublicense (except as expressly set forth in a Supplement), during the applicable license term unless earlier terminated as provided below, to have Authorized Users install and use the Software, including modifications (if expressly permitted in a Supplement), in accordance with the Documentation. You are only licensed to activate and use Licensed Software for which you a have a valid license, even if during the download or installation you are presented with other product options. No Orders are binding on NVIDIA until accepted by NVIDIA. Your Orders are subject to the AGREEMENT. + +SLA Supplements: Certain Licensed Software licensed under this SLA may be subject to additional terms and conditions that will be presented to you in a Supplement for acceptance prior to the delivery of such Licensed Software under this SLA and the applicable Supplement. Licensed Software will only be delivered to you upon your acceptance of all applicable terms. + +1.2 Limited Purpose Licenses. If your license is provided for one of the purposes indicated below, then notwithstanding contrary terms in Section 1.1 or in a Supplement, such licenses are for internal use and do not include any right or license to sub-license and distribute the Licensed Software or its output in any way in any public release, however limited, and/or in any manner that provides third parties with use of or access to the Licensed Software or its functionality or output, including (but not limited to) external alpha or beta testing or development phases. Further: + +(i) Evaluation License. You may use evaluation licenses solely for your internal evaluation of the Licensed Software for broader adoption within your Enterprise or in connection with a NVIDIA product purchase decision, and such licenses have an expiration date as indicated by NVIDIA in its sole discretion (or ninety days from the date of download if no other duration is indicated). + +(ii) Educational/Academic License. You may use educational/academic licenses solely for educational purposes and all users must be enrolled or employed by an academic institution. If you do not meet NVIDIA’s academic program requirements for educational institutions, you have no rights under this license. + +(iii) Test/Development License. You may use test/development licenses solely for your internal development, testing and/or debugging of your software applications or for interoperability testing with the Licensed Software, and such licenses have an expiration date as indicated by NVIDIA in its sole discretion (or one year from the date of download if no other duration is indicated). + +1.3 Pre-Release Licenses. With respect to alpha, beta, preview, and other pre-release Software and Documentation (“Pre-Release Licensed Software”) delivered to you under the AGREEMENT you acknowledge and agree that such Pre-Release Licensed Software (i) may not be fully functional, may contain errors or design flaws, and may have reduced or different security, privacy, accessibility, availability, and reliability standards relative to commercially provided NVIDIA software and documentation, and (ii) use of such Pre-Release Licensed Software may result in unexpected results, loss of data, project delays or other unpredictable damage or loss. THEREFORE, PRE-RELEASE LICENSED SOFTWARE IS NOT INTENDED FOR USE, AND SHOULD NOT BE USED, IN PRODUCTION OR BUSINESS-CRITICAL SYSTEMS. NVIDIA has no obligation to make available a commercial version of any Pre-Release Licensed Software and NVIDIA has the right to abandon development of Pre-Release Licensed Software at any time without liability. + +1.4 Enterprise and Contractor Usage. You may allow your Enterprise employees and Contractors to access and use the Licensed Software pursuant to the terms of the AGREEMENT solely to perform work on your behalf, provided further that with respect to Contractors: (i) you obtain a written agreement from each Contractor which contains terms and obligations with respect to access to and use of Licensed Software no less protective of NVIDIA than those set forth in the AGREEMENT, and (ii) such Contractor’s access and use expressly excludes any sublicensing or distribution rights for the Licensed Software. You are responsible for the compliance with the terms and conditions of the AGREEMENT by your Enterprise and Contractors. Any act or omission that, if committed by you, would constitute a breach of the AGREEMENT shall be deemed to constitute a breach of the AGREEMENT if committed by your Enterprise or Contractors. + +1.5 Services. Except as expressly indicated in an Order, NVIDIA is under no obligation to provide support for the Licensed Software or to provide any patches, maintenance, updates or upgrades under the AGREEMENT. Unless patches, maintenance, updates or upgrades are provided with their separate governing terms and conditions, they constitute Licensed Software licensed to you under the AGREEMENT. + +2. LIMITATIONS. + +2.1 License Restrictions. Except as expressly authorized in the AGREEMENT, you agree that you will not (nor authorize third parties to): (i) copy and use Software that was licensed to you for use in one or more NVIDIA hardware products in other unlicensed products (provided that copies solely for backup purposes are allowed); (ii) reverse engineer, decompile, disassemble (except to the extent applicable laws specifically require that such activities be permitted) or attempt to derive the source code, underlying ideas, algorithm or structure of Software provided to you in object code form; (iii) sell, transfer, assign, distribute, rent, loan, lease, sublicense or otherwise make available the Licensed Software or its functionality to third parties (a) as an application services provider or service bureau, (b) by operating hosted/virtual system environments, (c) by hosting, time sharing or providing any other type of services, or (d) otherwise by means of the internet; (iv) modify, translate or otherwise create any derivative works of any Licensed Software; (v) remove, alter, cover or obscure any proprietary notice that appears on or with the Licensed Software or any copies thereof; (vi) use the Licensed Software, or allow its use, transfer, transmission or export in violation of any applicable export control laws, rules or regulations; (vii) distribute, permit access to, or sublicense the Licensed Software as a stand-alone product; (viii) bypass, disable, circumvent or remove any form of copy protection, encryption, security or digital rights management or authentication mechanism used by NVIDIA in connection with the Licensed Software, or use the Licensed Software together with any authorization code, serial number, or other copy protection device not supplied by NVIDIA directly or through an authorized reseller; (ix) use the Licensed Software for the purpose of developing competing products or technologies or assisting a third party in such activities; (x) use the Licensed Software with any system or application where the use or failure of such system or application can reasonably be expected to threaten or result in personal injury, death, or catastrophic loss including, without limitation, use in connection with any nuclear, avionics, navigation, military, medical, life support or other life critical application (“Critical Applications”), unless the parties have entered into a Critical Applications agreement; (xi) distribute any modification or derivative work you make to the Licensed Software under or by reference to the same name as used by NVIDIA; or (xii) use the Licensed Software in any manner that would cause the Licensed Software to become subject to an Excluded License. Nothing in the AGREEMENT shall be construed to give you a right to use, or otherwise obtain access to, any source code from which the Software or any portion thereof is compiled or interpreted. You acknowledge that NVIDIA does not design, test, manufacture or certify the Licensed Software for use in the context of a Critical Application and NVIDIA shall not be liable to you or any third party, in whole or in part, for any claims or damages arising from such use. You agree to defend, indemnify and hold harmless NVIDIA and its Affiliates, and their respective employees, contractors, agents, officers and directors, from and against any and all claims, damages, obligations, losses, liabilities, costs or debt, fines, restitutions and expenses (including but not limited to attorney’s fees and costs incident to establishing the right of indemnification) arising out of or related to you and your Enterprise, and their respective employees, contractors, agents, distributors, resellers, end users, officers and directors use of Licensed Software outside of the scope of the AGREEMENT or any other breach of the terms of the AGREEMENT. + +2.2 Third Party License Obligations. The Licensed Software may come bundled with, or otherwise include or be distributed with, third party software licensed by an NVIDIA supplier and/or open source software provided under an open source license (collectively, “Third Party Software”). Notwithstanding anything to the contrary herein, Third Party Software is licensed to you subject to the terms and conditions of the software license agreement accompanying such Third Party Software whether in the form of a discrete agreement, click-through license, or electronic license terms accepted at the time of installation and any additional terms or agreements provided by the third party licensor (“Third Party License Terms”). Use of the Third Party Software by you shall be governed by such Third Party License Terms, or if no Third Party License Terms apply, then the Third Party Software is provided to you as-is, without support or warranty or indemnity obligations, for use in or with the Licensed Software and not otherwise used separately. Copyright to Third Party Software is held by the copyright holders indicated in the Third Party License Terms. + +Audio/Video Encoders and Decoders. You acknowledge and agree that it is your sole responsibility to obtain any additional third party licenses required to make, have made, use, have used, sell, import, and offer for sale your products or services that include or incorporate any Third Party Software and content relating to audio and/or video encoders and decoders from, including but not limited to, Microsoft, Thomson, Fraunhofer IIS, Sisvel S.p.A., MPEG-LA, and Coding Technologies as NVIDIA does not grant to you under the AGREEMENT any necessary patent or other rights with respect to audio and/or video encoders and decoders. + +2.3 Limited Rights. Your rights in the Licensed Software are limited to those expressly granted under the AGREEMENT and no other licenses are granted whether by implication, estoppel or otherwise. NVIDIA reserves all rights, title and interest in and to the Licensed Software not expressly granted under the AGREEMENT. + +3. CONFIDENTIALITY. Neither party will use the other party’s Confidential Information, except as necessary for the performance of the AGREEMENT, nor will either party disclose such Confidential Information to any third party, except to personnel of NVIDIA and its Affiliates, you, your Enterprise, your Enterprise Contractors, and each party’s legal and financial advisors that have a need to know such Confidential Information for the performance of the AGREEMENT, provided that each such personnel, employee and Contractors are subject to a written agreement that includes confidentiality obligations consistent with those set forth herein. Each party will use all reasonable efforts to maintain the confidentiality of all of the other party’s Confidential Information in its possession or control, but in no event less than the efforts that it ordinarily uses with respect to its own Confidential Information of similar nature and importance. The foregoing obligations will not restrict either party from disclosing the other party’s Confidential Information or the terms and conditions of the AGREEMENT as required under applicable securities regulations or pursuant to the order or requirement of a court, administrative agency, or other governmental body, provided that the party required to make such disclosure (i) gives reasonable notice to the other party to enable it to contest such order or requirement prior to its disclosure (whether through protective orders or otherwise), (ii) uses reasonable effort to obtain confidential treatment or similar protection to the fullest extent possible to avoid such public disclosure, and (iii) discloses only the minimum amount of information necessary to comply with such requirements. + +NVIDIA Confidential Information under the AGREEMENT includes output from Licensed Software developer tools identified as “Pro” versions, where the output reveals functionality or performance data pertinent to NVIDIA hardware or software products. + +4. OWNERSHIP. You are not obligated to disclose to NVIDIA any modifications that you, your Enterprise or your Contractors make to the Licensed Software as permitted under the AGREEMENT. As between the parties, all modifications are owned by NVIDIA and licensed to you under the AGREEMENT unless otherwise expressly provided in a Supplement. The Licensed Software and all modifications owned by NVIDIA, and the respective Intellectual Property Rights therein, are and will remain the sole and exclusive property of NVIDIA or its licensors. You shall not engage in any act or omission that would impair NVIDIA’s and/or its licensors’ Intellectual Property Rights in the Licensed Software or any other materials, information, processes or subject matter proprietary to NVIDIA. NVIDIA’s licensors are intended third party beneficiaries with the right to enforce provisions of the AGREEMENT with respect to their Confidential Information and/or Intellectual Property Rights. + +5. FEEDBACK. You may, but you are not obligated, to provide Feedback to NVIDIA. You hereby grant NVIDIA and its Affiliates a perpetual, non-exclusive, worldwide, irrevocable license to use, reproduce, modify, license, sublicense (through multiple tiers of sublicensees), distribute (through multiple tiers of distributors) and otherwise commercialize any Feedback that you voluntarily provide without the payment of any royalties or fees to you. NVIDIA has no obligation to respond to Feedback or to incorporate Feedback into the Licensed Software. + +6. NO WARRANTIES. THE LICENSED SOFTWARE AND ANY CONFIDENTIAL INFORMATION AND/OR SERVICES ARE PROVIDED BY NVIDIA “AS IS” AND “WITH ALL FAULTS,” AND NVIDIA AND ITS AFFILIATES EXPRESSLY DISCLAIM ALL WARRANTIES OF ANY KIND OR NATURE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF OPERABILITY, CONDITION, VALUE, ACCURACY OF DATA, OR QUALITY, AS WELL AS ANY WARRANTIES OF MERCHANTABILITY, SYSTEM INTEGRATION, WORKMANSHIP, SUITABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, OR THE ABSENCE OF ANY DEFECTS THEREIN, WHETHER LATENT OR PATENT. NO WARRANTY IS MADE ON THE BASIS OF TRADE USAGE, COURSE OF DEALING OR COURSE OF TRADE. WITHOUT LIMITING THE FOREGOING, NVIDIA AND ITS AFFILIATES DO NOT WARRANT THAT THE LICENSED SOFTWARE OR ANY CONFIDENTIAL INFORMATION AND/OR SERVICES PROVIDED UNDER THE AGREEMENT WILL MEET YOUR REQUIREMENTS OR THAT THE OPERATION THEREOF WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ALL ERRORS WILL BE CORRECTED. + +7. LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND ITS AFFILIATES SHALL NOT BE LIABLE FOR ANY SPECIAL, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, OR ANY LOST PROFITS, LOSS OF USE, LOSS OF DATA OR LOSS OF GOODWILL, OR THE COSTS OF PROCURING SUBSTITUTE PRODUCTS, ARISING OUT OF OR IN CONNECTION WITH THE AGREEMENT OR THE USE OR PERFORMANCE OF THE LICENSED SOFTWARE AND ANY CONFIDENTIAL INFORMATION AND/OR SERVICES PROVIDED UNDER THE AGREEMENT, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON BREACH OF CONTRACT, BREACH OF WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR ANY OTHER CAUSE OF ACTION OR THEORY OF LIABILITY. IN NO EVENT WILL NVIDIA’S AND ITS AFFILIATES TOTAL CUMULATIVE LIABILITY UNDER OR ARISING OUT OF THE AGREEMENT EXCEED THE NET AMOUNTS RECEIVED BY NVIDIA OR ITS AFFILIATES FOR YOUR USE OF THE PARTICULAR LICENSED SOFTWARE DURING THE TWELVE (12) MONTHS BEFORE THE LIABILITY AROSE (or up to US$10.00 if you acquired the Licensed Software for no charge). THE NATURE OF THE LIABILITY, THE NUMBER OF CLAIMS OR SUITS OR THE NUMBER OF PARTIES WITHIN YOUR ENTERPRISE THAT ACCEPTED THE TERMS OF THE AGREEMENT SHALL NOT ENLARGE OR EXTEND THIS LIMIT. THE FOREGOING LIMITATIONS SHALL APPLY REGARDLESS OF WHETHER NVIDIA, ITS AFFILIATES OR ITS LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES AND REGARDLESS OF WHETHER ANY REMEDY FAILS ITS ESSENTIAL PURPOSE. YOU ACKNOWLEDGE THAT NVIDIA’S OBLIGATIONS UNDER THE AGREEMENT ARE FOR THE BENEFIT OF YOU ONLY. The disclaimers, exclusions and limitations of liability set forth in the AGREEMENT form an essential basis of the bargain between the parties, and, absent any such disclaimers, exclusions or limitations of liability, the provisions of the AGREEMENT, including, without limitation, the economic terms, would be substantially different. + +8. TERM AND TERMINATION. + +8.1 AGREEMENT, Licenses and Services. This SLA shall become effective upon the Effective Date, each Supplement upon their acceptance, and both this SLA and Supplements shall continue in effect until your last access or use of the Licensed Software and/or services hereunder, unless earlier terminated as provided in this “Term and Termination” section. Each Licensed Software license ends at the earlier of (a) the expiration of the applicable license term, or (b) termination of such license or the AGREEMENT. Each service ends at the earlier of (x) the expiration of the applicable service term, (y) termination of such service or the AGREEMENT, or (z) expiration or termination of the associated license and no credit or refund will be provided upon the expiration or termination of the associated license for any service fees paid. + +8.2 Termination and Effect of Expiration or Termination. NVIDIA may terminate the AGREEMENT in whole or in part: (i) if you breach any term of the AGREEMENT and fail to cure such breach within thirty (30) days following notice thereof from NVIDIA (or immediately if you violate NVIDIA’s Intellectual Property Rights); (ii) if you become the subject of a voluntary or involuntary petition in bankruptcy or any proceeding relating to insolvency, receivership, liquidation or composition for the benefit of creditors, if that petition or proceeding is not dismissed with prejudice within sixty (60) days after filing, or if you cease to do business; or (iii) if you commence or participate in any legal proceeding against NVIDIA, with respect to the Licensed Software that is the subject of the proceeding during the pendency of such legal proceeding. If you or your authorized NVIDIA reseller fail to pay license fees or service fees when due then NVIDIA may, in its sole discretion, suspend or terminate your license grants, services and any other rights provided under the AGREEMENT for the affected Licensed Software, in addition to any other remedies NVIDIA may have at law or equity. Upon any expiration or termination of the AGREEMENT, a license or a service provided hereunder, (a) any amounts owed to NVIDIA become immediately due and payable, (b) you must promptly discontinue use of the affected Licensed Software and/or service, and (c) you must promptly destroy or return to NVIDIA all copies of the affected Licensed Software and all portions thereof in your possession or control, and each party will promptly destroy or return to the other all of the other party’s Confidential Information within its possession or control. Upon written request, you will certify in writing that you have complied with your obligations under this section. Upon expiration or termination of the AGREEMENT all provisions survive except for the license grant provisions. + +9. CONSENT TO COLLECTION AND USE OF INFORMATION. + +You hereby agree and acknowledge that the Software may access and collect data about your Enterprise computer systems as well as configures the systems in order to (a) properly optimize such systems for use with the Software, (b) deliver content through the Software, (c) improve NVIDIA products and services, and (d) deliver marketing communications. Data collected by the Software includes, but is not limited to, system (i) hardware configuration and ID, (ii) operating system and driver configuration, (iii) installed applications, (iv) applications settings, performance, and usage data, and (iv) usage metrics of the Software. To the extent that you use the Software, you hereby consent to all of the foregoing, and represent and warrant that you have the right to grant such consent. In addition, you agree that you are solely responsible for maintaining appropriate data backups and system restore points for your Enterprise systems, and that NVIDIA will have no responsibility for any damage or loss to such systems (including loss of data or access) arising from or relating to (a) any changes to the configuration, application settings, environment variables, registry, drivers, BIOS, or other attributes of the systems (or any part of such systems) initiated through the Software; or (b) installation of any Software or third party software patches initiated through the Software. In certain systems you may change your system update preferences by unchecking "Automatically check for updates" in the "Preferences" tab of the control panel for the Software. + +In connection with the receipt of the Licensed Software or services you may receive access to links to third party websites and services and the availability of those links does not imply any endorsement by NVIDIA. NVIDIA encourages you to review the privacy statements on those sites and services that you choose to visit so that you can understand how they may collect, use and share personal information of individuals. NVIDIA is not responsible or liable for: (i) the availability or accuracy of such links; or (ii) the products, services or information available on or through such links; or (iii) the privacy statements or practices of sites and services controlled by other companies or organizations. + +To the extent that you or members of your Enterprise provide to NVIDIA during registration or otherwise personal data, you acknowledge that such information will be collected, used and disclosed by NVIDIA in accordance with NVIDIA's privacy policy, available at URL http://www.nvidia.com/object/privacy_policy.html. + +10. GENERAL. + +This SLA, any Supplements incorporated hereto, and Orders constitute the entire agreement of the parties with respect to the subject matter hereto and supersede all prior negotiations, conversations, or discussions between the parties relating to the subject matter hereto, oral or written, and all past dealings or industry custom. Any additional and/or conflicting terms and conditions on purchase order(s) or any other documents issued by you are null, void, and invalid. Any amendment or waiver under the AGREEMENT must be in writing and signed by representatives of both parties. + +The AGREEMENT and the rights and obligations thereunder may not be assigned by you, in whole or in part, including by merger, consolidation, dissolution, operation of law, or any other manner, without written consent of NVIDIA, and any purported assignment in violation of this provision shall be void and of no effect. NVIDIA may assign, delegate or transfer the AGREEMENT and its rights and obligations hereunder, and if to a non-Affiliate you will be notified. + +Each party acknowledges and agrees that the other is an independent contractor in the performance of the AGREEMENT, and each party is solely responsible for all of its employees, agents, contractors, and labor costs and expenses arising in connection therewith. The parties are not partners, joint ventures or otherwise affiliated, and neither has any authority to make any statements, representations or commitments of any kind to bind the other party without prior written consent. + +Neither party will be responsible for any failure or delay in its performance under the AGREEMENT (except for any payment obligations) to the extent due to causes beyond its reasonable control for so long as such force majeure event continues in effect. + +The AGREEMENT will be governed by and construed under the laws of the State of Delaware and the United States without regard to the conflicts of law provisions thereof and without regard to the United Nations Convention on Contracts for the International Sale of Goods. The parties consent to the personal jurisdiction of the federal and state courts located in Santa Clara County, California. You acknowledge and agree that a breach of any of your promises or agreements contained in the AGREEMENT may result in irreparable and continuing injury to NVIDIA for which monetary damages may not be an adequate remedy and therefore NVIDIA is entitled to seek injunctive relief as well as such other and further relief as may be appropriate. If any court of competent jurisdiction determines that any provision of the AGREEMENT is illegal, invalid or unenforceable, the remaining provisions will remain in full force and effect. Unless otherwise specified, remedies are cumulative. + +The Licensed Software has been developed entirely at private expense and is “commercial items” consisting of “commercial computer software” and “commercial computer software documentation” provided with RESTRICTED RIGHTS. Use, duplication or disclosure by the U.S. Government or a U.S. Government subcontractor is subject to the restrictions set forth in the AGREEMENT pursuant to DFARS 227.7202-3(a) or as set forth in subparagraphs (c)(1) and (2) of the Commercial Computer Software - Restricted Rights clause at FAR 52.227-19, as applicable. Contractor/manufacturer is NVIDIA, 2788 San Tomas Expressway, Santa Clara, CA 95051. + +You acknowledge that the Licensed Software described under the AGREEMENT is subject to export control under the U.S. Export Administration Regulations (EAR) and economic sanctions regulations administered by the U.S. Department of Treasury’s Office of Foreign Assets Control (OFAC). Therefore, you may not export, reexport or transfer in-country the Licensed Software without first obtaining any license or other approval that may be required by BIS and/or OFAC. You are responsible for any violation of the U.S. or other applicable export control or economic sanctions laws, regulations and requirements related to the Licensed Software. By accepting this SLA, you confirm that you are not a resident or citizen of any country currently embargoed by the U.S. and that you are not otherwise prohibited from receiving the Licensed Software. + +Any notice delivered by NVIDIA to you under the AGREEMENT will be delivered via mail, email or fax. Please direct your legal notices or other correspondence to NVIDIA Corporation, 2788 San Tomas Expressway, Santa Clara, California 95051, United States of America, Attention: Legal Department. + +GLOSSARY OF TERMS + +Certain capitalized terms, if not otherwise defined elsewhere in this SLA, shall have the meanings set forth below: + +a. “Affiliate” means any legal entity that Owns, is Owned by, or is commonly Owned with a party. “Own” means having more than 50% ownership or the right to direct the management of the entity. + +b. “AGREEMENT” means this SLA and all associated Supplements entered by the parties referencing this SLA. + +c. “Authorized Users” means your Enterprise individual employees and any of your Enterprise’s Contractors, subject to the terms of the “Enterprise and Contractors Usage” section. + +d. “Confidential Information” means the Licensed Software (unless made publicly available by NVIDIA without confidentiality obligations), and any NVIDIA business, marketing, pricing, research and development, know-how, technical, scientific, financial status, proposed new products or other information disclosed by NVIDIA to you which, at the time of disclosure, is designated in writing as confidential or proprietary (or like written designation), or orally identified as confidential or proprietary or is otherwise reasonably identifiable by parties exercising reasonable business judgment, as confidential. Confidential Information does not and will not include information that: (i) is or becomes generally known to the public through no fault of or breach of the AGREEMENT by the receiving party; (ii) is rightfully known by the receiving party at the time of disclosure without an obligation of confidentiality; (iii) is independently developed by the receiving party without use of the disclosing party’s Confidential Information; or (iv) is rightfully obtained by the receiving party from a third party without restriction on use or disclosure. + +e. “Contractor” means an individual who works primarily for your Enterprise on a contractor basis from your secure network. + +f. “Documentation” means the NVIDIA documentation made available for use with the Software, including (without limitation) user manuals, datasheets, operations instructions, installation guides, release notes and other materials provided to you under the AGREEMENT. + +g. “Enterprise” means you or any company or legal entity for which you accepted the terms of this SLA, and their subsidiaries of which your company or legal entity owns more than fifty percent (50%) of the issued and outstanding equity. + +h. “Excluded License” includes, without limitation, a software license that requires as a condition of use, modification, and/or distribution that software be (i) disclosed or distributed in source code form; (ii) licensed for the purpose of making derivative works; or (iii) redistributable at no charge. + +i. “Feedback” means any and all suggestions, feature requests, comments or other feedback regarding the Licensed Software, including possible enhancements or modifications thereto. + +j. “Intellectual Property Rights” means all patent, copyright, trademark, trade secret, trade dress, trade names, utility models, mask work, moral rights, rights of attribution or integrity service marks, master recording and music publishing rights, performance rights, author’s rights, database rights, registered design rights and any applications for the protection or registration of these rights, or other intellectual or industrial property rights or proprietary rights, howsoever arising and in whatever media, whether now known or hereafter devised, whether or not registered, (including all claims and causes of action for infringement, misappropriation or violation and all rights in any registrations and renewals), worldwide and whether existing now or in the future. + +k. “Licensed Software” means Software, Documentation and all modifications owned by NVIDIA. + +l. “Order” means a purchase order issued by you, a signed purchase agreement with you, or other ordering document issued by you to NVIDIA or a NVIDIA authorized reseller (including any on-line acceptance process) that references and incorporates the AGREEMENT and is accepted by NVIDIA. + +m. “Software” means the NVIDIA software programs licensed to you under the AGREEMENT including, without limitation, libraries, sample code, utility programs and programming code. + +n. “Supplement” means the additional terms and conditions beyond those stated in this SLA that apply to certain Licensed Software licensed hereunder. + +Notices +Notice +THE INFORMATION IN THIS GUIDE AND ALL OTHER INFORMATION CONTAINED IN NVIDIA DOCUMENTATION REFERENCED IN THIS GUIDE IS PROVIDED “AS IS.” NVIDIA MAKES NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO THE INFORMATION FOR THE PRODUCT, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. Notwithstanding any damages that customer might incur for any reason whatsoever, NVIDIA’s aggregate and cumulative liability towards customer for the product described in this guide shall be limited in accordance with the NVIDIA terms and conditions of sale for the product. + +THE NVIDIA PRODUCT DESCRIBED IN THIS GUIDE IS NOT FAULT TOLERANT AND IS NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE IN CONNECTION WITH THE DESIGN, CONSTRUCTION, MAINTENANCE, AND/OR OPERATION OF ANY SYSTEM WHERE THE USE OR A FAILURE OF SUCH SYSTEM COULD RESULT IN A SITUATION THAT THREATENS THE SAFETY OF HUMAN LIFE OR SEVERE PHYSICAL HARM OR PROPERTY DAMAGE (INCLUDING, FOR EXAMPLE, USE IN CONNECTION WITH ANY NUCLEAR, AVIONICS, LIFE SUPPORT OR OTHER LIFE CRITICAL APPLICATION). NVIDIA EXPRESSLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR SUCH HIGH RISK USES. NVIDIA SHALL NOT BE LIABLE TO CUSTOMER OR ANY THIRD PARTY, IN WHOLE OR IN PART, FOR ANY CLAIMS OR DAMAGES ARISING FROM SUCH HIGH RISK USES. + +NVIDIA makes no representation or warranty that the product described in this guide will be suitable for any specified use without further testing or modification. Testing of all parameters of each product is not necessarily performed by NVIDIA. It is customer’s sole responsibility to ensure the product is suitable and fit for the application planned by customer and to do the necessary testing for the application in order to avoid a default of the application or the product. Weaknesses in customer’s product designs may affect the quality and reliability of the NVIDIA product and may result in additional or different conditions and/or requirements beyond those contained in this guide. NVIDIA does not accept any liability related to any default, damage, costs or problem which may be based on or attributable to: (i) the use of the NVIDIA product in any manner that is contrary to this guide, or (ii) customer product designs. + +Other than the right for customer to use the information in this guide with the product, no other license, either expressed or implied, is hereby granted by NVIDIA under this guide. Reproduction of information in this guide is permissible only if reproduction is approved by NVIDIA in writing, is reproduced without alteration, and is accompanied by all associated conditions, limitations, and notices. + +Trademarks +NVIDIA, the NVIDIA logo, and cuBLAS, CUDA, cuDNN, cuFFT, cuSPARSE, DIGITS, DGX, DGX-1, DGX Station, GRID, Jetson, Kepler, NGX, NVIDIA GPU Cloud, Maxwell, NCCL, NVLink, Pascal, Tegra, TensorRT, Tesla and Volta are trademarks and/or registered trademarks of NVIDIA Corporation in the Unites States and other countries. Other company and product names may be trademarks of the respective companies with which they are associated. + +Copyright +© 2021 NVIDIA Corporation. All rights reserved. \ No newline at end of file diff --git a/README.md b/README.md index 0108669..4dd680a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# JetROS Test +# Isaac ROS Common +Isaac ROS common utilities for use in conjunction with the Isaac ROS suite of packages. +Note: Please refer to `scripts/README.md` for script used to setup dev environment diff --git a/docker/Dockerfile.aarch64.base b/docker/Dockerfile.aarch64.base new file mode 100644 index 0000000..a80f243 --- /dev/null +++ b/docker/Dockerfile.aarch64.base @@ -0,0 +1,107 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +# Dockder file to aarch64 based Jetson device +ARG BASE_IMAGE=dustynv/ros:foxy-ros-base-l4t-r32.6.1 +FROM ${BASE_IMAGE} + +# Disable terminal interaction for apt +ENV DEBIAN_FRONTEND=noninteractive + +# Fundamentals +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + curl \ + git \ + sudo \ + unzip \ + vim \ + wget \ + software-properties-common \ +&& rm -rf /var/lib/apt/lists/* + +# Install OpenCV dependencies +RUN apt-get update && apt-get install -y \ + libavformat-dev \ + libjpeg-dev \ + libopenjp2-7-dev \ + libpng-dev \ + libpq-dev \ + libswscale-dev \ + libtbb2 \ + libtbb-dev \ + libtiff-dev \ + pkg-config \ + yasm \ +&& rm -rf /var/lib/apt/lists/* + +# Install additional packages needed for ROS2 dependencies +RUN apt-get update && apt-get install -y \ + python3-distutils \ + libboost-all-dev \ + libboost-dev \ +&& rm -rf /var/lib/apt/lists/* + +# sklearn dependencies +RUN apt-get update && apt-get install -y \ + gfortran \ + libatlas-base-dev \ + python3-scipy \ +&& rm -rf /var/lib/apt/lists/* + +# sklearn Python dependencies +RUN python3 -m pip install -U \ + Cython \ + wheel + +# Install sklearn +RUN python3 -m pip install -U \ + scikit-learn + +# Install Git-LFS +RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \ + apt-get update && apt-get install -y \ + git-lfs \ +&& rm -rf /var/lib/apt/lists/* + +# Install Realsense +RUN apt update \ + && apt-key adv --keyserver keys.gnupg.net --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE || apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE \ + && add-apt-repository -y "deb https://librealsense.intel.com/Debian/apt-repo bionic main" -u \ + && apt-get install -y librealsense2-utils librealsense2-dev + + +# Update environment +ENV LD_LIBRARY_PATH="/opt/nvidia/vpi1/lib64:${LD_LIBRARY_PATH}" +ENV LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu/tegra:${LD_LIBRARY_PATH}" +ENV LD_LIBRARY_PATH="/usr/local/cuda-10.2/targets/aarch64-linux/lib:${LD_LIBRARY_PATH}" +ENV LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu/tegra-egl:${LD_LIBRARY_PATH}" + +RUN echo "source /opt/ros/foxy/install/setup.bash" > /opt/ros/foxy/setup.bash + +# Restore using the default Foxy DDS middleware: FastRTPS +ENV RMW_IMPLEMENTATION=rmw_fastrtps_cpp + +### ----------------------------- + +# Setup non-root admin user +ARG USERNAME=admin +ARG USER_UID=1000 +ARG USER_GID=1001 + +# Create the 'admin' user +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && adduser admin video && adduser admin sudo + +COPY scripts/workspace-entrypoint.sh /home/$USERNAME/workspace-entrypoint.sh +RUN chmod +x /home/$USERNAME/workspace-entrypoint.sh + diff --git a/docker/Dockerfile.x86_64.base b/docker/Dockerfile.x86_64.base new file mode 100644 index 0000000..af14d2b --- /dev/null +++ b/docker/Dockerfile.x86_64.base @@ -0,0 +1,141 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. +# +# Docker file to build on x86_64 +ARG BASE_IMAGE=nvidia/cuda:11.2.0-devel-ubuntu20.04 +FROM ${BASE_IMAGE} + +# disable terminal interaction for apt +ENV DEBIAN_FRONTEND=noninteractive + +# Fundamentals +RUN apt-get update && apt-get install -y \ + bash-completion \ + build-essential \ + clang-format \ + cmake \ + curl \ + git \ + gnupg2 \ + locales \ + lsb-release \ + rsync \ + software-properties-common \ + wget \ + vim \ + mlocate \ +&& rm -rf /var/lib/apt/lists/* + +# Python basics +RUN apt-get update && apt-get install -y \ + python3-flake8 \ + python3-opencv \ + python3-pip \ + python3-pytest-cov \ + python3-setuptools \ +&& rm -rf /var/lib/apt/lists/* + +# Video utilities +RUN apt-get update && apt-get install -y \ + v4l-utils \ + mesa-utils \ + libcanberra-gtk-module \ + libcanberra-gtk3-module \ +&& rm -rf /var/lib/apt/lists/* + +# Core dev libraries +RUN apt-get update && apt-get install -y \ + libasio-dev \ + libbullet-dev \ + libtinyxml2-dev \ + libcunit1-dev \ +&& rm -rf /var/lib/apt/lists/* + +# Python3 (PIP) +RUN python3 -m pip install -U \ + argcomplete \ + autopep8 \ + flake8 \ + flake8-blind-except \ + flake8-builtins \ + flake8-class-newline \ + flake8-comprehensions \ + flake8-deprecated \ + flake8-docstrings \ + flake8-import-order \ + flake8-quotes \ + pytest-repeat \ + pytest-rerunfailures \ + pytest \ + pydocstyle \ + scikit-learn + +# Install Git-LFS +RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \ + apt-get update && apt-get install -y \ + git-lfs \ +&& rm -rf /var/lib/apt/lists/* + +# Install VPI packages +ARG HAS_GPU +COPY vpi/*.deb /opt/install/ +RUN if [ "$HAS_GPU" = "true" ]; then \ + dpkg -i /opt/install/vpi-lib-1.1.11-cuda11-x86_64-linux.deb; \ + dpkg -i /opt/install/vpi-dev-1.1.11-cuda11-x86_64-linux.deb; \ + updatedb; \ + fi + +# Setup ROS2 Foxy +RUN locale-gen en_US en_US.UTF-8 +RUN update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 + +RUN curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | apt-key add - +RUN sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list' + +RUN apt-get update && apt-get install -y \ + python3-colcon-common-extensions \ + python3-rosdep \ + python3-vcstool \ + ros-foxy-camera-calibration-parsers \ + ros-foxy-camera-info-manager \ + ros-foxy-desktop \ + ros-foxy-launch-testing-ament-cmake \ + ros-foxy-rqt* \ + ros-foxy-turtlesim \ + ros-foxy-v4l2-camera \ + ros-foxy-realsense2-camera \ +&& rm -rf /var/lib/apt/lists/* + +RUN rosdep init + +# Install Realsense +RUN apt update \ + && apt-key adv --keyserver keys.gnupg.net --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE \ + || apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE \ + && add-apt-repository -y "deb https://librealsense.intel.com/Debian/apt-repo bionic main" -u \ + && apt-get install -y librealsense2-utils librealsense2-dev + +# Restore using the default Foxy DDS middleware: FastRTPS +ENV RMW_IMPLEMENTATION=rmw_fastrtps_cpp + +# Setup non-root admin user +ARG USERNAME=admin +ARG USER_UID=1000 +ARG USER_GID=1001 + +# Create the 'admin' user +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && adduser admin video && adduser admin sudo + +COPY scripts/workspace-entrypoint.sh /home/$USERNAME/workspace-entrypoint.sh +RUN chmod +x /home/$USERNAME/workspace-entrypoint.sh + diff --git a/docker/scripts/workspace-entrypoint.sh b/docker/scripts/workspace-entrypoint.sh new file mode 100755 index 0000000..75d8592 --- /dev/null +++ b/docker/scripts/workspace-entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +# Build ROS dependency +echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc +source /opt/ros/foxy/setup.bash + +sudo apt-get update +rosdep update + +$@ diff --git a/docker/vpi/vpi-dev-1.1.11-cuda11-x86_64-linux.deb b/docker/vpi/vpi-dev-1.1.11-cuda11-x86_64-linux.deb new file mode 100755 index 0000000..30d0ced --- /dev/null +++ b/docker/vpi/vpi-dev-1.1.11-cuda11-x86_64-linux.deb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cc330dc311803789b573283beb212fe44b307d57ff63565bc570ffbf75a48a0d +size 55790 diff --git a/docker/vpi/vpi-lib-1.1.11-cuda11-x86_64-linux.deb b/docker/vpi/vpi-lib-1.1.11-cuda11-x86_64-linux.deb new file mode 100755 index 0000000..834bf90 --- /dev/null +++ b/docker/vpi/vpi-lib-1.1.11-cuda11-x86_64-linux.deb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2ff7114caa50d4a2fd31fb675f1d1c23e1e06d2dda4e1fd9921d126d5a89f66 +size 16271658 diff --git a/giistr-cla.md b/giistr-cla.md new file mode 100644 index 0000000..77e33bb --- /dev/null +++ b/giistr-cla.md @@ -0,0 +1,58 @@ +## Individual Contributor License Agreement (CLA) + +**Thank you for submitting your contributions to this project.** + +By signing this CLA, you agree that the following terms apply to all of your past, present and future contributions +to the project. + +### License. + +You hereby represent that all present, past and future contributions are governed by the +[MIT License](https://opensource.org/licenses/MIT) +copyright statement. + +This entails that to the extent possible under law, you transfer all copyright and related or neighboring rights +of the code or documents you contribute to the project itself or its maintainers. +Furthermore you also represent that you have the authority to perform the above waiver +with respect to the entirety of you contributions. + +### Moral Rights. + +To the fullest extent permitted under applicable law, you hereby waive, and agree not to +assert, all of your “moral rights” in or relating to your contributions for the benefit of the project. + +### Third Party Content. + +If your Contribution includes or is based on any source code, object code, bug fixes, configuration changes, tools, +specifications, documentation, data, materials, feedback, information or other works of authorship that were not +authored by you (“Third Party Content”) or if you are aware of any third party intellectual property or proprietary +rights associated with your Contribution (“Third Party Rights”), +then you agree to include with the submission of your Contribution full details respecting such Third Party +Content and Third Party Rights, including, without limitation, identification of which aspects of your +Contribution contain Third Party Content or are associated with Third Party Rights, the owner/author of the +Third Party Content and Third Party Rights, where you obtained the Third Party Content, and any applicable +third party license terms or restrictions respecting the Third Party Content and Third Party Rights. For greater +certainty, the foregoing obligations respecting the identification of Third Party Content and Third Party Rights +do not apply to any portion of a Project that is incorporated into your Contribution to that same Project. + +### Representations. + +You represent that, other than the Third Party Content and Third Party Rights identified by +you in accordance with this Agreement, you are the sole author of your Contributions and are legally entitled +to grant the foregoing licenses and waivers in respect of your Contributions. If your Contributions were +created in the course of your employment with your past or present employer(s), you represent that such +employer(s) has authorized you to make your Contributions on behalf of such employer(s) or such employer +(s) has waived all of their right, title or interest in or to your Contributions. + +### Disclaimer. + +To the fullest extent permitted under applicable law, your Contributions are provided on an "as is" +basis, without any warranties or conditions, express or implied, including, without limitation, any implied +warranties or conditions of non-infringement, merchantability or fitness for a particular purpose. You are not +required to provide support for your Contributions, except to the extent you desire to provide support. + +### No Obligation. + +You acknowledge that the maintainers of this project are under no obligation to use or incorporate your contributions +into the project. The decision to use or incorporate your contributions into the project will be made at the +sole discretion of the maintainers or their authorized delegates. \ No newline at end of file diff --git a/isaac_ros_common/CMakeLists.txt b/isaac_ros_common/CMakeLists.txt new file mode 100644 index 0000000..1dcfb78 --- /dev/null +++ b/isaac_ros_common/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +cmake_minimum_required(VERSION 3.5) +project(isaac_ros_common) + +# Default to C++17 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +find_package(ament_cmake_auto REQUIRED) +ament_auto_find_build_dependencies() + +# Find VPI dependency +find_package(vpi REQUIRED) + +ament_auto_add_library(${PROJECT_NAME} SHARED + src/vpi_utilities.cpp +) + +target_link_libraries(${PROJECT_NAME} vpi) + +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + + # Ignore copyright notices since we use custom JetPack EULA + set(ament_cmake_copyright_FOUND TRUE) + + ament_lint_auto_find_test_dependencies() + +endif() + +ament_auto_package() diff --git a/isaac_ros_common/include/isaac_ros_common/vpi_utilities.hpp b/isaac_ros_common/include/isaac_ros_common/vpi_utilities.hpp new file mode 100644 index 0000000..5cf8115 --- /dev/null +++ b/isaac_ros_common/include/isaac_ros_common/vpi_utilities.hpp @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +#ifndef ISAAC_ROS_COMMON__VPI_UTILITIES_HPP_ +#define ISAAC_ROS_COMMON__VPI_UTILITIES_HPP_ + +#include "rclcpp/rclcpp.hpp" +#include "vpi/VPI.h" + +// VPI status check macro +#define CHECK_STATUS(STMT) \ + do { \ + VPIStatus status = (STMT); \ + if (status != VPI_SUCCESS) { \ + char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \ + vpiGetLastStatusMessage(buffer, sizeof(buffer)); \ + std::ostringstream ss; \ + ss << vpiStatusGetName(status) << ": " << buffer; \ + throw std::runtime_error(ss.str()); \ + } \ + } while (0); + +namespace isaac_ros +{ +namespace common +{ + +/** + * @brief Declare and parse ROS2 parameter into VPI backend flags + * + * @param node The node to declare the parameter with + * @param default_backends The default backends to use if given invalid input + * @return uint32_t The resulting VPI backend flags + */ +uint32_t DeclareVPIBackendParameter(rclcpp::Node * node, uint32_t default_backends) noexcept; + +} // namespace common + +} // namespace isaac_ros + +#endif // ISAAC_ROS_COMMON__VPI_UTILITIES_HPP_ diff --git a/isaac_ros_common/package.xml b/isaac_ros_common/package.xml new file mode 100644 index 0000000..515a26e --- /dev/null +++ b/isaac_ros_common/package.xml @@ -0,0 +1,35 @@ + + + + + + + isaac_ros_common + 0.9.0 + Utilities for performing common functions in Isaac ROS packages + + Hemal Shah + JetPack EULA + https://developer.nvidia.com/blog/accelerating-ai-modules-for-ros-and-ros-2-on-jetson/ + Jaiveer Singh + + ament_cmake_auto + + rclcpp + vpi + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/isaac_ros_common/src/vpi_utilities.cpp b/isaac_ros_common/src/vpi_utilities.cpp new file mode 100644 index 0000000..f8e1e4f --- /dev/null +++ b/isaac_ros_common/src/vpi_utilities.cpp @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +#include "isaac_ros_common/vpi_utilities.hpp" + +#include +#include + +namespace isaac_ros +{ +namespace common +{ + +namespace +{ + +// Map from human-friendly backend string to VPI backend as uint32_t +const std::unordered_map g_str_to_vpi_backend({ + {"CPU", VPI_BACKEND_CPU}, + {"CUDA", VPI_BACKEND_CUDA}, + {"PVA", VPI_BACKEND_PVA}, + {"VIC", VPI_BACKEND_VIC}, + {"NVENC", VPI_BACKEND_NVENC}, + {"TEGRA", VPI_BACKEND_TEGRA}, + {"ALL", VPI_BACKEND_ALL}, + }); + +} // namespace + +uint32_t DeclareVPIBackendParameter(rclcpp::Node * node, uint32_t default_backends) noexcept +{ + const std::string DEFAULT_BACKENDS_STRING{""}; + const std::string backends_string{node->declare_parameter("backends", DEFAULT_BACKENDS_STRING)}; + + // If the ROS2 parameter is still at the default value, then return the default backend + if (backends_string == DEFAULT_BACKENDS_STRING) { + return default_backends; + } + + // Final backend to be returned after combining all requested backends + uint32_t backends{}; + + std::stringstream stream{backends_string}; + while (stream.good()) { + // Extract next backend delimited by commas + std::string backend_str; + std::getline(stream, backend_str, ','); + + // Search the map for the backend + auto backend_it{g_str_to_vpi_backend.find(backend_str)}; + if (backend_it != g_str_to_vpi_backend.end()) { + // If found, bitwise-or the backend to add it into the allowable backends + backends |= backend_it->second; + } else { + // Otherwise, log an error with all allowable backends + std::ostringstream os{}; + os << "Backend '" << backend_str << "' from requested backends '" << backends_string << + "' not recognized. Backend must be one of:" << + std::endl; + std::for_each( + g_str_to_vpi_backend.begin(), g_str_to_vpi_backend.end(), [&os](auto & entry) { + os << entry.first << std::endl; + }); + + RCLCPP_ERROR(node->get_logger(), os.str()); + + // Return default backends due to error + return default_backends; + } + } + + // Once all backends have been bitwise-or'ed together, return the result + return backends; +} + +} // namespace common +} // namespace isaac_ros diff --git a/isaac_ros_test/isaac_ros_test/__init__.py b/isaac_ros_test/isaac_ros_test/__init__.py new file mode 100644 index 0000000..922facf --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/__init__.py @@ -0,0 +1,21 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Imports for isaac_ros_test module.""" + +from .cpu_profiler import CPUProfiler +from .isaac_ros_base_test import IsaacROSBaseTest +from .json_conversion import JSONConversion +from .tegrastats_profiler import TegrastatsProfiler + +__all__ = [ + 'CPUProfiler', + 'IsaacROSBaseTest', + 'JSONConversion', + 'TegrastatsProfiler' +] diff --git a/isaac_ros_test/isaac_ros_test/cpu_profiler.py b/isaac_ros_test/isaac_ros_test/cpu_profiler.py new file mode 100644 index 0000000..5f091b8 --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/cpu_profiler.py @@ -0,0 +1,94 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""CPU profiler class to measure performance of benchmark tests on x86.""" + +from pathlib import Path +from threading import Thread +from typing import Dict, Tuple + +import numpy as np +import psutil + +from .profiler import Profiler + + +class CPUProfiler(Profiler): + """CPU profiler class to measure CPU performance of benchmark tests.""" + + def __init__(self): + """Construct CPU profiler.""" + super().__init__() + + def start_profiling(self, log_dir: Path, interval: float = 1.0) -> Path: + """ + Start CPU profiling thread to keep track of performance metrics. + + Parameters + ---------- + log_dir : Path + Path to write the logs to + + interval: float + The interval between measurements, in seconds + + """ + super().start_profiling(log_dir) + + # While the is_running flag is true, log CPU usage + def psutil_log(): + with open(self.logfile_path, 'w+') as logfile: + while self.is_running: + logfile.write( + f'{psutil.cpu_percent(interval=interval, percpu=True)}\n') + + self.psutil_thread = Thread(target=psutil_log) + self.psutil_thread.start() + + return self.logfile_path + + def stop_profiling(self): + """Stop profiling after running start_profiling().""" + super().stop_profiling() + + # Now that the is_running flag has been set to false, wait for thread to stop + self.psutil_thread.join() + + def get_results(self, logfile_path: Path = None) -> Dict[str, Tuple[str, str]]: + """ + Return a labelled dictionary of results parsed from the logfile. + + This should only be called after calling start_profiling() and stop_profiling(). + + Returns + ------- + Dict[str, str] + Dictionary mapping label: (value, units) + + """ + assert not self.is_running, 'Cannot collect results until profiler has been stopped!' + + logfile_path = self.logfile_path if logfile_path is None else logfile_path + assert self.logfile_path is not None, 'No logfile to read results from!' + + data = {} + with open(logfile_path) as logfile: + cpu_values = [] + for line in logfile.readlines(): + # Remove brackets from line before splitting entries by comma + cpu_values.append(np.mean([float(v) + for v in line[1:-2].split(',')])) + + cpu_values = np.array(cpu_values) + data['cpu_mean'] = np.mean(cpu_values) + data['cpu_dev'] = np.std(cpu_values) + data['cpu_min'] = np.min(cpu_values) + data['cpu_max'] = np.max(cpu_values) + data['cpu_baseline'] = cpu_values[0] + + return data diff --git a/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_comparison_test.py b/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_comparison_test.py new file mode 100644 index 0000000..f9a1d8c --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_comparison_test.py @@ -0,0 +1,92 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Example to show how a comparison test can be written with isaac_ros_test.""" + +import time + +from isaac_ros_test import IsaacROSBaseTest +import launch_ros +import pytest +import rclpy +from std_msgs.msg import String + + +@pytest.mark.rostest +def generate_test_description(): + """Generate launch description with all ROS2 nodes for testing.""" + nodes = [ + # Normally, we will compare our custom implementation to a reference implementation, + # but for the sake of example here we will compare two separate reference implementations. + launch_ros.actions.Node( + package='demo_nodes_cpp', + executable='talker_loaned_message', + namespace=IsaacROSTalkerComparisonTest.generate_namespace('custom') + ), + launch_ros.actions.Node( + package='demo_nodes_cpp', + executable='talker', + namespace=IsaacROSTalkerComparisonTest.generate_namespace( + 'reference') + ) + ] + + return IsaacROSTalkerComparisonTest.generate_test_description(nodes) + + +class IsaacROSTalkerComparisonTest(IsaacROSBaseTest): + """Comparison tests for demo_nodes_cpp's talker node.""" + + def test_messages_match(self) -> None: + """Expect the messages sent to output topics to match.""" + TIMEOUT = 10 # Seconds before this test times out + # Minimum number of messages that must be received + MESSAGES_RECEIVED_COUNT = 5 + + received_messages = {} + + custom_namespace = self.generate_namespace('custom', 'chatter') + reference_namespace = self.generate_namespace('reference', 'chatter') + + custom_sub, reference_sub = self.create_logging_subscribers( + [(custom_namespace, String), + (reference_namespace, String)], + received_messages, + use_namespace_lookup=False, + accept_multiple_messages=True + ) + + try: + # Wait until the nodes publish messages over the ROS topic + end_time = time.time() + TIMEOUT + done = False + while time.time() < end_time: + rclpy.spin_once(self.node, timeout_sec=0.1) + + if all([ + len(messages) >= MESSAGES_RECEIVED_COUNT + for messages in received_messages.values() + ]): + done = True + break + + self.assertTrue(done, + f'Expected {MESSAGES_RECEIVED_COUNT} messages but received' + f'{len(received_messages)} messages on topic.' + ) + + for custom_msg, reference_msg in zip( + received_messages[custom_namespace], received_messages[reference_namespace] + ): + # We ignore the message number typically included in the talker's output to + # avoid synchronization errors + self.assertEqual(custom_msg.data[:-1], reference_msg.data[:-1]) + + finally: + self.node.destroy_subscription(custom_sub) + self.node.destroy_subscription(reference_sub) diff --git a/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_test.py b/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_test.py new file mode 100644 index 0000000..7076b74 --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/examples/isaac_ros_talker_test.py @@ -0,0 +1,67 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Example to show how an integration test can be written with isaac_ros_test.""" + +import time + +from isaac_ros_test import IsaacROSBaseTest +import launch_ros +import pytest +import rclpy +from std_msgs.msg import String + + +@pytest.mark.rostest +def generate_test_description(): + """Generate launch description with all ROS2 nodes for testing.""" + nodes = [ + launch_ros.actions.Node(package='demo_nodes_cpp', + executable='talker', + namespace=IsaacROSTalkerTest.generate_namespace()) + ] + + return IsaacROSTalkerTest.generate_test_description(nodes) + + +class IsaacROSTalkerTest(IsaacROSBaseTest): + """Tests for demo_nodes_cpp's talker node.""" + + def test_messages_received(self) -> None: + """Expect the node to send messages to output topic.""" + TIMEOUT = 10 # Seconds before this test times out + # Minimum number of messages that must be received + MESSAGES_RECEIVED_COUNT = 5 + + received_messages = [] + + sub = self.node.create_subscription( + String, + self.generate_namespace('chatter'), + lambda msg: received_messages.append(msg), + 10, + ) + + try: + # Wait until the node publishes messages over the ROS topic + end_time = time.time() + TIMEOUT + done = False + while time.time() < end_time: + rclpy.spin_once(self.node, timeout_sec=0.1) + + if len(received_messages) >= MESSAGES_RECEIVED_COUNT: + done = True + break + + self.assertTrue(done, + f'Expected {MESSAGES_RECEIVED_COUNT} messages but received' + f'{len(received_messages)} messages on topic.' + ) + + finally: + self.node.destroy_subscription(sub) diff --git a/isaac_ros_test/isaac_ros_test/isaac_ros_base_test.py b/isaac_ros_test/isaac_ros_test/isaac_ros_base_test.py new file mode 100644 index 0000000..fd7e7d8 --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/isaac_ros_base_test.py @@ -0,0 +1,299 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Base test class for all Isaac ROS tests.""" + +import functools +from pathlib import Path +import time +from typing import Any, Callable, Dict, Iterable, Tuple +import unittest + +from cv_bridge import CvBridge +import launch +import launch_testing.actions +import numpy as np +import rclpy +from rclpy.subscription import Subscription +from sensor_msgs.msg import CameraInfo, Image + + +class IsaacROSBaseTest(unittest.TestCase): + """Base class for all Isaac ROS integration tests.""" + + DEFAULT_NAMESPACE = 'isaac_ros_test' + DEFAULT_QOS = 10 + + def for_each_test_case(subfolder: Path = '') -> Callable: + """ + Create a decorator to run a test function on each of several test case folders. + + Parameters + ---------- + subfolder : Path, optional + Subfolder under test_cases/ to iterate through, by default '' + + Returns + ------- + Callable + Decorator that will iterate in the specified folder or subfolder + + """ + def test_case_decorator(test_fn: Callable[[Path], None]) -> Callable[[], None]: + """ + Decorate a test function to run on each folder under a specified path. + + Parameters + ---------- + test_fn : Callable[[Path], None] + The test function to run on each case, with the case's path passed in + + Returns + ------- + Callable[[], None] + The wrapped function that iterates over all test cases + + """ + @functools.wraps(test_fn) + def wrapper(self): + for test_folder in (self.filepath / 'test_cases' / subfolder).iterdir(): + if (test_folder / 'SKIP').exists(): # Skip folders with SKIP file + self.node.get_logger().info( + f'Skipping folder: {test_folder}') + else: + self.node.get_logger().info( + f'Starting test for case: {test_folder}') + test_fn(self, test_folder) + return wrapper + + return test_case_decorator + + @classmethod + def generate_namespace(cls, *tokens: Iterable[str], absolute=True) -> str: + """ + Generate a namespace with an optional list of tokens. + + This function is a utility for producing namespaced topic and service names in + such a way that there are no collisions between 'dummy' nodes running for testing + and 'normal' nodes running on the same machine. + + Parameters + ---------- + tokens : Iterable[str] + List of tokens to include in the namespace. Often used to generate + separate namespaces for Isaac ROS and reference implementations. + + absolute: bool + Whether or not to generate an absolute namespace, by default True. + + Returns + ------- + str + The generated namespace as a slash-delimited string + + """ + return ('/' if absolute else '') + '/'.join([cls.DEFAULT_NAMESPACE, *tokens]) + + def generate_namespace_lookup( + self, topic_names: Iterable[str], *tokens: Iterable[str], absolute: bool = True + ) -> None: + """ + Save a lookup dictionary mapping topics from friendly names to namespaced names. + + Parameters + ---------- + topic_names : Iterable[str] + The friendly topic names to produce namespaced names for + tokens : Iterable[str] + List of tokens to include in the namespace. + Passed directly to generate_namespace + absolute : bool, optional + Whether or not to generate an absolute namespace, by default True. + Passed directly to generate_namespace + + """ + self.namespaces = { + topic: self.generate_namespace(*tokens, topic, absolute=absolute) + for topic in topic_names + } + + @classmethod + def generate_test_description( + cls, nodes: Iterable[launch.Action], node_startup_delay: float = 2.0 + ) -> launch.LaunchDescription: + """ + Generate a test launch description. + + The nodes included in this launch description will be launched as a test fixture + immediately before the first test in the test class runs. Note that the graph is + NOT shut down or re-launched between tests within the same class. + + Parameters + ---------- + nodes : Iterable[launch.Action] + List of Actions to launch before running the test. + node_startup_delay : float, optional + Seconds to delay by to account for node startup, by default 2.0 + + Returns + ------- + launch.LaunchDescription + The LaunchDescription object to launch before running the test + + """ + return launch.LaunchDescription( + nodes + [ + # Start tests after a fixed delay for node startup + launch.actions.TimerAction( + period=node_startup_delay, actions=[launch_testing.actions.ReadyToTest()]) + ] + ) + + def assertImagesEqual( + self, actual: np.ndarray, expected: np.ndarray, threshold_fraction: float = 0.01 + ) -> None: + """ + Assert that two images are equal within tolerance. + + Parameters + ---------- + actual : np.ndarray + Actual image received + expected : np.ndarray + Expected image to match against + threshold_fraction : float, optional + The fraction of allowable variation between the images, by default 0.01. + A value of 0 means a pixel-perfect match is required. A value of 1 means + that even the biggest possible difference (full-white against full-black) + will count as a match. + + """ + self.assertTupleEqual(actual.shape, expected.shape) + difference = np.linalg.norm(actual - expected) + threshold_pixels = threshold_fraction * actual.size * 255 + self.assertLessEqual( + difference, threshold_pixels, + f'Image difference of {difference} pixels is larger than ' + f'threshold of {threshold_pixels} pixels!' + ) + + def create_logging_subscribers( + self, + subscription_requests: Iterable[Tuple[str, Any]], + received_messages: Dict[str, Iterable], + use_namespace_lookup: bool = True, + accept_multiple_messages: bool = False, + add_received_message_timestamps: bool = False + ) -> Iterable[Subscription]: + """ + Create subscribers that log any messages received to the passed-in dictionary. + + Parameters + ---------- + subscription_requests : Iterable[Tuple[str, Any]] + List of topic names and topic types to subscribe to. + + received_messages : Dict[str, Iterable] + Output dictionary mapping topic name to list of messages received + + use_namespace_lookup : bool + Whether the object's namespace dictionary should be used for topic + namespace remapping, by default True + + accept_multiple_messages : bool + Whether the generated subscription callbacks should accept multiple messages, + by default False + + add_received_message_timestamps : bool + Whether the generated subscription callbacks should add a timestamp to the messages, + by default False + + Returns + ------- + Iterable[Subscription] + List of subscribers, passing the unsubscribing responsibility to the caller + + """ + received_messages.clear() + if accept_multiple_messages: + for topic, _ in subscription_requests: + received_messages[topic] = [] + + def make_callback(topic): + def callback(msg): + if accept_multiple_messages: + if add_received_message_timestamps: + received_messages[topic].append((msg, time.time())) + else: + received_messages[topic].append(msg) + else: + self.assertTrue(topic not in received_messages, + f'Already received a message on topic {topic}!') + received_messages[topic] = msg + + return callback + + subscriptions = [self.node.create_subscription( + msg_type, + self.namespaces[topic] if use_namespace_lookup else topic, + make_callback(topic), + self.DEFAULT_QOS, + ) for topic, msg_type in subscription_requests] + + return subscriptions + + def synchronize_timestamps( + self, + image: Image, + camera_info: CameraInfo + ) -> Tuple[Image, CameraInfo]: + """ + Create subscribers that log any messages received to the passed-in dictionary. + + Parameters + ---------- + image : Image + Image message to synchronize timestamp with camera_info + + camera_info : CameraInfo + CameraInfo to synchronize timestamp with image + + Returns + ------- + Tuple[Image, CameraInfo] + Same input image and camera info but now with equal timestamps + + """ + timestamp = self.node.get_clock().now().to_msg() + image.header.stamp = timestamp + camera_info.header.stamp = timestamp + + return image, camera_info + + @classmethod + def setUpClass(cls) -> None: + """Set up before first test method.""" + # Initialize the ROS context for the test node + rclpy.init() + + @classmethod + def tearDownClass(cls) -> None: + """Tear down after last test method.""" + # Shutdown the ROS context + rclpy.shutdown() + + def setUp(self) -> None: + """Set up before each test method.""" + # Create a ROS node for tests + self.node = rclpy.create_node( + 'isaac_ros_base_test_node', namespace=self.generate_namespace()) + self.bridge = CvBridge() + + def tearDown(self) -> None: + """Tear down after each test method.""" + self.node.destroy_node() diff --git a/isaac_ros_test/isaac_ros_test/json_conversion.py b/isaac_ros_test/isaac_ros_test/json_conversion.py new file mode 100644 index 0000000..bce3ab8 --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/json_conversion.py @@ -0,0 +1,197 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Utilities to convert ROS2 messages to and from human-readable JSON.""" + +import json +from pathlib import Path +from typing import Dict, Tuple + +import cv2 +from cv_bridge import CvBridge +from sensor_msgs.msg import CameraInfo, Image + + +class JSONConversion: + """Class for JSON conversion utilities.""" + + @staticmethod + def load_from_json(json_filepath: Path) -> Dict: + """ + Load a dictionary from a JSON filepath. + + Parameters + ---------- + json_filepath : Path + The path to a JSON file containing the object + + Returns + ------- + Dict + Generated dictionary containing object fields + + """ + with open(json_filepath) as json_file: + return json.load(json_file) + + @staticmethod + def save_to_json(obj: Dict, json_filepath: Path) -> None: + """ + Save an arbitrary object to a JSON filepath. + + Parameters + ---------- + obj : Dict + The object to save, as a dictionary + + json_filepath : Path + The path to the JSON file to save the object to + + """ + with open(json_filepath, 'w+') as json_file: + json.dump(obj, json_file, indent=2) + + @staticmethod + def load_camera_info_from_json(json_filepath: Path) -> CameraInfo: + """ + Load a CameraInfo message from a JSON filepath. + + Parameters + ---------- + json_filepath : Path + The path to a JSON file containing the CameraInfo fields + + Returns + ------- + CameraInfo + Generated CameraInfo message + + """ + camera_info_json = JSONConversion.load_from_json(json_filepath) + + camera_info = CameraInfo() + camera_info.header.frame_id = camera_info_json['header']['frame_id'] + camera_info.width = camera_info_json['width'] + camera_info.height = camera_info_json['height'] + camera_info.distortion_model = camera_info_json['distortion_model'] + camera_info.d = camera_info_json['D'] + camera_info.k = camera_info_json['K'] + camera_info.r = camera_info_json['R'] + camera_info.p = camera_info_json['P'] + + return camera_info + + @staticmethod + def save_camera_info_to_json(camera_info: CameraInfo, json_filepath: Path) -> None: + """ + Save a CameraInfo message to a JSON filepath. + + Parameters + ---------- + camera_info : CameraInfo + The message to save to JSON + + json_filepath : Path + The path to save the JSON file + + """ + camera_info_json = {} + + camera_info_json['header'] = {} + camera_info_json['header']['frame_id'] = camera_info.header.frame_id + + camera_info_json['width'] = camera_info.width + camera_info_json['height'] = camera_info.height + camera_info_json['distortion_model'] = camera_info.distortion_model + + camera_info_json['D'] = camera_info.d.tolist() + camera_info_json['K'] = camera_info.k.tolist() + camera_info_json['R'] = camera_info.r.tolist() + camera_info_json['P'] = camera_info.p.tolist() + + JSONConversion.save_to_json(camera_info_json, json_filepath) + + @staticmethod + def load_image_from_json(json_filepath: Path) -> Image: + """ + Load an Image message from a JSON filepath. + + Parameters + ---------- + json_filepath : Path + The path to a JSON file containing the Image fields + + Returns + ------- + Image + Generated Image message + + """ + image_json = JSONConversion.load_from_json(json_filepath) + + # Load the main image data from a JSON-specified image file + image = CvBridge().cv2_to_imgmsg(cv2.imread( + str(json_filepath.parent / image_json['image']))) + + image.encoding = image_json['encoding'] + + return image + + @staticmethod + def save_image_to_json( + image: Image, json_filepath: Path, image_filename: str = 'image_raw.jpg') -> None: + """ + Save an Image message to a JSON filepath. + + Parameters + ---------- + image : Image + The message to save to JSON + + json_filepath : Path + The path to save the JSON file + + image_filename : str + The filename to save the image data to, by default image_raw.jpg + + """ + # Load the main image data from a JSON-specified image file + cv2.imwrite(str(json_filepath.parent / + image_filename), CvBridge().imgmsg_to_cv2(image)) + + image_json = {} + image_json['image'] = image_filename + image_json['encoding'] = image.encoding + + JSONConversion.save_to_json(image_json, json_filepath) + + @staticmethod + def load_chessboard_image_from_json(json_filepath: Path) -> Tuple[Image, Tuple[int, int]]: + """ + Load a chessboard Image message from a JSON filepath. + + Parameters + ---------- + json_filepath : Path + The path to a JSON file containing the Image fields + + Returns + ------- + Tuple[Image, Tuple[int, int]] + Generated Image message and tuple of chessboard dimensions as (width, height) + + """ + image_json = JSONConversion.load_from_json(json_filepath) + + # Load the chessboard dimensions from JSON + chessboard_dimensions = ( + image_json['chessboard']['width'], image_json['chessboard']['height']) + + # Return the loaded image along with the dimensions + return JSONConversion.load_image_from_json(json_filepath), \ + chessboard_dimensions diff --git a/isaac_ros_test/isaac_ros_test/profiler.py b/isaac_ros_test/isaac_ros_test/profiler.py new file mode 100644 index 0000000..2040c5a --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/profiler.py @@ -0,0 +1,69 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Profiler base class to measure the performance of benchmark tests.""" + +from abc import ABC, abstractmethod +from datetime import datetime +from pathlib import Path +from typing import Dict, Tuple + + +class Profiler(ABC): + """Profiler base class to measure the performance of benchmark tests.""" + + @abstractmethod + def __init__(self): + """Construct profiler.""" + self.is_running = False + + # Logfile path is generated once start_profiling() is called + self.logfile_path = None + + @abstractmethod + def start_profiling(self, log_dir: Path) -> None: + """ + Run profiling program to keep track of performance metrics. + + Parameters + ---------- + log_dir : Path + Path to write the logs to + + """ + assert not self.is_running, 'Profiler has already been started!' + self.is_running = True + + # Create logfile parent folders if they don't exist already + log_dir.mkdir(parents=True, exist_ok=True) + + self.logfile_path = log_dir / \ + f'{type(self).__name__}_{datetime.timestamp(datetime.now())}.log' + + return self.logfile_path + + @abstractmethod + def stop_profiling(self) -> None: + """Stop profiling after running start_profiling().""" + assert self.is_running, 'Profiler was not yet started!' + self.is_running = False + + @abstractmethod + def get_results(self, logfile_path: Path = None) -> Dict[str, Tuple[str, str]]: + """ + Return a labelled dictionary of results parsed from the logfile. + + This should only be called after calling start_profiling() and stop_profiling(). + + Returns + ------- + Dict[str, str] + Dictionary mapping label: (value, units) + + """ + return diff --git a/isaac_ros_test/isaac_ros_test/tegrastats_profiler.py b/isaac_ros_test/isaac_ros_test/tegrastats_profiler.py new file mode 100644 index 0000000..2273d7e --- /dev/null +++ b/isaac_ros_test/isaac_ros_test/tegrastats_profiler.py @@ -0,0 +1,110 @@ +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Tegrastats profiler class to measure CPU and GPU performance of benchmark tests.""" + +from datetime import datetime +import os +import re +import subprocess +from typing import Dict + +import numpy as np + +from .profiler import Profiler + + +class TegrastatsProfiler(Profiler): + """Tegrastats profiler class to measure CPU and GPU performance of benchmark tests.""" + + def __init__(self, command_path: str = '/tegrastats'): + """ + Construct Tegrastats profiler. + + Parameters + ---------- + command_path : str + Path to invoke the profiler binary + + """ + self.tegrastats_path = command_path + self.profiler_running = False + + def start_profiling(self, interval: float, log_dir: str) -> str: + """ + Run tegrastats profiling program to keep track of performance metrics. + + Parameters + ---------- + interval : float + Interval for the profiler + log_dir : str + Path to write the logs to + + Returns + ------- + str + The path to the file where the profiler will write its logs to. If start_profiling() + is called when the profiler is still running, return an empty string + + """ + if not self.profiler_running: + file_name = str(datetime.timestamp(datetime.now())) + '.txt' + file_path = os.path.join(log_dir, file_name) + subprocess.Popen([self.tegrastats_path, '--interval', + str(interval), '--logfile', file_path]) + self.profiler_running = True + return file_path + else: + print('Profiler is already running.') + return '' + + def stop_profiling(self): + """Stop profiling after running start_profiling().""" + if self.profiler_running: + subprocess.Popen([self.tegrastats_path, '--stop']) + self.profiler_running = False + + def print_profiling_results(self, logfile_path: str) -> Dict[str, float]: + """ + Parse Tegrastats profiling results from the logs and print them. + + This should only be called after calling start_profiling() and stop_profiling(). + + Parameters + ---------- + logfile_path : str + The path to the logfile that will be parsed + + Returns + ------- + Dict[str, float] + Dictionary where each key is the metric name, and the value is the metric's value + + """ + data = {} + gpu_values = [] + cpu_values = [] + with open(logfile_path) as file: + for line in file.readlines(): + fields = line.split() + GPU = fields[13] + CPU = fields[9][1:-1] + gpu_values.append(float(GPU[:-1])) + cpu_array = re.split('%@[0-9]+[,]?', CPU) + cpu_array = [float(value) for value in cpu_array[:-1]] + cpu_values.append(np.mean(cpu_array)) + data['gpu_mean'] = np.mean(gpu_values) + data['gpu_deviation'] = np.std(gpu_values) + data['gpu_max'] = max(gpu_values) + data['gpu_min'] = min(gpu_values) + data['cpu_mean'] = np.mean(cpu_values) + data['cpu_dev'] = np.std(cpu_values) + data['cpu_max'] = max(cpu_values) + data['cpu_min'] = min(cpu_values) + return data diff --git a/isaac_ros_test/package.xml b/isaac_ros_test/package.xml new file mode 100644 index 0000000..c8d6d71 --- /dev/null +++ b/isaac_ros_test/package.xml @@ -0,0 +1,33 @@ + + + + + + + isaac_ros_test + 0.9.0 + Isaac ROS testing utilities + + Hemal Shah + JetPack EULA + https://developer.nvidia.com/blog/accelerating-ai-modules-for-ros-and-ros-2-on-jetson/ + Ethan Yu + Isaac Chang + Jaiveer Singh + + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/isaac_ros_test/resource/isaac_ros_test b/isaac_ros_test/resource/isaac_ros_test new file mode 100644 index 0000000..e69de29 diff --git a/isaac_ros_test/setup.cfg b/isaac_ros_test/setup.cfg new file mode 100644 index 0000000..1be1f98 --- /dev/null +++ b/isaac_ros_test/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/isaac_ros_test +[install] +install_scripts=$base/lib/isaac_ros_test diff --git a/isaac_ros_test/setup.py b/isaac_ros_test/setup.py new file mode 100644 index 0000000..47c5b1c --- /dev/null +++ b/isaac_ros_test/setup.py @@ -0,0 +1,25 @@ +from setuptools import setup + +package_name = 'isaac_ros_test' + +setup( + name=package_name, + version='0.1.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Jaiveer Singh', + maintainer_email='jaiveers@nvidia.com', + description='Isaac ROS testing utilities', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + ], + }, +) diff --git a/isaac_ros_test/test/test_flake8.py b/isaac_ros_test/test/test_flake8.py new file mode 100644 index 0000000..27ee107 --- /dev/null +++ b/isaac_ros_test/test/test_flake8.py @@ -0,0 +1,25 @@ +# Copyright 2017 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_flake8.main import main_with_errors +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc, errors = main_with_errors(argv=[]) + assert rc == 0, \ + 'Found %d code style errors / warnings:\n' % len(errors) + \ + '\n'.join(errors) diff --git a/isaac_ros_test/test/test_pep257.py b/isaac_ros_test/test/test_pep257.py new file mode 100644 index 0000000..399afc9 --- /dev/null +++ b/isaac_ros_test/test/test_pep257.py @@ -0,0 +1,23 @@ +# Copyright 2015 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_pep257.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.pep257 +def test_pep257(): + rc = main(argv=['.']) + assert rc == 0, 'Found code style errors / warnings' diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..7b09314 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,6 @@ +# Isaac ROS Dev Build Scripts + + +For Jetson or x86_64: + `run_dev.sh` creates a dev environment with ROS2 installed. By default, the directory `/workspace` in the container is mapped from `~/workspaces/isaac_ros-dev` on the host machine, but the directory the container is mapping from can be replaced by running the script and passing a path as the first argument: + `run_dev.sh ` diff --git a/scripts/run_dev.sh b/scripts/run_dev.sh new file mode 100755 index 0000000..c84d2e8 --- /dev/null +++ b/scripts/run_dev.sh @@ -0,0 +1,98 @@ +#!/bin/bash -e +# +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +source $ROOT/utils/print_color.sh + +function usage() { + print_info "Usage: run_dev.sh" {isaac_ros_dev directory path OPTIONAL} + print_into "Copyright (c) 2021, NVIDIA CORPORATION." +} + +ISAAC_ROS_DEV_DIR="$1" +if [[ -z "$ISAAC_ROS_DEV_DIR" ]]; then + ISAAC_ROS_DEV_DIR="$HOME/workspaces/isaac_ros-dev" + print_warning "isaac_ros_dev not specified, assuming $ISAAC_ROS_DEV_DIR" +else + shift 1 +fi + +ON_EXIT=() +function cleanup { + for command in "${ON_EXIT[@]}" + do + $command + done +} +trap cleanup EXIT + +pushd . +cd $ROOT +ON_EXIT+=("popd") + +PLATFORM="$(uname -m)" + +BASE_NAME="isaac_ros_dev-$PLATFORM" +CONTAINER_NAME="$BASE_NAME-container" + +# Arguments for docker build +BUILD_ARGS+=("--build-arg USERNAME="admin"") +BUILD_ARGS+=("--build-arg USER_UID=`id -u`") +BUILD_ARGS+=("--build-arg USED_GID=`id -g`") + +# Check if GPU is installed +if [[ $PLATFORM == "x86_64" ]]; then + if type nvidia-smi &>/dev/null; then + GPU_ATTACHED=(`nvidia-smi -a | grep "Attached GPUs"`) + if [ ! -z $GPU_ATTACHED ]; then + BUILD_ARGS+=("--build-arg HAS_GPU="true"") + fi + fi +fi + +# Build image +print_info "Building $PLATFORM base as image: $BASE_NAME" +docker build -f $ROOT/../docker/Dockerfile.$PLATFORM.base \ + -t $BASE_NAME \ + ${BUILD_ARGS[@]} \ + $ROOT/../docker + +# Map host's display socket to docker +DOCKER_ARGS+=("-v /tmp/.X11-unix:/tmp/.X11-unix") +DOCKER_ARGS+=("-e DISPLAY") +DOCKER_ARGS+=("-e NVIDIA_VISIBLE_DEVICES=all") +DOCKER_ARGS+=("-e NVIDIA_DRIVER_CAPABILITIES=all") + +if [[ $PLATFORM == "aarch64" ]]; then + DOCKER_ARGS+=("-v /opt/nvidia:/opt/nvidia") + DOCKER_ARGS+=("-v /usr/bin/tegrastats:/usr/bin/tegrastats") + DOCKER_ARGS+=("-v /usr/share/vpi1:/usr/share/vpi1") + DOCKER_ARGS+=("-v /usr/lib/aarch64-linux-gnu/tegra:/usr/lib/aarch64-linux-gnu/tegra") + DOCKER_ARGS+=("-v /usr/local/cuda-10.2/targets/aarch64-linux/lib:/usr/local/cuda-10.2/targets/aarch64-linux/lib") + DOCKER_ARGS+=("-v /usr/lib/aarch64-linux-gnu/tegra-egl:/usr/lib/aarch64-linux-gnu/tegra-egl") + DOCKER_ARGS+=("-v /usr/lib/aarch64-linux-gnu/libcudnn.so.8.2.1:/usr/lib/aarch64-linux-gnu/libcudnn.so.8.2.1") + DOCKER_ARGS+=("-v /dev/video*:/dev/video*") +fi + +# Run container from image +print_info "Running $CONTAINER_NAME" +docker run -it --rm \ + --privileged --network host \ + ${DOCKER_ARGS[@]} \ + -v $ISAAC_ROS_DEV_DIR:/workspaces/isaac_ros-dev \ + --name "$CONTAINER_NAME" \ + --gpus all \ + --user="admin" \ + --entrypoint /home/admin/workspace-entrypoint.sh \ + $@ \ + $BASE_NAME \ + /bin/bash + + diff --git a/scripts/utils/print_color.sh b/scripts/utils/print_color.sh new file mode 100644 index 0000000..8a1ac77 --- /dev/null +++ b/scripts/utils/print_color.sh @@ -0,0 +1,27 @@ +#!/bin/bash -e +# +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +function print_color { + tput setaf $1 + echo "$2" + tput sgr0 +} + +function print_error { + print_color 1 "$1" +} + +function print_warning { + print_color 3 "$1" +} + +function print_info { + print_color 2 "$1" +}