记录一下自己从px4到板载控制的一系列流程以及踩坑过程,希望也可以帮助大家避雷。话不多说直接上干货。
一、软、硬件平台
px4版本:1.10.1
飞控板:pixhawk4
ros版本:melodic
linux版本:ubuntu18.04.05
二、px4下载、编译、环境配置
推荐直接到官网下载,一次不成功就多试几次,也可以换github的国内镜像站:
https://github.com.cnpmjs.org
https://hub.fastgit.org
下载完成之后在linux下配置环境:
1.先将串口加入到用户组,增加串口权限
sudo usermod -a -G dialout $USER
2.首先运行firmware/tools/setup/ubuntu.sh安装需要的依赖,找一个好一点的网络一次成功,有配置不成功的地方之后再说。
然后这其中可能出现的问题就是交叉编译器有问题,推荐2017-q4版本的编译器,gcc-arm-none-eabi-7-2017-q4-major,,这里有链接:
1.https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads2.tar -jxf gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2//解压3.gedit .bashrc#在最后一行加入下列代码。注意:gcc-arm-none-eabi-7-2017-q4-major替换成你的4.export PATH=$HOME/gcc-arm-none-eabi-7-2017-q4-major/bin:$PATH#查看版本是否成功5.echo $PATH6.arm-none-eabi-gcc --version
用ROS(melodic)的话建议python2,这样不会冲突。
3.这两个关键步骤做完之后,直接进firmware目录编译固件,然后就会报错,这个时候缺啥补啥就完事啦!
编译make px4_fmu-v5_default下载make px4_fmu-v5_default upload
三、mavros安装(这里推荐使用源码方式安装,因为后续要是修改mavros源码包的话方便修改)
1.我把mavros工作空间放在了home下,打开终端,执行下面命令,会逐级新建文件夹
mkdir -p ~/catkin_ws/srccd ~/catkin_wscatkin initwstool init src
2.安装必要的工具链,加-y目的是为了省略之后要一直输入y来确认安装的步骤
sudo apt-get install python-catkin-tools python-rosinstall-generator -y
3初始化工作空间
wstool init ~/catkin_ws/src
4.安装mavlink,4 5步骤进到src里边执行
rosinstall_generator --rosdistro melodic mavlink | tee /tmp/mavros.rosinstall
这时候可能会出现(这里引用了别人的图片)
这样的意思就是告诉你新的版本是多少,并没有完成安装。我们可以先忽略这个进行下一步。
5.安装mavros
rosinstall_generator --upstream-development mavros | tee -a /tmp/mavros.rosinstall
如果下载不成功。可以进行换镜像站操作,打开src目录下的.rosinstall文件,将github.com更换为hub.fastgit.org,然后重新执行命令
6.创建工作空间以及依赖,注意回退到上级目录执行,即catkin_ws目录下
wstool merge -t src /tmp/mavros.rosinstallwstool update -t src -j4
rosdep install --from-paths src --ignore-src -y
注意:这里有个大坑,在进行上面两步之后如果直接执行rosdep install这行代码,很大程度上是运行不成功的,因为rosdep并没有进行更新,要执行rosdep update,但是在国内的话rosdep update基本是运行不成功的,因为rosdep update的网址在国外,这里有如下解决办法
找到这几个文件:为了兼容melodic版本,我用的是python2.7,所以这三个文件在这个路径下,每个人情况不同,具体路径视情况而定,找到之后分别按以下的代码进行替换,如果有版本不一样的,可以对照进行修改,主要是在网址前加了代理
sudo gedit /usr/lib/python2.7/dist-packages/rosdep2/rep3.pysudo gedit /usr/lib/python2.7/dist-packages/rosdep2/sources_list.pysudo gedit /usr/lib/python2.7/dist-packages/rosdep2/gbpdistro_suppor
# Copyright (c) 2012, Willow Garage, Inc.# All rights reserved.## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions are met:## * Redistributions of source code must retain the above copyright# notice, this list of conditions and the following disclaimer.# * Redistributions in binary form must reproduce the above copyright# notice, this list of conditions and the following disclaimer in the# documentation and/or other materials provided with the distribution.# * Neither the name of the Willow Garage, Inc、nor the names of its# contributors may be used to endorse or promote products derived from# this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ConTRIBUTORS "AS IS"# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE# ARE DISCLAIMED、IN NO EVENT SHALL THE COPYRIGHT OWNER OR ConTRIBUTORS BE# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR# ConSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE# POSSIBILITY OF SUCH DAMAGE.try: from urllib.request import urlopenexcept importError: from urllib2 import urlopenimport yamlimport warningsfrom .core import DownloadFailurefrom .rosdistrohelper import PreRep137Warning# location of targets file for processing gbpdistro filesREP3_TARGETS_URL = 'https://ghproxy.com/https://raw.githubusercontent.com/ros/rosdistro/master/releases/targets.yaml'# seconds to wait before aborting download of gbpdistro dataDOWNLOAD_TIMEOUT = 15.0def download_targets_data(targets_url=None): """ Download REP 3 targets file and unmarshal from YAML. DEPRECATED: this function is deprecated、List of targets should be obtained from the rosdistro module. The body of this function is an example. :param target_url: override URL of platform targets file、Defaults to ``REP3_TARGETS_URL``. :raises: :exc:`DownloadFailure` :raises: :exc:`InvalidData` If targets file does not pass cursory validation checks. """ warnings.warn('deprecated, use rosdistro instead', PreRep137Warning) if targets_url is None: targets_url = REP3_TARGETS_URL try: f = urlopen(targets_url, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() targets_data = yaml.safe_load(text) except Exception as e: raise DownloadFailure('Failed to download target platform data for gbpdistro:nt%s' % (str(e))) if type(targets_data) == list: # convert to dictionary new_targets_data = {} for t in targets_data: platform = list(t.keys())[0] new_targets_data[platform] = t[platform] targets_data = new_targets_data return targets_data
# Copyright (c) 2012, Willow Garage, Inc.# All rights reserved.## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions are met:## * Redistributions of source code must retain the above copyright# notice, this list of conditions and the following disclaimer.# * Redistributions in binary form must reproduce the above copyright# notice, this list of conditions and the following disclaimer in the# documentation and/or other materials provided with the distribution.# * Neither the name of the Willow Garage, Inc、nor the names of its# contributors may be used to endorse or promote products derived from# this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ConTRIBUTORS "AS IS"# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE# ARE DISCLAIMED、IN NO EVENT SHALL THE COPYRIGHT OWNER OR ConTRIBUTORS BE# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR# ConSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE# POSSIBILITY OF SUCH DAMAGE.# Author Ken Conley/kwc@willowgarage.comfrom __future__ import print_functionimport osimport sysimport yamltry: from urllib.request import urlopen from urllib.error import URLError import urllib.request as requestexcept importError: from urllib2 import urlopen from urllib2 import URLError import urllib2 as requesttry: import cPickle as pickleexcept importError: import picklefrom .cache_tools import compute_filename_hash, PICKLE_CACHE_EXT, write_atomic, write_cache_filefrom .core import InvalidData, DownloadFailure, CachePermissionErrorfrom .gbpdistro_support import get_gbprepo_as_rosdep_data, download_gbpdistro_as_rosdep_datafrom .meta import metaDatabasefrom ._version import __version__try: import urlparseexcept importError: import urllib.parse as urlparse # py3ktry: import httplibexcept importError: import http.client as httplib # py3kimport rospkgimport rospkg.distrofrom .loader import RosdepLoaderfrom .rosdistrohelper import get_index, get_index_url# default file to download with 'init' command in order to bootstrap# rosdepDEFAULT_SOURCES_LIST_URL = 'https://ghproxy.com/https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list'# seconds to wait before aborting download of rosdep dataDOWNLOAD_TIMEOUT = 15.0SOURCES_LIST_DIR = 'sources.list.d'SOURCES_CACHE_DIR = 'sources.cache'# name of index file for sources cacheCACHE_INDEX = 'index'# extension for binary cacheSOURCE_PATH_ENV = 'ROSDEP_SOURCE_PATH'def get_sources_list_dirs(source_list_dir): if SOURCE_PATH_ENV in os.environ: sdirs = os.environ[SOURCE_PATH_ENV].split(os.pathsep) else: sdirs = [source_list_dir] for p in list(sdirs): if not os.path.exists(p): sdirs.remove(p) return sdirsdef get_sources_list_dir(): # base of where we read config files from # TODO: windows if 0: # we can't use etc/ros because environment config does not carry over under sudo etc_ros = rospkg.get_etc_ros_dir() else: etc_ros = '/etc/ros' # compute default system wide sources directory sys_sources_list_dir = os.path.join(etc_ros, 'rosdep', SOURCES_LIST_DIR) sources_list_dirs = get_sources_list_dirs(sys_sources_list_dir) if sources_list_dirs: return sources_list_dirs[0] else: return sys_sources_list_dirdef get_default_sources_list_file(): return os.path.join(get_sources_list_dir(), '20-default.list')def get_sources_cache_dir(): ros_home = rospkg.get_ros_home() return os.path.join(ros_home, 'rosdep', SOURCES_CACHE_DIR)# Default rosdep.yaml format、 For now this is the only valid type and# is specified for future compatibility.TYPE_YAML = 'yaml'# git-buildpackage repo listTYPE_GBPDISTRO = 'gbpdistro'VALID_TYPES = [TYPE_YAML, TYPE_GBPDISTRO]class DataSource(object): def __init__(self, type_, url, tags, origin=None): """ :param type_: data source type, e.g、TYPE_YAML, TYPE_GBPDISTRO :param url: URL of data location、 For file resources, must start with the file:// scheme、 For remote resources, URL must include a path. :param tags: tags for matching data source to configurations :param origin: filename or other indicator of where data came from for debugging. :raises: :exc:`ValueError` if parameters do not validate """ # validate inputs if type_ not in VALID_TYPES: raise ValueError('type must be one of [%s]' % (','.join(VALID_TYPES))) parsed = urlparse.urlparse(url) if not parsed.scheme or (parsed.scheme != 'file' and not parsed.netloc) or parsed.path in ('', '/'): raise ValueError('url must be a fully-specified URL with scheme, hostname, and path: %s' % (str(url))) if not type(tags) == list: raise ValueError('tags must be a list: %s' % (str(tags))) self.type = type_ self.tags = tags self.url = url self.origin = origin def __eq__(self, other): return isinstance(other, DataSource) and self.type == other.type and self.tags == other.tags and self.url == other.url and self.origin == other.origin def __str__(self): if self.origin: return '[%s]:n%s %s %s' % (self.origin, self.type, self.url, ' '.join(self.tags)) else: return '%s %s %s' % (self.type, self.url, ' '.join(self.tags)) def __repr__(self): return repr((self.type, self.url, self.tags, self.origin))class RosDistroSource(DataSource): def __init__(self, distro): self.type = TYPE_GBPDISTRO self.tags = [distro] # In this case self.url is a list if REP-143 is being used self.url = get_index().distributions[distro]['distribution'] self.origin = None# create function we can pass in as model to parse_source_data、 The# function emulates the CachedDataSource constructor but does the# necessary full filepath calculation and loading of data.def cache_data_source_loader(sources_cache_dir, verbose=False): def create_model(type_, uri, tags, origin=None): # compute the filename has from the URL filename = compute_filename_hash(uri) filepath = os.path.join(sources_cache_dir, filename) pickle_filepath = filepath + PICKLE_CACHE_EXT if os.path.exists(pickle_filepath): if verbose: print('loading cached data source:nt%snt%s' % (uri, pickle_filepath), file=sys.stderr) with open(pickle_filepath, 'rb') as f: rosdep_data = pickle.loads(f.read()) elif os.path.exists(filepath): if verbose: print('loading cached data source:nt%snt%s' % (uri, filepath), file=sys.stderr) with open(filepath) as f: rosdep_data = yaml.safe_load(f.read()) else: rosdep_data = {} return CachedDataSource(type_, uri, tags, rosdep_data, origin=filepath) return create_modelclass CachedDataSource(object): def __init__(self, type_, url, tags, rosdep_data, origin=None): """ Stores data source and loaded rosdep data for that source. NOTE: this is not a subclass of DataSource, though it's API is duck-type compatible with the DataSource API. """ self.source = DataSource(type_, url, tags, origin=origin) self.rosdep_data = rosdep_data def __eq__(self, other): try: return self.source == other.source and self.rosdep_data == other.rosdep_data except AttributeError: return False def __str__(self): return '%sn%s' % (self.source, self.rosdep_data) def __repr__(self): return repr((self.type, self.url, self.tags, self.rosdep_data, self.origin)) @property def type(self): """ :returns: data source type """ return self.source.type @property def url(self): """ :returns: data source URL """ return self.source.url @property def tags(self): """ :returns: data source tags """ return self.source.tags @property def origin(self): """ :returns: data source origin, if set, or ``None`` """ return self.source.originclass DataSourceMatcher(object): def __init__(self, tags): self.tags = tags def matches(self, rosdep_data_source): """ Check if the datasource matches this configuration. :param rosdep_data_source: :class:`DataSource` """ # all of the rosdep_data_source tags must be in our matcher tags return not any(set(rosdep_data_source.tags) - set(self.tags)) @staticmethod def create_default(os_override=None): """ Create a :class:`DataSourceMatcher` to match the current configuration. :param os_override: (os_name, os_codename) tuple to override OS detection :returns: :class:`DataSourceMatcher` """ distro_name = rospkg.distro.current_distro_codename() if os_override is None: os_detect = rospkg.os_detect.OsDetect() os_name, os_version, os_codename = os_detect.detect_os() else: os_name, os_codename = os_override tags = [t for t in (distro_name, os_name, os_codename) if t] return DataSourceMatcher(tags)def download_rosdep_data(url): """ :raises: :exc:`DownloadFailure` If data cannot be retrieved (e.g、404, bad YAML format, server down). """ try: # http/https URLs need custom requests to specify the user-agent, since some repositories reject # requests from the default user-agent. url="https://ghproxy.com/"+url if url.startswith("http://") or url.startswith("https://"): url_request = request.Request(url, headers={'User-Agent': 'rosdep/{version}'.format(version=__version__)}) else: url_request = url f = urlopen(url_request, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() data = yaml.safe_load(text) if type(data) != dict: raise DownloadFailure('rosdep data from [%s] is not a YAML dictionary' % (url)) return data except (URLError, httplib.HTTPException) as e: raise DownloadFailure(str(e) + ' (%s)' % url) except yaml.YAMLError as e: raise DownloadFailure(str(e))def download_default_sources_list(url=DEFAULT_SOURCES_LIST_URL): """ Download (and validate) contents of default sources list. :param url: override URL of default sources list file :return: raw sources list data, ``str`` :raises: :exc:`DownloadFailure` If data cannot be retrieved (e.g、404, bad YAML format, server down). :raises: :exc:`urllib2.URLError` If data cannot be retrieved (e.g、404, server down). """ try: f = urlopen(url, timeout=DOWNLOAD_TIMEOUT) except (URLError, httplib.HTTPException) as e: raise URLError(str(e) + ' (%s)' % url) data = f.read().decode() f.close() if not data: raise DownloadFailure('cannot download defaults file from %s : empty contents' % url) # parse just for validation try: parse_sources_data(data) except InvalidData as e: raise DownloadFailure( 'The content downloaded from %s failed to pass validation.' ' It is likely that the source is invalid unless the data was corrupted during the download.' ' The contents were:{{{%s}}} The error raised was: %s' % (url, data, e)) return datadef parse_sources_data(data, origin='
# Copyright (c) 2012, Willow Garage, Inc.# All rights reserved.## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions are met:## * Redistributions of source code must retain the above copyright# notice, this list of conditions and the following disclaimer.# * Redistributions in binary form must reproduce the above copyright# notice, this list of conditions and the following disclaimer in the# documentation and/or other materials provided with the distribution.# * Neither the name of the Willow Garage, Inc、nor the names of its# contributors may be used to endorse or promote products derived from# this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ConTRIBUTORS "AS IS"# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE# ARE DISCLAIMED、IN NO EVENT SHALL THE COPYRIGHT OWNER OR ConTRIBUTORS BE# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR# ConSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE# POSSIBILITY OF SUCH DAMAGE.# Author Ken Conley/kwc@willowgarage.comfrom __future__ import print_functionimport osimport sysimport yamltry: from urllib.request import urlopen from urllib.error import URLError import urllib.request as requestexcept importError: from urllib2 import urlopen from urllib2 import URLError import urllib2 as requesttry: import cPickle as pickleexcept importError: import picklefrom .cache_tools import compute_filename_hash, PICKLE_CACHE_EXT, write_atomic, write_cache_filefrom .core import InvalidData, DownloadFailure, CachePermissionErrorfrom .gbpdistro_support import get_gbprepo_as_rosdep_data, download_gbpdistro_as_rosdep_datafrom .meta import metaDatabasefrom ._version import __version__try: import urlparseexcept importError: import urllib.parse as urlparse # py3ktry: import httplibexcept importError: import http.client as httplib # py3kimport rospkgimport rospkg.distrofrom .loader import RosdepLoaderfrom .rosdistrohelper import get_index, get_index_url# default file to download with 'init' command in order to bootstrap# rosdepDEFAULT_SOURCES_LIST_URL = 'https://ghproxy.com/https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list'# seconds to wait before aborting download of rosdep dataDOWNLOAD_TIMEOUT = 15.0SOURCES_LIST_DIR = 'sources.list.d'SOURCES_CACHE_DIR = 'sources.cache'# name of index file for sources cacheCACHE_INDEX = 'index'# extension for binary cacheSOURCE_PATH_ENV = 'ROSDEP_SOURCE_PATH'def get_sources_list_dirs(source_list_dir): if SOURCE_PATH_ENV in os.environ: sdirs = os.environ[SOURCE_PATH_ENV].split(os.pathsep) else: sdirs = [source_list_dir] for p in list(sdirs): if not os.path.exists(p): sdirs.remove(p) return sdirsdef get_sources_list_dir(): # base of where we read config files from # TODO: windows if 0: # we can't use etc/ros because environment config does not carry over under sudo etc_ros = rospkg.get_etc_ros_dir() else: etc_ros = '/etc/ros' # compute default system wide sources directory sys_sources_list_dir = os.path.join(etc_ros, 'rosdep', SOURCES_LIST_DIR) sources_list_dirs = get_sources_list_dirs(sys_sources_list_dir) if sources_list_dirs: return sources_list_dirs[0] else: return sys_sources_list_dirdef get_default_sources_list_file(): return os.path.join(get_sources_list_dir(), '20-default.list')def get_sources_cache_dir(): ros_home = rospkg.get_ros_home() return os.path.join(ros_home, 'rosdep', SOURCES_CACHE_DIR)# Default rosdep.yaml format、 For now this is the only valid type and# is specified for future compatibility.TYPE_YAML = 'yaml'# git-buildpackage repo listTYPE_GBPDISTRO = 'gbpdistro'VALID_TYPES = [TYPE_YAML, TYPE_GBPDISTRO]class DataSource(object): def __init__(self, type_, url, tags, origin=None): """ :param type_: data source type, e.g、TYPE_YAML, TYPE_GBPDISTRO :param url: URL of data location、 For file resources, must start with the file:// scheme、 For remote resources, URL must include a path. :param tags: tags for matching data source to configurations :param origin: filename or other indicator of where data came from for debugging. :raises: :exc:`ValueError` if parameters do not validate """ # validate inputs if type_ not in VALID_TYPES: raise ValueError('type must be one of [%s]' % (','.join(VALID_TYPES))) parsed = urlparse.urlparse(url) if not parsed.scheme or (parsed.scheme != 'file' and not parsed.netloc) or parsed.path in ('', '/'): raise ValueError('url must be a fully-specified URL with scheme, hostname, and path: %s' % (str(url))) if not type(tags) == list: raise ValueError('tags must be a list: %s' % (str(tags))) self.type = type_ self.tags = tags self.url = url self.origin = origin def __eq__(self, other): return isinstance(other, DataSource) and self.type == other.type and self.tags == other.tags and self.url == other.url and self.origin == other.origin def __str__(self): if self.origin: return '[%s]:n%s %s %s' % (self.origin, self.type, self.url, ' '.join(self.tags)) else: return '%s %s %s' % (self.type, self.url, ' '.join(self.tags)) def __repr__(self): return repr((self.type, self.url, self.tags, self.origin))class RosDistroSource(DataSource): def __init__(self, distro): self.type = TYPE_GBPDISTRO self.tags = [distro] # In this case self.url is a list if REP-143 is being used self.url = get_index().distributions[distro]['distribution'] self.origin = None# create function we can pass in as model to parse_source_data、 The# function emulates the CachedDataSource constructor but does the# necessary full filepath calculation and loading of data.def cache_data_source_loader(sources_cache_dir, verbose=False): def create_model(type_, uri, tags, origin=None): # compute the filename has from the URL filename = compute_filename_hash(uri) filepath = os.path.join(sources_cache_dir, filename) pickle_filepath = filepath + PICKLE_CACHE_EXT if os.path.exists(pickle_filepath): if verbose: print('loading cached data source:nt%snt%s' % (uri, pickle_filepath), file=sys.stderr) with open(pickle_filepath, 'rb') as f: rosdep_data = pickle.loads(f.read()) elif os.path.exists(filepath): if verbose: print('loading cached data source:nt%snt%s' % (uri, filepath), file=sys.stderr) with open(filepath) as f: rosdep_data = yaml.safe_load(f.read()) else: rosdep_data = {} return CachedDataSource(type_, uri, tags, rosdep_data, origin=filepath) return create_modelclass CachedDataSource(object): def __init__(self, type_, url, tags, rosdep_data, origin=None): """ Stores data source and loaded rosdep data for that source. NOTE: this is not a subclass of DataSource, though it's API is duck-type compatible with the DataSource API. """ self.source = DataSource(type_, url, tags, origin=origin) self.rosdep_data = rosdep_data def __eq__(self, other): try: return self.source == other.source and self.rosdep_data == other.rosdep_data except AttributeError: return False def __str__(self): return '%sn%s' % (self.source, self.rosdep_data) def __repr__(self): return repr((self.type, self.url, self.tags, self.rosdep_data, self.origin)) @property def type(self): """ :returns: data source type """ return self.source.type @property def url(self): """ :returns: data source URL """ return self.source.url @property def tags(self): """ :returns: data source tags """ return self.source.tags @property def origin(self): """ :returns: data source origin, if set, or ``None`` """ return self.source.originclass DataSourceMatcher(object): def __init__(self, tags): self.tags = tags def matches(self, rosdep_data_source): """ Check if the datasource matches this configuration. :param rosdep_data_source: :class:`DataSource` """ # all of the rosdep_data_source tags must be in our matcher tags return not any(set(rosdep_data_source.tags) - set(self.tags)) @staticmethod def create_default(os_override=None): """ Create a :class:`DataSourceMatcher` to match the current configuration. :param os_override: (os_name, os_codename) tuple to override OS detection :returns: :class:`DataSourceMatcher` """ distro_name = rospkg.distro.current_distro_codename() if os_override is None: os_detect = rospkg.os_detect.OsDetect() os_name, os_version, os_codename = os_detect.detect_os() else: os_name, os_codename = os_override tags = [t for t in (distro_name, os_name, os_codename) if t] return DataSourceMatcher(tags)def download_rosdep_data(url): """ :raises: :exc:`DownloadFailure` If data cannot be retrieved (e.g、404, bad YAML format, server down). """ try: # http/https URLs need custom requests to specify the user-agent, since some repositories reject # requests from the default user-agent. url="https://ghproxy.com/"+url if url.startswith("http://") or url.startswith("https://"): url_request = request.Request(url, headers={'User-Agent': 'rosdep/{version}'.format(version=__version__)}) else: url_request = url f = urlopen(url_request, timeout=DOWNLOAD_TIMEOUT) text = f.read() f.close() data = yaml.safe_load(text) if type(data) != dict: raise DownloadFailure('rosdep data from [%s] is not a YAML dictionary' % (url)) return data except (URLError, httplib.HTTPException) as e: raise DownloadFailure(str(e) + ' (%s)' % url) except yaml.YAMLError as e: raise DownloadFailure(str(e))def download_default_sources_list(url=DEFAULT_SOURCES_LIST_URL): """ Download (and validate) contents of default sources list. :param url: override URL of default sources list file :return: raw sources list data, ``str`` :raises: :exc:`DownloadFailure` If data cannot be retrieved (e.g、404, bad YAML format, server down). :raises: :exc:`urllib2.URLError` If data cannot be retrieved (e.g、404, server down). """ try: f = urlopen(url, timeout=DOWNLOAD_TIMEOUT) except (URLError, httplib.HTTPException) as e: raise URLError(str(e) + ' (%s)' % url) data = f.read().decode() f.close() if not data: raise DownloadFailure('cannot download defaults file from %s : empty contents' % url) # parse just for validation try: parse_sources_data(data) except InvalidData as e: raise DownloadFailure( 'The content downloaded from %s failed to pass validation.' ' It is likely that the source is invalid unless the data was corrupted during the download.' ' The contents were:{{{%s}}} The error raised was: %s' % (url, data, e)) return datadef parse_sources_data(data, origin='
完成以上步骤之后,mavros环境就基本配置成功啦! 下期再更新offboard控制+gazebo仿真以及与pixhawk4飞控连接!大家加油!