ubuntu20.04安装ros Noetic Ninjemys教程及部分问题汇总
双系统或者虚拟机都可用这种方法安装,亲测有效
参考博主:https://www.bilibili.com/read/cv13788562/
制作Ubuntu启动U盘和相关的安装比较简单,不在这儿讲了
1:准备工作:
一定要把Ubuntu里面的软件更新里面的网址改为阿里云镜像的,不然后续安装慢,容易time out,如图: 源代码那一框可不勾选
2:添加源
之前版本的源文件应该有问题,看网上大佬说是不适配Ubuntu20.04,打开终端。输入:
sudo gedit /etc/apt/sources.list
可以点出一个文件,在文件最下面添加下面代码,如果不进行添加的话会在第四步出现更新失败或者错误
#添加阿里源
deb http:
deb-src http:
deb http:
deb-src http:
deb http:
deb-src http:
deb http:
deb-src http:
deb http:
deb-src http:
3:更新源
sudo apt-get update
4:更新软件
sudo apt-get upgrade
5:安装清华源
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'
6:设置秘钥
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
7:运行一下更新
sudo apt update
8:安装ros-noetic版本
在网上看到不同版本其支持的ros版本不同,Ubuntu20.04支持ros-noetic
sudo apt install ros-noetic-desktop-full
9:设置环境变量
每次在Ubuntu用右键打开一个新的终端都需要进行这个设置,但如果使用终端框左上角的小加号则不用
source /opt/ros/noetic/setup.bash
大佬说下面的命令是可以在每次启动新的shell窗口时很方便地为你自动source一下这个脚本。
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrcsource ~/.bashrc
10:构建依赖关系
这个也是在每个终端打开的时候进行设置,不然有时候报错找不到相关命令,如果按照终端提示进行一些软件的安装和下载后运行相关的指令还是会无法创建,报错依赖关系相关的错误
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
11:初始化 rosdep
sudo apt install python3-rosdep
12: 运行rosdep init
12.1: 运行rosdep init成功
sudo rosdep init
关于这个命令一般不会出错,我第一次安装的是双系统,没有报错,然后安装的VMware虚拟机,报错了,如果没报错是让你运行rosdep update,直接转入运行rosdep update,如果报错进行以下修改
12.2:运行rosdep init失败
12.2.1:打开host及相关文件进行修改
进入hosts,打开文件
sudo gedit /etc/hosts
在ipv4的部分加入
185.199.108.133 raw.githubusercontent.com
185.199.109.133 raw.githubusercontent.com
185.199.110.133 raw.githubusercontent.com
185.199.111.133 raw.githubusercontent.com
保存后退出
12.2.2:再次运行sudo rosdep init
sudo rosdep init
如果还是不行,切换个网络,比如手机热点再试几次
13: 运行rosdep update
rosdep update
13.1:如果运行rosdep update报错
13.1.1如果报错超时
一般报错为:The read operation timed out。 具体思路是下载报错内容20-default.list里面的5个网址,我们可以把这一步需要访问的包先下载下来,然后修改20-default.list文件,使其指向我们本地下载好的文件,离线更新,具体步骤如下:
1. 通过git clone将安装包下载:(要先安装git软件)
git clone https:
若下载较慢,可以通过访问Github镜像下载:
git clone https:
(这个网址我一般是无法访问) 到这一步会在Ubuntu下载一个rosdistro文件夹,需要进入根目录右键终端打开输入pwd 查看路径,后面要用最好记住你自己的路径比如我的: /home/linder/DeskTop/rosdistro,大大们要自己查看路径别搞错了
2. 修改rep3.py
进入路径
cd /usr/lib/python3/dist-packages
如果已经是在这个路径下,会提示找不到,大大们注意观察 调出rep3.py文件
sudo gedit rosdep2/rep3.py
原文件
# 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 urlopen
except ImportError:
from urllib2 import urlopen
import yaml
import warnings
from .core import DownloadFailure
from .rosdistrohelper import PreRep137Warning
# location of targets file for processing gbpdistro files
REP3_TARGETS_URL = 'https:
# seconds to wait before aborting download of gbpdistro data
DOWNLOAD_TIMEOUT = 15.0
def 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:\n\t%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
将原来的 REP3_TARGETS_URL = 'https://raw.githubusercontent.com/ros/rosdistro/master/releases/targets.yaml’用 # 注释掉,修改成以下代码,主要是把你的文件路径进行替换,下面的文件路径是我装的时候的路径,大家注意,大家注意,大家注意
REP3_TARGETS_URL = 'file: /home/linder/DeskTop/rosdistro/releases/targets.yaml'
保存并关闭
2. 修改sources_list.py
调出sources_list.py 文件
sudo gedit rosdep2/sources_list.py
原文件
# 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.com
from __future__ import print_function
import os
import sys
import yaml
try:
from urllib.request import urlopen
from urllib.error import URLError
import urllib.request as request
except ImportError:
from urllib2 import urlopen
from urllib2 import URLError
import urllib2 as request
try:
import cPickle as pickle
except ImportError:
import pickle
from .cache_tools import compute_filename_hash, PICKLE_CACHE_EXT, write_atomic, write_cache_file
from .core import InvalidData, DownloadFailure, CachePermissionError
from .gbpdistro_support import get_gbprepo_as_rosdep_data, download_gbpdistro_as_rosdep_data
from .meta import MetaDatabase
from ._version import __version__
try:
import urlparse
except ImportError:
import urllib.parse as urlparse # py3k
try:
import httplib
except ImportError:
import http.client as httplib # py3k
import rospkg
import rospkg.distro
from .loader import RosdepLoader
from .rosdistrohelper import get_index, get_index_url
# default file to download with 'init' command in order to bootstrap
# rosdep
DEFAULT_SOURCES_LIST_URL = 'https:
# seconds to wait before aborting download of rosdep data
DOWNLOAD_TIMEOUT = 15.0
SOURCES_LIST_DIR = 'sources.list.d'
SOURCES_CACHE_DIR = 'sources.cache'
# name of index file for sources cache
CACHE_INDEX = 'index'
# extension for binary cache
SOURCE_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 sdirs
def 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_dir
def 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 list
TYPE_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:
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:\n\t%s\n\t%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:\n\t%s\n\t%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_model
class 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 '%s\n%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.origin
class 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.
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 data
def parse_sources_data(data, origin='<string>', model=None):
"""
Parse sources file format (tags optional)::
# comments and empty lines allowed
<type> <uri> [tags]
e.g.::
yaml http:
If tags are specified, *all* tags must match the current
configuration for the sources data to be used.
:param data: data in sources file format
:param model: model to load data into. Defaults to :class:`DataSource`
:returns: List of data sources, [:class:`DataSource`]
:raises: :exc:`InvalidData`
"""
if model is None:
model = DataSource
sources = []
for line in data.split('\n'):
line = line.strip()
# ignore empty lines or comments
if not line or line.startswith('#'):
continue
splits = line.split(' ')
if len(splits) < 2:
raise InvalidData('invalid line:\n%s' % (line), origin=origin)
type_ = splits[0]
url = splits[1]
tags = splits[2:]
try:
sources.append(model(type_, url, tags, origin=origin))
except ValueError as e:
raise InvalidData('line:\n\t%s\n%s' % (line, e), origin=origin)
return sources
def parse_sources_file(filepath):
"""
Parse file on disk
:returns: List of data sources, [:class:`DataSource`]
:raises: :exc:`InvalidData` If any error occurs reading
file, so an I/O error, non-existent file, or invalid format.
"""
try:
with open(filepath, 'r') as f:
return parse_sources_data(f.read(), origin=filepath)
except IOError as e:
raise InvalidData('I/O error reading sources file: %s' % (str(e)), origin=filepath)
def parse_sources_list(sources_list_dir=None):
"""
Parse data stored in on-disk sources list directory into a list of
:class:`DataSource` for processing.
:returns: List of data sources, [:class:`DataSource`]. If there is
no sources list dir, this returns an empty list.
:raises: :exc:`InvalidData`
:raises: :exc:`OSError` if *sources_list_dir* cannot be read.
:raises: :exc:`IOError` if *sources_list_dir* cannot be read.
"""
if sources_list_dir is None:
sources_list_dir = get_sources_list_dir()
sources_list_dirs = get_sources_list_dirs(sources_list_dir)
filelist = []
for sdir in sources_list_dirs:
filelist += sorted([os.path.join(sdir, f) for f in os.listdir(sdir) if f.endswith('.list')])
sources_list = []
for f in filelist:
sources_list.extend(parse_sources_file(f))
return sources_list
def _generate_key_from_urls(urls):
# urls may be a list of urls or a single string
try:
assert isinstance(urls, (list, basestring))
except NameError:
assert isinstance(urls, (list, str))
# We join the urls by the '^' character because it is not allowed in urls
return '^'.join(urls if isinstance(urls, list) else [urls])
def update_sources_list(sources_list_dir=None, sources_cache_dir=None,
success_handler=None, error_handler=None,
skip_eol_distros=False, ros_distro=None):
"""
Re-downloaded data from remote sources and store in cache. Also
update the cache index based on current sources.
:param sources_list_dir: override source list directory
:param sources_cache_dir: override sources cache directory
:param success_handler: fn(DataSource) to call if a particular
source loads successfully. This hook is mainly for printing
errors to console.
:param error_handler: fn(DataSource, DownloadFailure) to call
if a particular source fails. This hook is mainly for
printing errors to console.
:param skip_eol_distros: skip downloading sources for EOL distros
:returns: list of (`DataSource`, cache_file_path) pairs for cache
files that were updated, ``[str]``
:raises: :exc:`InvalidData` If any of the sources list files is invalid
:raises: :exc:`OSError` if *sources_list_dir* cannot be read.
:raises: :exc:`IOError` If *sources_list_dir* cannot be read or cache data cannot be written
"""
if sources_cache_dir is None:
sources_cache_dir = get_sources_cache_dir()
sources = parse_sources_list(sources_list_dir=sources_list_dir)
retval = []
for source in list(sources):
try:
if source.type == TYPE_YAML:
rosdep_data = download_rosdep_data(source.url)
elif source.type == TYPE_GBPDISTRO: # DEPRECATED, do not use this file. See REP137
if not source.tags[0] in ['electric', 'fuerte']:
print('Ignore legacy gbpdistro "%s"' % source.tags[0])
sources.remove(source)
continue # do not store this entry in the cache
rosdep_data = download_gbpdistro_as_rosdep_data(source.url)
retval.append((source, write_cache_file(sources_cache_dir, source.url, rosdep_data)))
if success_handler is not None:
success_handler(source)
except DownloadFailure as e:
if error_handler is not None:
error_handler(source, e)
# Additional sources for ros distros
# In compliance with REP137 and REP143
python_versions = {}
print('Query rosdistro index %s' % get_index_url())
distribution_names = get_index().distributions.keys()
if ros_distro is not None and ros_distro not in distribution_names:
raise ValueError(
'Requested distribution "%s" is not in the index.' % ros_distro)
for dist_name in sorted(distribution_names):
distribution = get_index().distributions[dist_name]
if dist_name != ros_distro:
if ros_distro is not None:
print('Skip distro "%s" different from requested "%s"' % (dist_name, ros_distro))
continue
if skip_eol_distros:
if distribution.get('distribution_status') == 'end-of-life':
print('Skip end-of-life distro "%s"' % dist_name)
continue
print('Add distro "%s"' % dist_name)
rds = RosDistroSource(dist_name)
rosdep_data = get_gbprepo_as_rosdep_data(dist_name)
# Store Python version from REP153
if distribution.get('python_version'):
python_versions[dist_name] = distribution.get('python_version')
# dist_files can either be a string (single filename) or a list (list of filenames)
dist_files = distribution['distribution']
key = _generate_key_from_urls(dist_files)
retval.append((rds, write_cache_file(sources_cache_dir, key, rosdep_data)))
sources.append(rds)
# cache metadata that isn't a source list
MetaDatabase().set('ROS_PYTHON_VERSION', python_versions)
# Create a combined index of *all* the sources. We do all the
# sources regardless of failures because a cache from a previous
# attempt may still exist. We have to do this cache index so that
# loads() see consistent data.
if not os.path.exists(sources_cache_dir):
os.makedirs(sources_cache_dir)
cache_index = os.path.join(sources_cache_dir, CACHE_INDEX)
data = "#autogenerated by rosdep, do not edit. use 'rosdep update' instead\n"
for source in sources:
url = _generate_key_from_urls(source.url)
data += 'yaml %s %s\n' % (url, ' '.join(source.tags))
write_atomic(cache_index, data)
# mainly for debugging and testing
return retval
def load_cached_sources_list(sources_cache_dir=None, verbose=False):
"""
Load cached data based on the sources list.
:returns: list of :class:`CachedDataSource` instance with raw
rosdep data loaded.
:raises: :exc:`OSError` if cache cannot be read
:raises: :exc:`IOError` if cache cannot be read
"""
if sources_cache_dir is None:
sources_cache_dir = get_sources_cache_dir()
cache_index = os.path.join(sources_cache_dir, 'index')
if not os.path.exists(cache_index):
if verbose:
print('no cache index present, not loading cached sources', file=sys.stderr)
return []
try:
with open(cache_index, 'r') as f:
cache_data = f.read()
except IOError as e:
if e.strerror == 'Permission denied':
raise CachePermissionError('Failed to write cache file: ' + str(e))
else:
raise
# the loader does all the work
model = cache_data_source_loader(sources_cache_dir, verbose=verbose)
return parse_sources_data(cache_data, origin=cache_index, model=model)
class SourcesListLoader(RosdepLoader):
"""
SourcesList loader implements the general RosdepLoader API. This
implementation is fairly simple as there is only one view the
source list loader can create. It is also a bit degenerate as it
is not capable of mapping resource names to views, thus any
resource-name-based API fails or returns nothing interesting.
This loader should not be used directly; instead, it is more
useful composed with other higher-level implementations, like the
:class:`rosdep2.rospkg_loader.RospkgLoader`. The general intent
is to compose it with another loader by making all of the other
loader's views depends on all the views in this loader.
"""
ALL_VIEW_KEY = 'sources.list'
def __init__(self, sources):
"""
:param sources: cached sources list entries, [:class:`CachedDataSource`]
"""
self.sources = sources
@staticmethod
def create_default(matcher=None, sources_cache_dir=None, os_override=None, verbose=False):
"""
:param matcher: override DataSourceMatcher. Defaults to
DataSourceMatcher.create_default().
:param sources_cache_dir: override location of sources cache
"""
if matcher is None:
matcher = DataSourceMatcher.create_default(os_override=os_override)
if verbose:
print('using matcher with tags [%s]' % (', '.join(matcher.tags)), file=sys.stderr)
sources = load_cached_sources_list(sources_cache_dir=sources_cache_dir, verbose=verbose)
if verbose:
print('loaded %s sources' % (len(sources)), file=sys.stderr)
sources = [x for x in sources if matcher.matches(x)]
if verbose:
print('%s sources match current tags' % (len(sources)), file=sys.stderr)
return SourcesListLoader(sources)
def load_view(self, view_name, rosdep_db, verbose=False):
"""
Load view data into rosdep_db. If the view has already been
loaded into rosdep_db, this method does nothing.
:param view_name: name of ROS stack to load, ``str``
:param rosdep_db: database to load stack data into, :class:`RosdepDatabase`
:raises: :exc:`InvalidData`
"""
if rosdep_db.is_loaded(view_name):
return
source = self.get_source(view_name)
if verbose:
print('loading view [%s] with sources.list loader' % (view_name), file=sys.stderr)
view_dependencies = self.get_view_dependencies(view_name)
rosdep_db.set_view_data(view_name, source.rosdep_data, view_dependencies, view_name)
def get_loadable_resources(self):
return []
def get_loadable_views(self):
return [x.url for x in self.sources]
def get_view_dependencies(self, view_name):
# use dependencies to implement precedence
if view_name != SourcesListLoader.ALL_VIEW_KEY:
# if the view_name matches one of our sources, return
# empty list as none of our sources has deps.
if any([x for x in self.sources if view_name == x.url]):
return []
# not one of our views, so it depends on everything we provide
return [x.url for x in self.sources]
def get_source(self, view_name):
matches = [x for x in self.sources if x.url == view_name]
if matches:
return matches[0]
else:
raise rospkg.ResourceNotFound(view_name)
def get_rosdeps(self, resource_name, implicit=True):
"""
Always raises as SourceListLoader defines no concrete resources with rosdeps.
:raises: :exc:`rospkg.ResourceNotFound`
"""
raise rospkg.ResourceNotFound(resource_name)
def get_view_key(self, resource_name):
"""
Always raises as SourceListLoader defines no concrete resources with rosdeps.
:returns: Name of view that *resource_name* is in, ``None`` if no associated view.
:raises: :exc:`rospkg.ResourceNotFound` if *resource_name* cannot be found.
"""
raise rospkg.ResourceNotFound(resource_name)
将原来的这一行代码修改成以下这种,注意改成自己的路径,注意改成自己的路径,注意改成自己的路径
DEFAULT_SOURCES_LIST_URL = 'file: /home/linderven/DeskTop/rosdistro/rosdep/sources.list.d/20-default.list'
保存并关闭
2. 修改__init__.py
sudo gedit rosdistro/__init__.py
原文件
# Software License Agreement (BSD License)
#
# Copyright (c) 2013, Open Source Robotics Foundation, 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 Open Source Robotics Foundation, 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.
from __future__ import print_function
import gzip
import logging
import os
try:
from cStringIO import StringIO
except ImportError:
from io import BytesIO as StringIO
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
import yaml
logger = logging.getLogger('rosdistro')
from .distribution import Distribution # noqa
from .distribution_cache import DistributionCache # noqa
from .distribution_file import DistributionFile # noqa
from .distribution_file import create_distribution_file # noqa
from .external.appdirs import site_config_dir, user_config_dir # noqa
from .index import Index # noqa
from .loader import load_url # noqa
from .manifest_provider.cache import CachedManifestProvider, CachedSourceManifestProvider # noqa
# same version as in:
# - setup.py
# - stdeb.cfg
__version__ = '0.8.3'
# index information
DEFAULT_INDEX_URL = 'https:
def get_index_url():
# environment variable has precedence over configuration files
if 'ROSDISTRO_INDEX_URL' in os.environ:
return os.environ['ROSDISTRO_INDEX_URL']
def read_cfg_index_url(fname):
try:
with open(fname) as f:
return yaml.safe_load(f.read())['index_url']
except (IOError, KeyError, yaml.YAMLError):
return None
cfg_file = 'config.yaml'
# first, look for the user configuration (usually ~/.config/rosdistro)
user_cfg_path = os.path.join(user_config_dir('rosdistro'), cfg_file)
index_url = read_cfg_index_url(user_cfg_path)
if index_url is not None:
return index_url
# if not found, look for the global configuration *usually /etc/xdg/rosdistro)
site_cfg_paths = os.path.join(site_config_dir('rosdistro', multipath=True), cfg_file).split(os.pathsep)
for site_cfg_path in site_cfg_paths:
index_url = read_cfg_index_url(site_cfg_path)
if index_url is not None:
return index_url
# if nothing is found, use the default
return DEFAULT_INDEX_URL
def get_index(url):
logger.debug('Load index from "%s"' % url)
yaml_str = load_url(url)
data = yaml.safe_load(yaml_str)
base_url = os.path.dirname(url)
url_parts = urlparse(url)
return Index(data, base_url, url_query=url_parts.query)
# distribution information
def get_distribution(index, dist_name):
dist_file = get_distribution_file(index, dist_name)
return Distribution(dist_file)
def get_distribution_file(index, dist_name):
data = _get_dist_file_data(index, dist_name, 'distribution')
return create_distribution_file(dist_name, data)
def get_distribution_files(index, dist_name):
data = _get_dist_file_data(index, dist_name, 'distribution')
if not isinstance(data, list):
data = [data]
dist_files = []
for d in data:
dist_file = DistributionFile(dist_name, d)
dist_files.append(dist_file)
return dist_files
def get_cached_distribution(index, dist_name, cache=None, allow_lazy_load=False):
if cache is None:
try:
cache = get_distribution_cache(index, dist_name)
except Exception:
if not allow_lazy_load:
raise
# create empty cache instance
dist_file_data = _get_dist_file_data(index, dist_name, 'distribution')
cache = DistributionCache(dist_name, distribution_file_data=dist_file_data)
dist = Distribution(
cache.distribution_file,
[CachedManifestProvider(cache, Distribution.default_manifest_providers if allow_lazy_load else None)],
[CachedSourceManifestProvider(cache, Distribution.default_source_manifest_providers if allow_lazy_load else None)])
assert cache.distribution_file.name == dist_name
return dist
def get_distribution_cache_string(index, dist_name):
if dist_name not in index.distributions.keys():
raise RuntimeError("Unknown distribution: '{0}'. Valid distribution names are: {1}".format(dist_name, ', '.join(sorted(index.distributions.keys()))))
dist = index.distributions[dist_name]
if 'distribution_cache' not in dist.keys():
raise RuntimeError("Distribution has no cache: '{0}'".format(dist_name))
url = dist['distribution_cache']
logger.debug('Load cache from "%s"' % url)
if url.endswith('.yaml'):
yaml_str = load_url(url)
elif url.endswith('.yaml.gz'):
yaml_gz_str = load_url(url, skip_decode=True)
yaml_gz_stream = StringIO(yaml_gz_str)
f = gzip.GzipFile(fileobj=yaml_gz_stream, mode='rb')
yaml_str = f.read()
f.close()
if not isinstance(yaml_str, str):
yaml_str = yaml_str.decode('utf-8')
else:
raise NotImplementedError('The url of the cache must end with either ".yaml" or ".yaml.gz"')
return yaml_str
def get_distribution_cache(index, dist_name):
yaml_str = get_distribution_cache_string(index, dist_name)
data = yaml.safe_load(yaml_str)
return DistributionCache(dist_name, data)
# internal
def _get_dist_file_data(index, dist_name, type_):
if dist_name not in index.distributions.keys():
raise RuntimeError("Unknown release: '{0}'. Valid release names are: {1}".format(dist_name, ', '.join(sorted(index.distributions.keys()))))
dist = index.distributions[dist_name]
if type_ not in dist.keys():
raise RuntimeError('unknown release type "%s"' % type_)
url = dist[type_]
def _load_yaml_data(url):
logger.debug('Load file from "%s"' % url)
yaml_str = load_url(url)
return yaml.safe_load(yaml_str)
if not isinstance(url, list):
data = _load_yaml_data(url)
else:
data = []
for u in url:
data.append(_load_yaml_data(u))
return data
from .legacy import * # noqa
同理,注意改路径,注意改路径,注意改路径
DEFAULT_INDEX_URL = 'file:/home/linderven/DeskTop/rosdistro/index-v4.yaml'
3:修改20-default.list
cd /etc/ros/rosdep/sources.list.d
sudo gedit 20-default.list
原文件
# os-specific listings first
yaml https:
# generic
yaml https:
yaml https:
yaml https:
gbpdistro https:
# newer distributions (Groovy, Hydro, ...) must not be listed anymore, they are being fetched from the rosdistro index.yaml instead
修改后文件(/home/linderven/DeskTop/rosdistro/rosdep)
# os-specific listings first
yaml file: /home/linderven/DeskTop/rosdistro/rosdep/osx-homebrew.yaml osx
# generic
yaml file: /home/linderven/DeskTop/rosdistro/rosdep/base.yaml
yaml file: /home/linderven/DeskTop/rosdistro/rosdep/python.yaml
yaml file: /home/linderven/DeskTop/rosdistro/rosdep/ruby.yaml
gbpdistro file: /home/linderven/DeskTop/rosdistro/releases/fuerte.yaml fuerte
也是进行路径修改
13.1.2如果报错路径
从之前那个环境变量配置那儿重新配置一下,一般是运行下面两行
source /opt/ros/noetic/setup.bash
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrcsource ~/.bashrc
13.2:如果运行rosdep update成功
13.2.1:运行rosdep update成功后 ,终端显示结果:
inderven@linderVen:/etc/ros/rosdep/sources.list.d$ rosdep update
reading in sources list data from /etc/ros/rosdep/sources.list.d
Hit https:
Hit https:
Hit https:
Hit https:
Hit https:
Query rosdistro index file:/home/linderven/DeskTop/rosdistro/index-v4.yaml
Skip end-of-life distro "ardent"
Skip end-of-life distro "bouncy"
Skip end-of-life distro "crystal"
Skip end-of-life distro "dashing"
Skip end-of-life distro "eloquent"
Add distro "foxy"
Add distro "galactic"
Skip end-of-life distro "groovy"
Skip end-of-life distro "hydro"
Skip end-of-life distro "indigo"
Skip end-of-life distro "jade"
Skip end-of-life distro "kinetic"
Skip end-of-life distro "lunar"
Add distro "melodic"
Add distro "noetic"
Add distro "rolling"
updated cache in /home/linderven/.ros/rosdep/sources.cache
linderven@linderVen:/etc/ros/rosdep/sources.list.d$
接着进行14步
14:运行roscore
roscore
结果:
linderven@linderVen:/etc/ros/rosdep/sources.list.d$ roscore
... logging to /home/linderven/.ros/log/0ce2d1fa-b09b-11ec-9fb7-fbefee69b858/roslaunch-linderVen-52942.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http:
ros_comm version 1.15.14
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.15.14
NODES
auto-starting new master
process[master]: started with pid [52952]
ROS_MASTER_URI=http:
setting /run_id to 0ce2d1fa-b09b-11ec-9fb7-fbefee69b858
process[rosout-1]: started with pid [52962]
started core service [/rosout]
15:新打开一个终端运行turtlesim_node
输入
rosrun turtlesim turtlesim_node
如果报错找不到命令,重新配置一下环境变量,然后运行,如下
source /opt/ros/noetic/setup.bash
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrcsource ~/.bashrc
rosrun turtlesim turtlesim_node
结果
linderven@linderVen:/etc/ros/rosdep/sources.list.d$ rosrun turtlesim turtlesim_node
[ INFO] [1648694267.602281083]: Starting turtlesim with node name /turtlesim
[ INFO] [1648694267.606405459]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
16:再打开一个终端运行turtle_teleop_key,调出控制键盘
输入
rosrun turtlesim turtle_teleop_key
结果
linder@linder:~/桌面$ source /opt/ros/noetic/setup.bash
linder@linder:~/桌面$ echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrcsource ~/.bashrc
linder@linder:~/桌面$ rosrun turtlesim turtle_teleop_key
Reading from keyboard
---------------------------
Use arrow keys to move the turtle. 'q' to quit.
点击一下,用方向键控制
17:操作小乌龟
注意,鼠标要放在调出的turtle_teleop_key终端上,然后用方向键控制
其他错误(建议先看一下)
如果第一次运行rosdep init 成功,后面再运行的时候提示文件已经存在,则运行下列代码:
sudo rm /etc/ros/rosdep/sources.list.d/20-default.list
然后再运行 rosdep init
如果报错路径或者某些命令找不到的话,可以尝试重新配置下环境变量
source /opt/ros/noetic/setup.bash
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrcsource ~/.bashrc
最后感谢大佬 作者:被打愣的猫 https://www.bilibili.com/read/cv13788562/ 出处:bilibili 大家可以去总结一下经验
|