mirror of
https://github.com/CopterExpress/clover.git
synced 2026-06-07 18:14:32 +00:00
Compare commits
77 Commits
known_vert
...
bullseye
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6defbea453 | ||
|
|
9e8470a3cb | ||
|
|
e9cd3d917c | ||
|
|
373cefb01c | ||
|
|
d0039ea23f | ||
|
|
bd25818aa7 | ||
|
|
a73457c5c5 | ||
|
|
c8a4d49577 | ||
|
|
123379b60e | ||
|
|
71d3144691 | ||
|
|
d306a9d96d | ||
|
|
1d514cf5ca | ||
|
|
96adadeae9 | ||
|
|
a1061ff32c | ||
|
|
e9d13b865c | ||
|
|
b655a4274e | ||
|
|
d58a59afab | ||
|
|
d0fabd8b3e | ||
|
|
b50207e5e9 | ||
|
|
97797a9178 | ||
|
|
1e8569b664 | ||
|
|
21cc47eecb | ||
|
|
4c56adafb2 | ||
|
|
8a524a8aa5 | ||
|
|
5493445747 | ||
|
|
0ef26334dc | ||
|
|
8d83e8faa3 | ||
|
|
9b90214d9d | ||
|
|
224f6cee27 | ||
|
|
ff04b2fb75 | ||
|
|
473444ae33 | ||
|
|
168734ad8c | ||
|
|
4e7b2e379a | ||
|
|
ad1d51fd9e | ||
|
|
57c415db22 | ||
|
|
568386a758 | ||
|
|
55f8f4fa1a | ||
|
|
dd0dd6b5c1 | ||
|
|
4c40bea226 | ||
|
|
6b3f5c3690 | ||
|
|
63067823ee | ||
|
|
880f67c3bc | ||
|
|
839aeb6a26 | ||
|
|
b123585756 | ||
|
|
fa4757a4c8 | ||
|
|
28d77aea33 | ||
|
|
0425e1da24 | ||
|
|
692d424a0b | ||
|
|
1c9fd7b126 | ||
|
|
a1752c1642 | ||
|
|
0dbd2d1048 | ||
|
|
79408861a2 | ||
|
|
063f2c3c13 | ||
|
|
68819bbd34 | ||
|
|
3a5c3d5bb4 | ||
|
|
032eb52a88 | ||
|
|
7dc24437cf | ||
|
|
1ccb756931 | ||
|
|
b5268a7b62 | ||
|
|
a0663d6b36 | ||
|
|
26f2c966ff | ||
|
|
4517186862 | ||
|
|
5236afe035 | ||
|
|
fe1707d0c3 | ||
|
|
03854d2589 | ||
|
|
28339e65af | ||
|
|
e11f0cf054 | ||
|
|
c1045cd11e | ||
|
|
aa3373da58 | ||
|
|
a4ad408228 | ||
|
|
0d436637cd | ||
|
|
18daff1044 | ||
|
|
b96d17a746 | ||
|
|
1506d3fd96 | ||
|
|
eec0833707 | ||
|
|
f9883baa87 | ||
|
|
3bebecf91e |
7
.github/workflows/docs.yml
vendored
7
.github/workflows/docs.yml
vendored
@@ -11,6 +11,10 @@ permissions:
|
|||||||
pages: write
|
pages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -71,9 +75,6 @@ jobs:
|
|||||||
|
|
||||||
deploy-docs:
|
deploy-docs:
|
||||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
concurrency:
|
|
||||||
group: "pages"
|
|
||||||
cancel-in-progress: true
|
|
||||||
environment:
|
environment:
|
||||||
name: github-pages
|
name: github-pages
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ It's recommended to run it within the same nodelet manager with the camera nodel
|
|||||||
* `~frame_id_prefix` (*string*) – prefix for TF transforms names, marker's ID is appended (default: `aruco_`)
|
* `~frame_id_prefix` (*string*) – prefix for TF transforms names, marker's ID is appended (default: `aruco_`)
|
||||||
* `~length` (*double*) – markers' sides length
|
* `~length` (*double*) – markers' sides length
|
||||||
* `~length_override` (*map*) – lengths of markers with specified ids
|
* `~length_override` (*map*) – lengths of markers with specified ids
|
||||||
* `~known_vertical` (*string*) – known vertical (Z axis) of all the markers as a frame
|
* `~known_tilt` (*string*) – known tilt (pitch and roll) of all the markers as a frame
|
||||||
* `~flip_vertical` – flip vertical vector
|
|
||||||
|
|
||||||
### Topics
|
### Topics
|
||||||
|
|
||||||
@@ -72,8 +71,7 @@ It's recommended to run it within the same nodelet manager with the camera nodel
|
|||||||
|
|
||||||
* `~map` – path to text file with markers list
|
* `~map` – path to text file with markers list
|
||||||
* `~frame_id` – published frame id (default: `aruco_map`)
|
* `~frame_id` – published frame id (default: `aruco_map`)
|
||||||
* `~known_vertical` – known vertical (Z axis) of markers map as a frame
|
* `~known_tilt` – known tilt (pitch and roll) of markers map as a frame
|
||||||
* `~flip_vertical` – flip vertical vector
|
|
||||||
* `~image_width` – debug image width (default: 2000)
|
* `~image_width` – debug image width (default: 2000)
|
||||||
* `~image_height` – debug image height (default: 2000)
|
* `~image_height` – debug image height (default: 2000)
|
||||||
* `~image_margin` – debug image margin (default: 200)
|
* `~image_margin` – debug image margin (default: 200)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<package format="3">
|
<package format="2">
|
||||||
<name>aruco_pose</name>
|
<name>aruco_pose</name>
|
||||||
<version>0.23.0</version>
|
<version>0.23.0</version>
|
||||||
<description>Positioning with ArUco markers</description>
|
<description>Positioning with ArUco markers</description>
|
||||||
@@ -28,8 +28,6 @@
|
|||||||
<depend>sensor_msgs</depend>
|
<depend>sensor_msgs</depend>
|
||||||
<depend>rostest</depend>
|
<depend>rostest</depend>
|
||||||
<depend>dynamic_reconfigure</depend>
|
<depend>dynamic_reconfigure</depend>
|
||||||
<depend condition="$ROS_PYTHON_VERSION == 2">python-docopt</depend>
|
|
||||||
<depend condition="$ROS_PYTHON_VERSION == 3">python3-docopt</depend>
|
|
||||||
|
|
||||||
<test_depend>image_publisher</test_depend>
|
<test_depend>image_publisher</test_depend>
|
||||||
<test_depend>ros_pytest</test_depend>
|
<test_depend>ros_pytest</test_depend>
|
||||||
|
|||||||
@@ -71,12 +71,11 @@ private:
|
|||||||
ros::Publisher markers_pub_, vis_markers_pub_;
|
ros::Publisher markers_pub_, vis_markers_pub_;
|
||||||
ros::Subscriber map_markers_sub_;
|
ros::Subscriber map_markers_sub_;
|
||||||
ros::ServiceServer set_markers_srv_;
|
ros::ServiceServer set_markers_srv_;
|
||||||
bool estimate_poses_, send_tf_, flip_vertical_, auto_flip_, use_map_markers_;
|
bool estimate_poses_, send_tf_, auto_flip_;
|
||||||
bool waiting_for_map_;
|
|
||||||
double length_;
|
double length_;
|
||||||
ros::Duration transform_timeout_;
|
ros::Duration transform_timeout_;
|
||||||
std::unordered_map<int, double> length_override_;
|
std::unordered_map<int, double> length_override_;
|
||||||
std::string frame_id_prefix_, known_vertical_;
|
std::string frame_id_prefix_, known_tilt_;
|
||||||
Mat camera_matrix_, dist_coeffs_;
|
Mat camera_matrix_, dist_coeffs_;
|
||||||
aruco_pose::MarkerArray array_;
|
aruco_pose::MarkerArray array_;
|
||||||
std::unordered_set<int> map_markers_ids_;
|
std::unordered_set<int> map_markers_ids_;
|
||||||
@@ -96,8 +95,6 @@ public:
|
|||||||
dictionary = nh_priv_.param("dictionary", 2);
|
dictionary = nh_priv_.param("dictionary", 2);
|
||||||
estimate_poses_ = nh_priv_.param("estimate_poses", true);
|
estimate_poses_ = nh_priv_.param("estimate_poses", true);
|
||||||
send_tf_ = nh_priv_.param("send_tf", true);
|
send_tf_ = nh_priv_.param("send_tf", true);
|
||||||
use_map_markers_ = nh_priv_.param("use_map_markers", false);
|
|
||||||
waiting_for_map_ = use_map_markers_;
|
|
||||||
if (estimate_poses_ && !nh_priv_.getParam("length", length_)) {
|
if (estimate_poses_ && !nh_priv_.getParam("length", length_)) {
|
||||||
NODELET_FATAL("can't estimate marker's poses as ~length parameter is not defined");
|
NODELET_FATAL("can't estimate marker's poses as ~length parameter is not defined");
|
||||||
ros::shutdown();
|
ros::shutdown();
|
||||||
@@ -105,8 +102,7 @@ public:
|
|||||||
readLengthOverride(nh_priv_);
|
readLengthOverride(nh_priv_);
|
||||||
transform_timeout_ = ros::Duration(nh_priv_.param("transform_timeout", 0.02));
|
transform_timeout_ = ros::Duration(nh_priv_.param("transform_timeout", 0.02));
|
||||||
|
|
||||||
known_vertical_ = nh_priv_.param("known_vertical", nh_priv_.param("known_tilt", std::string(""))); // known_tilt is an old name
|
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
|
||||||
flip_vertical_ = nh_priv_.param<bool>("flip_vertical", false);
|
|
||||||
auto_flip_ = nh_priv_.param("auto_flip", false);
|
auto_flip_ = nh_priv_.param("auto_flip", false);
|
||||||
|
|
||||||
frame_id_prefix_ = nh_priv_.param<std::string>("frame_id_prefix", "aruco_");
|
frame_id_prefix_ = nh_priv_.param<std::string>("frame_id_prefix", "aruco_");
|
||||||
@@ -137,7 +133,6 @@ private:
|
|||||||
void imageCallback(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr &cinfo)
|
void imageCallback(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr &cinfo)
|
||||||
{
|
{
|
||||||
if (!enabled_) return;
|
if (!enabled_) return;
|
||||||
if (waiting_for_map_) return;
|
|
||||||
|
|
||||||
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image;
|
Mat image = cv_bridge::toCvShare(msg, "bgr8")->image;
|
||||||
|
|
||||||
@@ -145,7 +140,7 @@ private:
|
|||||||
vector<vector<cv::Point2f>> corners, rejected;
|
vector<vector<cv::Point2f>> corners, rejected;
|
||||||
vector<cv::Vec3d> rvecs, tvecs;
|
vector<cv::Vec3d> rvecs, tvecs;
|
||||||
vector<cv::Point3f> obj_points;
|
vector<cv::Point3f> obj_points;
|
||||||
geometry_msgs::TransformStamped vertical;
|
geometry_msgs::TransformStamped snap_to;
|
||||||
|
|
||||||
// Detect markers
|
// Detect markers
|
||||||
cv::aruco::detectMarkers(image, dictionary_, corners, ids, parameters_, rejected);
|
cv::aruco::detectMarkers(image, dictionary_, corners, ids, parameters_, rejected);
|
||||||
@@ -180,12 +175,12 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!known_vertical_.empty()) {
|
if (!known_tilt_.empty()) {
|
||||||
try {
|
try {
|
||||||
vertical = tf_buffer_->lookupTransform(msg->header.frame_id, known_vertical_,
|
snap_to = tf_buffer_->lookupTransform(msg->header.frame_id, known_tilt_,
|
||||||
msg->header.stamp, transform_timeout_);
|
msg->header.stamp, transform_timeout_);
|
||||||
} catch (const tf2::TransformException& e) {
|
} catch (const tf2::TransformException& e) {
|
||||||
NODELET_WARN_THROTTLE(5, "can't retrieve known vertical: %s", e.what());
|
NODELET_WARN_THROTTLE(5, "can't snap: %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,9 +201,9 @@ private:
|
|||||||
if (estimate_poses_) {
|
if (estimate_poses_) {
|
||||||
fillPose(marker.pose, rvecs[i], tvecs[i]);
|
fillPose(marker.pose, rvecs[i], tvecs[i]);
|
||||||
|
|
||||||
// apply known vertical (if enabled and vertical frame available)
|
// snap orientation (if enabled and snap frame available)
|
||||||
if (!known_vertical_.empty() && !vertical.header.frame_id.empty()) {
|
if (!known_tilt_.empty() && !snap_to.header.frame_id.empty()) {
|
||||||
applyVertical(marker.pose.orientation, vertical.transform.rotation, false, auto_flip_);
|
snapOrientation(marker.pose.orientation, snap_to.transform.rotation, auto_flip_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_tf_) {
|
if (send_tf_) {
|
||||||
@@ -400,13 +395,7 @@ private:
|
|||||||
map_markers_ids_.clear();
|
map_markers_ids_.clear();
|
||||||
for (auto const& marker : msg.markers) {
|
for (auto const& marker : msg.markers) {
|
||||||
map_markers_ids_.insert(marker.id);
|
map_markers_ids_.insert(marker.id);
|
||||||
if (use_map_markers_) {
|
|
||||||
if (length_override_.find(marker.id) == length_override_.end()) {
|
|
||||||
length_override_[marker.id] = marker.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
waiting_for_map_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void paramCallback(aruco_pose::DetectorConfig &config, uint32_t level)
|
void paramCallback(aruco_pose::DetectorConfig &config, uint32_t level)
|
||||||
|
|||||||
@@ -81,9 +81,9 @@ private:
|
|||||||
bool enabled_ = true;
|
bool enabled_ = true;
|
||||||
std::string type_;
|
std::string type_;
|
||||||
visualization_msgs::MarkerArray vis_array_;
|
visualization_msgs::MarkerArray vis_array_;
|
||||||
std::string known_vertical_, map_, markers_frame_, markers_parent_frame_;
|
std::string known_tilt_, map_, markers_frame_, markers_parent_frame_;
|
||||||
int image_width_, image_height_, image_margin_;
|
int image_width_, image_height_, image_margin_;
|
||||||
bool flip_vertical_, auto_flip_, image_axis_;
|
bool auto_flip_, image_axis_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void onInit()
|
virtual void onInit()
|
||||||
@@ -104,8 +104,7 @@ public:
|
|||||||
|
|
||||||
type_ = nh_priv_.param<std::string>("type", "map");
|
type_ = nh_priv_.param<std::string>("type", "map");
|
||||||
transform_.child_frame_id = nh_priv_.param<std::string>("frame_id", "aruco_map");
|
transform_.child_frame_id = nh_priv_.param<std::string>("frame_id", "aruco_map");
|
||||||
known_vertical_ = nh_priv_.param("known_vertical", nh_priv_.param("known_tilt", std::string(""))); // known_tilt is an old name
|
known_tilt_ = nh_priv_.param<std::string>("known_tilt", "");
|
||||||
flip_vertical_ = nh_priv_.param<bool>("flip_vertical", false);
|
|
||||||
auto_flip_ = nh_priv_.param("auto_flip", false);
|
auto_flip_ = nh_priv_.param("auto_flip", false);
|
||||||
image_width_ = nh_priv_.param("image_width" , 2000);
|
image_width_ = nh_priv_.param("image_width" , 2000);
|
||||||
image_height_ = nh_priv_.param("image_height", 2000);
|
image_height_ = nh_priv_.param("image_height", 2000);
|
||||||
@@ -178,7 +177,7 @@ public:
|
|||||||
corners.push_back(marker_corners);
|
corners.push_back(marker_corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (known_vertical_.empty()) {
|
if (known_tilt_.empty()) {
|
||||||
// simple estimation
|
// simple estimation
|
||||||
valid = cv::aruco::estimatePoseBoard(corners, ids, board_, camera_matrix_, dist_coeffs_,
|
valid = cv::aruco::estimatePoseBoard(corners, ids, board_, camera_matrix_, dist_coeffs_,
|
||||||
rvec, tvec, false);
|
rvec, tvec, false);
|
||||||
@@ -192,7 +191,7 @@ public:
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
Mat obj_points, img_points;
|
Mat obj_points, img_points;
|
||||||
// estimation with known vertical
|
// estimation with "snapping"
|
||||||
cv::aruco::getBoardObjectAndImagePoints(board_, corners, ids, obj_points, img_points);
|
cv::aruco::getBoardObjectAndImagePoints(board_, corners, ids, obj_points, img_points);
|
||||||
if (obj_points.empty()) goto publish_debug;
|
if (obj_points.empty()) goto publish_debug;
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ public:
|
|||||||
|
|
||||||
fillTransform(transform_.transform, rvec, tvec);
|
fillTransform(transform_.transform, rvec, tvec);
|
||||||
try {
|
try {
|
||||||
geometry_msgs::TransformStamped vertical = tf_buffer_.lookupTransform(markers->header.frame_id,
|
geometry_msgs::TransformStamped snap_to = tf_buffer_.lookupTransform(markers->header.frame_id,
|
||||||
known_vertical_, markers->header.stamp, ros::Duration(0.02));
|
known_tilt_, markers->header.stamp, ros::Duration(0.02));
|
||||||
applyVertical(transform_.transform.rotation, vertical.transform.rotation, flip_vertical_, auto_flip_);
|
snapOrientation(transform_.transform.rotation, snap_to.transform.rotation, auto_flip_);
|
||||||
} catch (const tf2::TransformException& e) {
|
} catch (const tf2::TransformException& e) {
|
||||||
NODELET_WARN_THROTTLE(1, "can't retrieve known vertical: %s", e.what());
|
NODELET_WARN_THROTTLE(1, "can't snap: %s", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry_msgs::TransformStamped shift;
|
geometry_msgs::TransformStamped shift;
|
||||||
@@ -504,7 +503,7 @@ publish_debug:
|
|||||||
vis_marker.pose.position.x = x;
|
vis_marker.pose.position.x = x;
|
||||||
vis_marker.pose.position.y = y;
|
vis_marker.pose.position.y = y;
|
||||||
vis_marker.pose.position.z = z;
|
vis_marker.pose.position.z = z;
|
||||||
tf::quaternionTFToMsg(q, vis_marker.pose.orientation);
|
tf::quaternionTFToMsg(q, marker.pose.orientation);
|
||||||
vis_marker.frame_locked = true;
|
vis_marker.frame_locked = true;
|
||||||
vis_array_.markers.push_back(vis_marker);
|
vis_array_.markers.push_back(vis_marker);
|
||||||
|
|
||||||
|
|||||||
@@ -106,25 +106,26 @@ inline bool isFlipped(tf::Quaternion& q)
|
|||||||
return (abs(pitch) > M_PI / 2) || (abs(roll) > M_PI / 2);
|
return (abs(pitch) > M_PI / 2) || (abs(roll) > M_PI / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply a vertical to an orientation */
|
/* Set roll and pitch from "from" to "to", keeping yaw */
|
||||||
inline void applyVertical(geometry_msgs::Quaternion& orientation, const geometry_msgs::Quaternion& vertical,
|
inline void snapOrientation(geometry_msgs::Quaternion& to, const geometry_msgs::Quaternion& from, bool auto_flip = false)
|
||||||
bool flip_vertical = false, bool auto_flip = false) // editorconfig-checker-disable-line
|
|
||||||
{
|
{
|
||||||
tf::Quaternion _vertical, _orientation;
|
tf::Quaternion _from, _to;
|
||||||
tf::quaternionMsgToTF(vertical, _vertical);
|
tf::quaternionMsgToTF(from, _from);
|
||||||
tf::quaternionMsgToTF(orientation, _orientation);
|
tf::quaternionMsgToTF(to, _to);
|
||||||
|
|
||||||
if (flip_vertical || (auto_flip && !isFlipped(_orientation))) {
|
if (auto_flip) {
|
||||||
static const tf::Quaternion flip = tf::createQuaternionFromRPY(M_PI, 0, 0);
|
if (!isFlipped(_from)) {
|
||||||
_vertical *= flip; // flip vertical
|
static const tf::Quaternion flip = tf::createQuaternionFromRPY(M_PI, 0, 0);
|
||||||
|
_from *= flip; // flip "from"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto diff = tf::Matrix3x3(_orientation).transposeTimes(tf::Matrix3x3(_vertical));
|
auto diff = tf::Matrix3x3(_to).transposeTimes(tf::Matrix3x3(_from));
|
||||||
double _, yaw;
|
double _, yaw;
|
||||||
diff.getRPY(_, _, yaw);
|
diff.getRPY(_, _, yaw);
|
||||||
auto q = tf::createQuaternionFromRPY(0, 0, -yaw);
|
auto q = tf::createQuaternionFromRPY(0, 0, -yaw);
|
||||||
_vertical = _vertical * q; // set yaw from orientation to vertical
|
_from = _from * q; // set yaw from "to" to "from"
|
||||||
tf::quaternionTFToMsg(_vertical, orientation); // set vertical to orientation
|
tf::quaternionTFToMsg(_from, to); // set "from" to "to"
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void transformToPose(const geometry_msgs::Transform& transform, geometry_msgs::Pose& pose)
|
inline void transformToPose(const geometry_msgs::Transform& transform, geometry_msgs::Pose& pose)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import tf2_geometry_msgs
|
|||||||
from geometry_msgs.msg import PoseWithCovarianceStamped
|
from geometry_msgs.msg import PoseWithCovarianceStamped
|
||||||
from sensor_msgs.msg import Image
|
from sensor_msgs.msg import Image
|
||||||
from aruco_pose.msg import MarkerArray
|
from aruco_pose.msg import MarkerArray
|
||||||
from visualization_msgs.msg import MarkerArray as VisMarkerArray, Marker as VisMarker
|
from visualization_msgs.msg import MarkerArray as VisMarkerArray
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -199,36 +199,6 @@ def test_map_markers(node):
|
|||||||
|
|
||||||
def test_map_visualization(node):
|
def test_map_visualization(node):
|
||||||
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
|
vis = rospy.wait_for_message('aruco_map/visualization', VisMarkerArray, timeout=5)
|
||||||
assert len(vis.markers) == 7
|
|
||||||
assert vis.markers[0].header.frame_id == 'aruco_map'
|
|
||||||
assert vis.markers[0].type == VisMarker.CUBE
|
|
||||||
assert vis.markers[0].action == VisMarker.ADD
|
|
||||||
assert vis.markers[0].pose.position.x == 0
|
|
||||||
assert vis.markers[0].pose.position.y == 0
|
|
||||||
assert vis.markers[0].pose.position.z == 0
|
|
||||||
assert vis.markers[0].pose.orientation.x == 0
|
|
||||||
assert vis.markers[0].pose.orientation.y == 0
|
|
||||||
assert vis.markers[0].pose.orientation.z == 0
|
|
||||||
assert vis.markers[0].pose.orientation.w == 1
|
|
||||||
assert vis.markers[0].scale.x == approx(0.33)
|
|
||||||
assert vis.markers[0].scale.y == approx(0.33)
|
|
||||||
assert vis.markers[0].scale.z == approx(0.001)
|
|
||||||
assert vis.markers[1].pose.position.x == 1
|
|
||||||
assert vis.markers[1].pose.position.y == 0
|
|
||||||
assert vis.markers[1].pose.position.z == 0
|
|
||||||
assert vis.markers[1].pose.orientation.x == 0
|
|
||||||
assert vis.markers[1].pose.orientation.y == 0
|
|
||||||
assert vis.markers[1].pose.orientation.z == 0
|
|
||||||
assert vis.markers[1].pose.orientation.w == 1
|
|
||||||
# non-zero yaw marker:
|
|
||||||
assert vis.markers[4].scale.x == approx(0.5)
|
|
||||||
assert vis.markers[4].pose.position.x == approx(0.5)
|
|
||||||
assert vis.markers[4].pose.position.y == 2
|
|
||||||
assert vis.markers[4].pose.position.z == 0
|
|
||||||
assert vis.markers[4].pose.orientation.x == 0
|
|
||||||
assert vis.markers[4].pose.orientation.y == 0
|
|
||||||
assert vis.markers[4].pose.orientation.z == approx(0.5646424733950354)
|
|
||||||
assert vis.markers[4].pose.orientation.w == approx(0.8253356149096783)
|
|
||||||
|
|
||||||
def test_map_debug(node):
|
def test_map_debug(node):
|
||||||
img = rospy.wait_for_message('aruco_map/debug', Image, timeout=5)
|
img = rospy.wait_for_message('aruco_map/debug', Image, timeout=5)
|
||||||
|
|||||||
735
builder/assets/noetic-bullseye.yaml
Normal file
735
builder/assets/noetic-bullseye.yaml
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
catkin:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-catkin]
|
||||||
|
genmsg:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-genmsg]
|
||||||
|
gencpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-gencpp]
|
||||||
|
geneus:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-geneus]
|
||||||
|
genlisp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-genlisp]
|
||||||
|
gennodejs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-gennodejs]
|
||||||
|
genpy:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-genpy]
|
||||||
|
bond_core:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-bond-core]
|
||||||
|
cmake_modules:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-cmake-modules]
|
||||||
|
class_loader:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-class-loader]
|
||||||
|
common_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-common-msgs]
|
||||||
|
common_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-common-tutorials]
|
||||||
|
cpp_common:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-cpp-common]
|
||||||
|
desktop:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-desktop]
|
||||||
|
diagnostics:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostics]
|
||||||
|
executive_smach:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-executive-smach]
|
||||||
|
geometry:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-geometry]
|
||||||
|
geometry_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-geometry-tutorials]
|
||||||
|
gl_dependency:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-gl-dependency]
|
||||||
|
image_common:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-common]
|
||||||
|
image_pipeline:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-pipeline]
|
||||||
|
image_transport_plugins:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-transport-plugins]
|
||||||
|
laser_pipeline:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-laser-pipeline]
|
||||||
|
mavlink:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-mavlink]
|
||||||
|
media_export:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-media-export]
|
||||||
|
message_generation:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-message-generation]
|
||||||
|
message_runtime:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-message-runtime]
|
||||||
|
mk:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-mk]
|
||||||
|
nodelet_core:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-nodelet-core]
|
||||||
|
orocos_kdl:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-orocos-kdl]
|
||||||
|
perception:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-perception]
|
||||||
|
perception_pcl:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-perception-pcl]
|
||||||
|
python_orocos_kdl:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-python-orocos-kdl]
|
||||||
|
qt_dotgraph:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-qt-dotgraph]
|
||||||
|
qt_gui:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-qt-gui]
|
||||||
|
qt_gui_py_common:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-qt-gui-py-common]
|
||||||
|
qwt_dependency:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-qwt-dependency]
|
||||||
|
robot:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-robot]
|
||||||
|
ros:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros]
|
||||||
|
ros_base:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-base]
|
||||||
|
ros_comm:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-comm]
|
||||||
|
ros_core:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-core]
|
||||||
|
ros_environment:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-environment]
|
||||||
|
ros_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-tutorials]
|
||||||
|
rosapi:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosapi]
|
||||||
|
rosbag_migration_rule:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbag-migration-rule]
|
||||||
|
rosbash:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbash]
|
||||||
|
rosboost_cfg:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosboost-cfg]
|
||||||
|
rosbridge_server:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbridge-server]
|
||||||
|
rosbridge_suite:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbridge-suite]
|
||||||
|
rosbuild:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbuild]
|
||||||
|
rosclean:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosclean]
|
||||||
|
roscpp_core:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscpp-core]
|
||||||
|
roscpp_traits:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscpp-traits]
|
||||||
|
roscreate:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscreate]
|
||||||
|
rosgraph:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosgraph]
|
||||||
|
roslang:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslang]
|
||||||
|
roslint:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslint]
|
||||||
|
roslisp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslisp]
|
||||||
|
rosmake:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosmake]
|
||||||
|
rosmaster:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosmaster]
|
||||||
|
rospack:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rospack]
|
||||||
|
roslib:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslib]
|
||||||
|
rosparam:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosparam]
|
||||||
|
rospy:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rospy]
|
||||||
|
rosserial:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosserial]
|
||||||
|
rosserial_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosserial-msgs]
|
||||||
|
rosserial_python:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosserial-python]
|
||||||
|
rosservice:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosservice]
|
||||||
|
rostime:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rostime]
|
||||||
|
roscpp_serialization:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscpp-serialization]
|
||||||
|
python_qt_binding:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-python-qt-binding]
|
||||||
|
roslaunch:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslaunch]
|
||||||
|
rosunit:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosunit]
|
||||||
|
angles:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-angles]
|
||||||
|
libmavconn:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-libmavconn]
|
||||||
|
rosconsole:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosconsole]
|
||||||
|
pluginlib:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-pluginlib]
|
||||||
|
qt_gui_cpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-qt-gui-cpp]
|
||||||
|
resource_retriever:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-resource-retriever]
|
||||||
|
rosconsole_bridge:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosconsole-bridge]
|
||||||
|
roslz4:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roslz4]
|
||||||
|
rosserial_client:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosserial-client]
|
||||||
|
rostest:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rostest]
|
||||||
|
rqt_action:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-action]
|
||||||
|
rqt_bag:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-bag]
|
||||||
|
rqt_bag_plugins:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-bag-plugins]
|
||||||
|
rqt_common_plugins:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-common-plugins]
|
||||||
|
rqt_console:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-console]
|
||||||
|
rqt_dep:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-dep]
|
||||||
|
rqt_graph:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-graph]
|
||||||
|
rqt_gui:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-gui]
|
||||||
|
rqt_logger_level:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-logger-level]
|
||||||
|
rqt_moveit:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-moveit]
|
||||||
|
rqt_msg:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-msg]
|
||||||
|
rqt_nav_view:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-nav-view]
|
||||||
|
rqt_plot:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-plot]
|
||||||
|
rqt_pose_view:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-pose-view]
|
||||||
|
rqt_publisher:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-publisher]
|
||||||
|
rqt_py_console:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-py-console]
|
||||||
|
rqt_reconfigure:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-reconfigure]
|
||||||
|
rqt_robot_dashboard:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-robot-dashboard]
|
||||||
|
rqt_robot_monitor:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-robot-monitor]
|
||||||
|
rqt_robot_plugins:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-robot-plugins]
|
||||||
|
rqt_robot_steering:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-robot-steering]
|
||||||
|
rqt_runtime_monitor:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-runtime-monitor]
|
||||||
|
rqt_service_caller:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-service-caller]
|
||||||
|
rqt_shell:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-shell]
|
||||||
|
rqt_srv:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-srv]
|
||||||
|
rqt_tf_tree:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-tf-tree]
|
||||||
|
rqt_top:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-top]
|
||||||
|
rqt_topic:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-topic]
|
||||||
|
rqt_web:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-web]
|
||||||
|
smach:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-smach]
|
||||||
|
smclib:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-smclib]
|
||||||
|
std_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-std-msgs]
|
||||||
|
actionlib_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-actionlib-msgs]
|
||||||
|
bond:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-bond]
|
||||||
|
diagnostic_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostic-msgs]
|
||||||
|
geometry_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-geometry-msgs]
|
||||||
|
eigen_conversions:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-eigen-conversions]
|
||||||
|
kdl_conversions:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-kdl-conversions]
|
||||||
|
nav_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-nav-msgs]
|
||||||
|
rosbridge_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbridge-msgs]
|
||||||
|
rosgraph_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosgraph-msgs]
|
||||||
|
rosmsg:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosmsg]
|
||||||
|
rqt_py_common:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-py-common]
|
||||||
|
shape_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-shape-msgs]
|
||||||
|
smach_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-smach-msgs]
|
||||||
|
std_srvs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-std-srvs]
|
||||||
|
tf2_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-msgs]
|
||||||
|
tf2:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2]
|
||||||
|
tf2_eigen:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-eigen]
|
||||||
|
trajectory_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-trajectory-msgs]
|
||||||
|
control_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-control-msgs]
|
||||||
|
urdf_parser_plugin:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-urdf-parser-plugin]
|
||||||
|
urdfdom_py:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-urdfdom-py]
|
||||||
|
uuid_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-uuid-msgs]
|
||||||
|
geographic_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-geographic-msgs]
|
||||||
|
vision_opencv:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-vision-opencv]
|
||||||
|
visualization_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-visualization-msgs]
|
||||||
|
visualization_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-visualization-tutorials]
|
||||||
|
viz:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-viz]
|
||||||
|
webkit_dependency:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-webkit-dependency]
|
||||||
|
xmlrpcpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-xmlrpcpp]
|
||||||
|
roscpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscpp]
|
||||||
|
bondcpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-bondcpp]
|
||||||
|
bondpy:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-bondpy]
|
||||||
|
nodelet:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-nodelet]
|
||||||
|
nodelet_tutorial_math:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-nodelet-tutorial-math]
|
||||||
|
pluginlib_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-pluginlib-tutorials]
|
||||||
|
roscpp_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roscpp-tutorials]
|
||||||
|
rosout:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosout]
|
||||||
|
async_web_server_cpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-async-web-server-cpp]
|
||||||
|
camera_calibration:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-camera-calibration]
|
||||||
|
diagnostic_aggregator:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostic-aggregator]
|
||||||
|
diagnostic_updater:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostic-updater]
|
||||||
|
diagnostic_common_diagnostics:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostic-common-diagnostics]
|
||||||
|
dynamic_reconfigure:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-dynamic-reconfigure]
|
||||||
|
filters:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-filters]
|
||||||
|
joint_state_publisher:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-joint-state-publisher]
|
||||||
|
message_filters:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-message-filters]
|
||||||
|
ros_pytest:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ros-pytest]
|
||||||
|
rosauth:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosauth]
|
||||||
|
rosbag_storage:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbag-storage]
|
||||||
|
rosnode:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosnode]
|
||||||
|
rospy_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rospy-tutorials]
|
||||||
|
rosshow:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosshow]
|
||||||
|
rostopic:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rostopic]
|
||||||
|
rqt_gui_cpp:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-gui-cpp]
|
||||||
|
rqt_gui_py:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-gui-py]
|
||||||
|
self_test:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-self-test]
|
||||||
|
smach_ros:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-smach-ros]
|
||||||
|
tf2_py:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-py]
|
||||||
|
topic_tools:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-topic-tools]
|
||||||
|
rosbag:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbag]
|
||||||
|
actionlib:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-actionlib]
|
||||||
|
actionlib_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-actionlib-tutorials]
|
||||||
|
diagnostic_analysis:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-diagnostic-analysis]
|
||||||
|
nodelet_topic_tools:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-nodelet-topic-tools]
|
||||||
|
roswtf:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-roswtf]
|
||||||
|
rqt_launch:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-launch]
|
||||||
|
sensor_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-sensor-msgs]
|
||||||
|
camera_calibration_parsers:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-camera-calibration-parsers]
|
||||||
|
cv_bridge:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-cv-bridge]
|
||||||
|
image_geometry:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-geometry]
|
||||||
|
image_transport:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-transport]
|
||||||
|
camera_info_manager:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-camera-info-manager]
|
||||||
|
compressed_depth_image_transport:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-compressed-depth-image-transport]
|
||||||
|
compressed_image_transport:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-compressed-image-transport]
|
||||||
|
cv_camera:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-cv-camera]
|
||||||
|
image_proc:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-proc]
|
||||||
|
image_publisher:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-publisher]
|
||||||
|
map_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-map-msgs]
|
||||||
|
mavros_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-mavros-msgs]
|
||||||
|
pcl_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-pcl-msgs]
|
||||||
|
pcl_conversions:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-pcl-conversions]
|
||||||
|
polled_camera:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-polled-camera]
|
||||||
|
rqt_image_view:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-image-view]
|
||||||
|
stereo_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-stereo-msgs]
|
||||||
|
image_view:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-view]
|
||||||
|
rosbridge_library:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rosbridge-library]
|
||||||
|
stereo_image_proc:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-stereo-image-proc]
|
||||||
|
tf2_ros:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-ros]
|
||||||
|
depth_image_proc:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-depth-image-proc]
|
||||||
|
mavros:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-mavros]
|
||||||
|
tf:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf]
|
||||||
|
interactive_markers:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-interactive-markers]
|
||||||
|
interactive_marker_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-interactive-marker-tutorials]
|
||||||
|
laser_geometry:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-laser-geometry]
|
||||||
|
laser_assembler:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-laser-assembler]
|
||||||
|
laser_filters:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-laser-filters]
|
||||||
|
pcl_ros:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-pcl-ros]
|
||||||
|
tf2_geometry_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-geometry-msgs]
|
||||||
|
image_rotate:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-image-rotate]
|
||||||
|
tf2_kdl:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-kdl]
|
||||||
|
tf2_web_republisher:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf2-web-republisher]
|
||||||
|
tf_conversions:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-tf-conversions]
|
||||||
|
theora_image_transport:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-theora-image-transport]
|
||||||
|
turtlesim:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-turtlesim]
|
||||||
|
turtle_actionlib:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-turtle-actionlib]
|
||||||
|
turtle_tf:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-turtle-tf]
|
||||||
|
turtle_tf2:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-turtle-tf2]
|
||||||
|
urdf:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-urdf]
|
||||||
|
kdl_parser:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-kdl-parser]
|
||||||
|
kdl_parser_py:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-kdl-parser-py]
|
||||||
|
mavros_extras:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-mavros-extras]
|
||||||
|
robot_state_publisher:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-robot-state-publisher]
|
||||||
|
rviz:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rviz]
|
||||||
|
librviz_tutorial:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-librviz-tutorial]
|
||||||
|
rqt_rviz:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rqt-rviz]
|
||||||
|
rviz_plugin_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rviz-plugin-tutorials]
|
||||||
|
rviz_python_tutorial:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-rviz-python-tutorial]
|
||||||
|
urdf_tutorial:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-urdf-tutorial]
|
||||||
|
usb_cam:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-usb-cam]
|
||||||
|
visualization_marker_tutorials:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-visualization-marker-tutorials]
|
||||||
|
vl53l1x:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-vl53l1x]
|
||||||
|
web_video_server:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-web-video-server]
|
||||||
|
xacro:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-xacro]
|
||||||
|
led_msgs:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-led-msgs]
|
||||||
|
ws281x:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ws281x]
|
||||||
|
ddynamic_reconfigure:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-ddynamic-reconfigure]
|
||||||
|
librealsense2:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-librealsense2]
|
||||||
|
realsense2_camera:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-realsense2-camera]
|
||||||
|
realsense2_description:
|
||||||
|
debian:
|
||||||
|
bullseye: [ros-noetic-realsense2-description]
|
||||||
100
builder/image-build-ros.sh
Executable file
100
builder/image-build-ros.sh
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Script for building ROS packages from scratch
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 Copter Express Technologies
|
||||||
|
#
|
||||||
|
# Author: Oleg Kalachev <okalachev@gmail.com>
|
||||||
|
#
|
||||||
|
# Distributed under MIT License (available at https://opensource.org/licenses/MIT).
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -ex # exit on error, echo commands
|
||||||
|
|
||||||
|
# http://wiki.ros.org/Installation/Source
|
||||||
|
|
||||||
|
export ROS_DISTRO=noetic
|
||||||
|
. /etc/os-release # set $VERSION_CODENAME to Debian release code name
|
||||||
|
export ROS_OS_OVERRIDE=debian:11:$VERSION_CODENAME
|
||||||
|
|
||||||
|
echo "=== Building ROS from scratch"
|
||||||
|
|
||||||
|
#echo "--- Adding sources"
|
||||||
|
#echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list
|
||||||
|
#curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y python3-distutils python3-rosdep python3-rosinstall-generator build-essential git # python3-vcstool
|
||||||
|
|
||||||
|
# install vcstool using pip
|
||||||
|
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py && rm get-pip.py
|
||||||
|
pip3 install -U vcstool
|
||||||
|
|
||||||
|
# sudo rosdep init
|
||||||
|
rm /etc/ros/rosdep/sources.list.d/20-default.list
|
||||||
|
rosdep init
|
||||||
|
rosdep update
|
||||||
|
|
||||||
|
# rm /etc/ros/rosdep/sources.list.d/20-default.list && rosdep init
|
||||||
|
# rosdep --os=debian:$VERSION_CODENAME update
|
||||||
|
|
||||||
|
echo "--- Create Catkin workspace to build ROS package"
|
||||||
|
mkdir ~/ros_catkin_ws
|
||||||
|
cd ~/ros_catkin_ws
|
||||||
|
|
||||||
|
echo "--- Download ROS sources"
|
||||||
|
rosinstall_generator ros_base --rosdistro $ROS_DISTRO --deps --tar > noetic.rosinstall
|
||||||
|
mkdir ./src
|
||||||
|
vcs import --input noetic.rosinstall ./src
|
||||||
|
|
||||||
|
# https://answers.ros.org/question/343367/catkin-package-dependencies-issue-when-installing-ros-melodic-on-raspberry-pi-4/
|
||||||
|
#sudo apt remove python-rospkg
|
||||||
|
#sudo apt remove python-catkin-pkg
|
||||||
|
##sudo apt --fix-broken install
|
||||||
|
#sudo apt-get autoremove
|
||||||
|
|
||||||
|
echo "--- Install catkin_pkg"
|
||||||
|
cd
|
||||||
|
git clone https://github.com/ros-infrastructure/catkin_pkg.git
|
||||||
|
cd catkin_pkg
|
||||||
|
python3 setup.py install
|
||||||
|
cd ~/ros_catkin_ws
|
||||||
|
|
||||||
|
echo "--- Resolve dependencies"
|
||||||
|
rosdep install --from-paths ./src --ignore-packages-from-source --rosdistro $ROS_DISTRO -y --os=debian:$VERSION_CODENAME --skip-keys="python3-catkin-pkg python3-catkin-pkg-modules python3-rosdep-modules"
|
||||||
|
|
||||||
|
echo "--- Build ROS"
|
||||||
|
# https://github.com/ros/catkin/issues/863#issuecomment-290392074
|
||||||
|
./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DSETUPTOOLS_DEB_LAYOUT=OFF \
|
||||||
|
--install-space=/opt/ros/$ROS_DISTRO
|
||||||
|
|
||||||
|
# source ~/ros_catkin_ws/install_isolated/setup.bash
|
||||||
|
source /opt/ros/$ROS_DISTRO/setup.bash
|
||||||
|
|
||||||
|
echo "--- List built ROS packages"
|
||||||
|
set +x
|
||||||
|
rospack list-names | while read line; do echo $line `rosversion $line`; done
|
||||||
|
set -x
|
||||||
|
|
||||||
|
echo "--- Build Debian packages"
|
||||||
|
apt-get install -y python3-bloom debhelper dpkg-dev libtinyxml-dev
|
||||||
|
|
||||||
|
# add rosdep file to help bloom-generate resolve missing bullseye dependencies
|
||||||
|
echo "yaml file:///etc/ros/rosdep/noetic-bullseye.yaml" >> /etc/ros/rosdep/sources.list.d/20-default.list
|
||||||
|
rosdep update
|
||||||
|
|
||||||
|
pip3 install setuptools==45.2.0 # https://github.com/ros/catkin/issues/863#issuecomment-1000446018
|
||||||
|
|
||||||
|
for file in `find . -name "package.xml" -not -path "*/debian/*"`; do
|
||||||
|
cd $(dirname ${file})
|
||||||
|
rm -rf debian
|
||||||
|
bloom-generate rosdebian --os-name debian --os-version $VERSION_CODENAME --ros-distro $ROS_DISTRO --debug
|
||||||
|
debian/rules binary # fakeroot is not needed as we are root
|
||||||
|
cd -
|
||||||
|
done
|
||||||
|
|
||||||
|
ls
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
set -e # Exit immidiately on non-zero result
|
set -e # Exit immidiately on non-zero result
|
||||||
|
|
||||||
# https://www.raspberrypi.org/software/operating-systems/#raspberry-pi-os-32-bit
|
# https://www.raspberrypi.org/software/operating-systems/#raspberry-pi-os-32-bit
|
||||||
SOURCE_IMAGE="https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/2021-05-07-raspios-buster-armhf-lite.zip"
|
SOURCE_IMAGE="https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2023-12-11/2023-12-11-raspios-bookworm-armhf-lite.img.xz"
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
|
export DEBIAN_FRONTEND=${DEBIAN_FRONTEND:='noninteractive'}
|
||||||
export LANG=${LANG:='C.UTF-8'}
|
export LANG=${LANG:='C.UTF-8'}
|
||||||
@@ -104,7 +104,7 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/butterf
|
|||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/butterfly.socket' '/lib/systemd/system/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/butterfly.socket' '/lib/systemd/system/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey.service' '/lib/systemd/system/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/monkey.service' '/lib/systemd/system/'
|
||||||
# software install
|
# software install
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software.sh'
|
# ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-software.sh'
|
||||||
# network setup
|
# network setup
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-network.sh'
|
||||||
# avahi setup
|
# avahi setup
|
||||||
@@ -113,13 +113,14 @@ ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/avahi-s
|
|||||||
# If RPi then use a one thread to build a ROS package on RPi, else use all
|
# If RPi then use a one thread to build a ROS package on RPi, else use all
|
||||||
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)
|
[[ $(arch) == 'armv7l' ]] && NUMBER_THREADS=1 || NUMBER_THREADS=$(nproc --all)
|
||||||
# Clover
|
# Clover
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/noetic-rosdep-clover.yaml' '/etc/ros/rosdep/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/noetic-bullseye.yaml' '/etc/ros/rosdep/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/ros_python_paths' '/etc/sudoers.d/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/ros_python_paths' '/etc/sudoers.d/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/pigpiod.service' '/lib/systemd/system/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/pigpiod.service' '/lib/systemd/system/'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/launch.nanorc' '/usr/share/nano/'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/launch.nanorc' '/usr/share/nano/'
|
||||||
# ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-ros-clover.rosinstall' '/home/pi/ros_catkin_ws/'
|
# ${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} copy ${SCRIPTS_DIR}'/assets/kinetic-ros-clover.rosinstall' '/home/pi/ros_catkin_ws/'
|
||||||
# Add rename script
|
# Add rename script
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-ros.sh' ${REPO_URL} ${IMAGE_VERSION} false false ${NUMBER_THREADS}
|
#${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-ros.sh' ${REPO_URL} ${IMAGE_VERSION} false false ${NUMBER_THREADS}
|
||||||
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-build-ros.sh'
|
||||||
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-validate.sh'
|
${BUILDER_DIR}/image-chroot.sh ${IMAGE_PATH} exec ${SCRIPTS_DIR}'/image-validate.sh'
|
||||||
|
|
||||||
${BUILDER_DIR}/image-resize.sh ${IMAGE_PATH}
|
${BUILDER_DIR}/image-resize.sh ${IMAGE_PATH}
|
||||||
|
|||||||
@@ -151,9 +151,6 @@ catkin_make run_tests #&& catkin_test_results
|
|||||||
echo_stamp "Change permissions for catkin_ws"
|
echo_stamp "Change permissions for catkin_ws"
|
||||||
chown -Rf pi:pi /home/pi/catkin_ws
|
chown -Rf pi:pi /home/pi/catkin_ws
|
||||||
|
|
||||||
echo_stamp "Update www"
|
|
||||||
sudo -u pi sh -c ". devel/setup.sh && rosrun clover www"
|
|
||||||
|
|
||||||
echo_stamp "Make \$HOME/examples symlink"
|
echo_stamp "Make \$HOME/examples symlink"
|
||||||
ln -s "$(catkin_find clover examples --first-only)" /home/pi
|
ln -s "$(catkin_find clover examples --first-only)" /home/pi
|
||||||
chown -Rf pi:pi /home/pi/examples
|
chown -Rf pi:pi /home/pi/examples
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
# validate all required modules installed
|
# validate all required modules installed
|
||||||
|
|
||||||
import os
|
|
||||||
import rospy
|
import rospy
|
||||||
from geometry_msgs.msg import PoseStamped
|
from geometry_msgs.msg import PoseStamped
|
||||||
from sensor_msgs.msg import Range, BatteryState
|
from sensor_msgs.msg import Range, BatteryState
|
||||||
@@ -23,7 +22,6 @@ from clover.srv import GetTelemetry, Navigate, NavigateGlobal, SetPosition, SetV
|
|||||||
from led_msgs.srv import SetLEDs
|
from led_msgs.srv import SetLEDs
|
||||||
from led_msgs.msg import LEDStateArray, LEDState
|
from led_msgs.msg import LEDStateArray, LEDState
|
||||||
from aruco_pose.msg import Marker, MarkerArray, Point2D
|
from aruco_pose.msg import Marker, MarkerArray, Point2D
|
||||||
from clover import long_callback
|
|
||||||
|
|
||||||
import dynamic_reconfigure.client
|
import dynamic_reconfigure.client
|
||||||
|
|
||||||
@@ -33,12 +31,9 @@ import tf2_geometry_msgs
|
|||||||
import VL53L1X
|
import VL53L1X
|
||||||
import pymavlink
|
import pymavlink
|
||||||
from pymavlink import mavutil
|
from pymavlink import mavutil
|
||||||
|
import rpi_ws281x
|
||||||
|
import pigpio
|
||||||
# from espeak import espeak
|
# from espeak import espeak
|
||||||
from pyzbar import pyzbar
|
from pyzbar import pyzbar
|
||||||
import docopt
|
|
||||||
|
|
||||||
print(cv2.getBuildInformation())
|
print(cv2.getBuildInformation())
|
||||||
|
|
||||||
if not os.environ.get('VM'):
|
|
||||||
import rpi_ws281x
|
|
||||||
import pigpio
|
|
||||||
|
|||||||
@@ -6,10 +6,16 @@ set -ex
|
|||||||
|
|
||||||
# validate required software is installed
|
# validate required software is installed
|
||||||
|
|
||||||
|
python --version
|
||||||
python2 --version
|
python2 --version
|
||||||
python3 --version
|
python3 --version
|
||||||
|
ipython --version
|
||||||
ipython3 --version
|
ipython3 --version
|
||||||
|
|
||||||
|
# ptvsd does not have a stand-alone binary
|
||||||
|
python -m ptvsd --version
|
||||||
|
python3 -m ptvsd --version
|
||||||
|
|
||||||
node -v
|
node -v
|
||||||
npm -v
|
npm -v
|
||||||
|
|
||||||
@@ -19,77 +25,42 @@ lsof -v
|
|||||||
git --version
|
git --version
|
||||||
vim --version
|
vim --version
|
||||||
pip --version
|
pip --version
|
||||||
|
pip2 --version
|
||||||
pip3 --version
|
pip3 --version
|
||||||
tcpdump --version
|
tcpdump --version
|
||||||
monkey --version
|
monkey --version
|
||||||
|
pigpiod -v
|
||||||
|
i2cdetect -V
|
||||||
|
butterfly -h
|
||||||
# espeak --version
|
# espeak --version
|
||||||
|
mjpg_streamer --version
|
||||||
systemctl --version
|
systemctl --version
|
||||||
|
|
||||||
if [ -z $VM ]; then
|
|
||||||
# rpi only software
|
|
||||||
python --version
|
|
||||||
ipython --version
|
|
||||||
pip2 --version
|
|
||||||
# `python` is python2 for now
|
|
||||||
[[ $(python -c 'import sys;print(sys.version_info.major)') == "2" ]]
|
|
||||||
|
|
||||||
# ptvsd does not have a stand-alone binary
|
|
||||||
python -m ptvsd --version
|
|
||||||
python3 -m ptvsd --version
|
|
||||||
|
|
||||||
pigpiod -v
|
|
||||||
i2cdetect -V
|
|
||||||
butterfly -h
|
|
||||||
mjpg_streamer --version
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ros stuff
|
# ros stuff
|
||||||
|
|
||||||
roscore -h
|
roscore -h
|
||||||
rosversion clover
|
rosversion clover
|
||||||
rosversion aruco_pose
|
rosversion aruco_pose
|
||||||
|
rosversion vl53l1x
|
||||||
rosversion mavros
|
rosversion mavros
|
||||||
rosversion mavros_extras
|
rosversion mavros_extras
|
||||||
rosversion ws281x
|
rosversion ws281x
|
||||||
rosversion led_msgs
|
rosversion led_msgs
|
||||||
rosversion dynamic_reconfigure
|
rosversion dynamic_reconfigure
|
||||||
rosversion tf2_web_republisher
|
rosversion tf2_web_republisher
|
||||||
rosversion rosbridge_server
|
rosversion compressed_image_transport
|
||||||
|
rosversion rosbridge_suite
|
||||||
|
rosversion rosserial
|
||||||
rosversion usb_cam
|
rosversion usb_cam
|
||||||
rosversion cv_camera
|
rosversion cv_camera
|
||||||
rosversion web_video_server
|
rosversion web_video_server
|
||||||
|
rosversion rosshow
|
||||||
rosversion nodelet
|
rosversion nodelet
|
||||||
rosversion image_view
|
rosversion image_view
|
||||||
|
|
||||||
|
# validate some versions
|
||||||
|
[[ $(rosversion cv_camera) == "0.5.1" ]] # patched version with init fix
|
||||||
[[ $(rosversion ws281x) == "0.0.13" ]]
|
[[ $(rosversion ws281x) == "0.0.13" ]]
|
||||||
|
|
||||||
if [ -z $VM ]; then
|
|
||||||
rosversion compressed_image_transport
|
|
||||||
rosversion rosshow
|
|
||||||
rosversion vl53l1x
|
|
||||||
rosversion rosserial
|
|
||||||
[[ $(rosversion cv_camera) == "0.5.1" ]] # patched version with init fix
|
|
||||||
fi
|
|
||||||
|
|
||||||
# determine user home directory
|
|
||||||
[ $VM ] && H="/home/clover" || H="/home/pi"
|
|
||||||
|
|
||||||
# test basic ros tool work
|
|
||||||
source $H/catkin_ws/devel/setup.bash
|
|
||||||
roscd
|
|
||||||
rosrun
|
|
||||||
rosmsg
|
|
||||||
rossrv
|
|
||||||
rosnode || [ $? -eq 64 ] # usage output code is 64
|
|
||||||
rostopic || [ $? -eq 64 ]
|
|
||||||
rosservice || [ $? -eq 64 ]
|
|
||||||
rosparam
|
|
||||||
roslaunch -h
|
|
||||||
|
|
||||||
# validate examples are present
|
# validate examples are present
|
||||||
[[ $(ls $H/examples/*) ]]
|
[[ $(ls /home/pi/examples/*) ]]
|
||||||
|
|
||||||
# validate web tools present
|
|
||||||
[ -d $H/.ros/www ]
|
|
||||||
[ "$(readlink $H/.ros/www/clover)" = "$H/catkin_ws/src/clover/clover/www" ]
|
|
||||||
[ "$(readlink $H/.ros/www/clover_blocks)" = "$H/catkin_ws/src/clover/clover_blocks/www" ]
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ find_package(OpenCV ${_opencv_version} REQUIRED
|
|||||||
## Uncomment this if the package has a setup.py. This macro ensures
|
## Uncomment this if the package has a setup.py. This macro ensures
|
||||||
## modules and global scripts declared therein get installed
|
## modules and global scripts declared therein get installed
|
||||||
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
|
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
|
||||||
catkin_python_setup()
|
# catkin_python_setup()
|
||||||
|
|
||||||
################################################
|
################################################
|
||||||
## Declare ROS messages, services and actions ##
|
## Declare ROS messages, services and actions ##
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
# Information: https://clover.coex.tech/camera
|
|
||||||
|
|
||||||
# Example on basic working with the camera and image processing:
|
|
||||||
|
|
||||||
# - cuts out a central square from the camera image;
|
|
||||||
# - publishes this cropped image to the topic `/cv/center`;
|
|
||||||
# - computes the average color of it;
|
|
||||||
# - prints its name to the console.
|
|
||||||
|
|
||||||
import rospy
|
|
||||||
import cv2
|
|
||||||
from sensor_msgs.msg import Image
|
|
||||||
from cv_bridge import CvBridge
|
|
||||||
from clover import long_callback
|
|
||||||
|
|
||||||
rospy.init_node('cv')
|
|
||||||
bridge = CvBridge()
|
|
||||||
|
|
||||||
printed_color = None
|
|
||||||
center_pub = rospy.Publisher('~center', Image, queue_size=1)
|
|
||||||
|
|
||||||
def get_color_name(h):
|
|
||||||
if h < 15: return 'red'
|
|
||||||
elif h < 30: return 'orange'
|
|
||||||
elif h < 60: return 'yellow'
|
|
||||||
elif h < 90: return 'green'
|
|
||||||
elif h < 120: return 'cyan'
|
|
||||||
elif h < 150: return 'blue'
|
|
||||||
elif h < 170: return 'magenta'
|
|
||||||
else: return 'red'
|
|
||||||
|
|
||||||
|
|
||||||
@long_callback
|
|
||||||
def image_callback(msg):
|
|
||||||
img = bridge.imgmsg_to_cv2(msg, 'bgr8')
|
|
||||||
|
|
||||||
# convert to HSV to work with color hue
|
|
||||||
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
|
||||||
|
|
||||||
# cut out a central square
|
|
||||||
w = img.shape[1]
|
|
||||||
h = img.shape[0]
|
|
||||||
r = 20
|
|
||||||
center = img_hsv[h // 2 - r:h // 2 + r, w // 2 - r:w // 2 + r]
|
|
||||||
|
|
||||||
# compute and print the average hue
|
|
||||||
mean_hue = center[:, :, 0].mean()
|
|
||||||
color = get_color_name(mean_hue)
|
|
||||||
global printed_color
|
|
||||||
if color != printed_color:
|
|
||||||
print(color)
|
|
||||||
printed_color = color
|
|
||||||
|
|
||||||
# publish the cropped image
|
|
||||||
center = cv2.cvtColor(center, cv2.COLOR_HSV2BGR)
|
|
||||||
center_pub.publish(bridge.cv2_to_imgmsg(center, 'bgr8'))
|
|
||||||
|
|
||||||
# process every frame:
|
|
||||||
image_sub = rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1)
|
|
||||||
|
|
||||||
# process 5 frames per second:
|
|
||||||
# image_sub = rospy.Subscriber('main_camera/image_raw_throttled', Image, image_callback, queue_size=1)
|
|
||||||
|
|
||||||
rospy.spin()
|
|
||||||
@@ -18,9 +18,8 @@
|
|||||||
<remap from="map_markers" to="aruco_map/map"/>
|
<remap from="map_markers" to="aruco_map/map"/>
|
||||||
<param name="estimate_poses" value="true"/>
|
<param name="estimate_poses" value="true"/>
|
||||||
<param name="send_tf" value="true"/>
|
<param name="send_tf" value="true"/>
|
||||||
<param name="use_map_markers" value="true"/>
|
<param name="known_tilt" value="map" if="$(eval placement == 'floor')"/>
|
||||||
<param name="known_vertical" value="map" if="$(eval placement == 'floor' or placement == 'ceiling')"/>
|
<param name="known_tilt" value="map_flipped" if="$(eval placement == 'ceiling')"/>
|
||||||
<param name="flip_vertical" value="true" if="$(eval placement == 'ceiling')"/>
|
|
||||||
<param name="length" value="$(arg length)"/>
|
<param name="length" value="$(arg length)"/>
|
||||||
<param name="transform_timeout" value="0.1"/>
|
<param name="transform_timeout" value="0.1"/>
|
||||||
<!-- aruco detector parameters -->
|
<!-- aruco detector parameters -->
|
||||||
@@ -36,8 +35,8 @@
|
|||||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||||
<remap from="markers" to="aruco_detect/markers"/>
|
<remap from="markers" to="aruco_detect/markers"/>
|
||||||
<param name="map" value="$(find aruco_pose)/map/$(arg map)"/>
|
<param name="map" value="$(find aruco_pose)/map/$(arg map)"/>
|
||||||
<param name="known_vertical" value="map" if="$(eval placement == 'floor' or placement == 'ceiling')"/>
|
<param name="known_tilt" value="map" if="$(eval placement == 'floor')"/>
|
||||||
<param name="flip_vertical" value="true" if="$(eval placement == 'ceiling')"/>
|
<param name="known_tilt" value="map_flipped" if="$(eval placement == 'ceiling')"/>
|
||||||
<param name="image_axis" value="true"/>
|
<param name="image_axis" value="true"/>
|
||||||
<param name="frame_id" value="aruco_map_detected" if="$(arg aruco_vpe)"/>
|
<param name="frame_id" value="aruco_map_detected" if="$(arg aruco_vpe)"/>
|
||||||
<param name="frame_id" value="aruco_map" unless="$(arg aruco_vpe)"/>
|
<param name="frame_id" value="aruco_map" unless="$(arg aruco_vpe)"/>
|
||||||
|
|||||||
@@ -45,9 +45,10 @@
|
|||||||
<remap from="camera_info" to="main_camera/camera_info"/>
|
<remap from="camera_info" to="main_camera/camera_info"/>
|
||||||
<param name="calc_flow_gyro" value="true"/>
|
<param name="calc_flow_gyro" value="true"/>
|
||||||
<param name="roi_rad" value="0.8"/>
|
<param name="roi_rad" value="0.8"/>
|
||||||
<param name="disable_on_vpe" value="false"/>
|
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
|
<node pkg="tf2_ros" type="static_transform_publisher" name="map_flipped_frame" args="0 0 0 3.1415926 3.1415926 0 map map_flipped"/>
|
||||||
|
|
||||||
<!-- simplified offboard control -->
|
<!-- simplified offboard control -->
|
||||||
<node name="simple_offboard" pkg="clover" type="simple_offboard" output="screen" clear_params="true">
|
<node name="simple_offboard" pkg="clover" type="simple_offboard" output="screen" clear_params="true">
|
||||||
<param name="reference_frames/main_camera_optical" value="map"/>
|
<param name="reference_frames/main_camera_optical" value="map"/>
|
||||||
@@ -85,4 +86,8 @@
|
|||||||
<param name="use_fake_gcs" value="false"/>
|
<param name="use_fake_gcs" value="false"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
|
<!-- Update static directory -->
|
||||||
|
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true">
|
||||||
|
<param name="default_package" value="clover"/>
|
||||||
|
</node>
|
||||||
</launch>
|
</launch>
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up -->
|
<arg name="direction_z" default="down"/> <!-- direction the camera points: down, up -->
|
||||||
<arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
|
<arg name="direction_y" default="backward"/> <!-- direction the camera cable points: backward, forward -->
|
||||||
<arg name="device" default="/dev/video0"/> <!-- v4l2 device -->
|
<arg name="device" default="/dev/video0"/> <!-- v4l2 device -->
|
||||||
<arg name="throttled_topic" default="true"/> <!-- enable throttled image topic -->
|
|
||||||
<arg name="throttled_topic_rate" default="5.0"/> <!-- throttled image topic rate -->
|
|
||||||
<arg name="simulator" default="false"/>
|
<arg name="simulator" default="false"/>
|
||||||
|
|
||||||
<node if="$(eval direction_z == 'down' and direction_y == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
|
<node if="$(eval direction_z == 'down' and direction_y == 'backward')" pkg="tf2_ros" type="static_transform_publisher" name="main_camera_frame" args="0.05 0 -0.07 -1.5707963 0 3.1415926 base_link main_camera_optical"/>
|
||||||
@@ -45,8 +43,4 @@
|
|||||||
<node pkg="clover" type="camera_markers" ns="main_camera" name="main_camera_markers">
|
<node pkg="clover" type="camera_markers" ns="main_camera" name="main_camera_markers">
|
||||||
<param name="scale" value="3.0"/>
|
<param name="scale" value="3.0"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
||||||
<!-- image topic throttled -->
|
|
||||||
<node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera"
|
|
||||||
args="messages image_raw $(arg throttled_topic_rate) image_raw_throttled" if="$(arg throttled_topic)"/>
|
|
||||||
</launch>
|
</launch>
|
||||||
|
|||||||
@@ -43,7 +43,8 @@
|
|||||||
<depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend>
|
<depend condition="$ROS_PYTHON_VERSION == 3">python3-lxml</depend>
|
||||||
<depend>dynamic_reconfigure</depend>
|
<depend>dynamic_reconfigure</depend>
|
||||||
<exec_depend>python-pymavlink</exec_depend>
|
<exec_depend>python-pymavlink</exec_depend>
|
||||||
<test_depend>ros_pytest</test_depend>
|
<!-- Use test_depend for packages you need only for testing: -->
|
||||||
|
<!-- <test_depend>gtest</test_depend> -->
|
||||||
|
|
||||||
<!-- The export tag contains other, unspecified, tags -->
|
<!-- The export tag contains other, unspecified, tags -->
|
||||||
<export>
|
<export>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
flask==1.1.1
|
flask==1.1.1
|
||||||
|
docopt==0.6.2
|
||||||
geopy==1.11.0
|
geopy==1.11.0
|
||||||
smbus2==0.3.0
|
smbus2==0.3.0
|
||||||
VL53L1X==0.0.5
|
VL53L1X==0.0.5
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
|
|
||||||
|
|
||||||
from distutils.core import setup
|
|
||||||
from catkin_pkg.python_setup import generate_distutils_setup
|
|
||||||
|
|
||||||
# fetch values from package.xml
|
|
||||||
setup_args = generate_distutils_setup(
|
|
||||||
packages=['clover'],
|
|
||||||
package_dir={'': 'src'})
|
|
||||||
|
|
||||||
setup(**setup_args)
|
|
||||||
@@ -13,12 +13,7 @@ from util import handle_response
|
|||||||
|
|
||||||
rospy.init_node('autotest_aruco', disable_signals=True) # disable signals to allow interrupting with ctrl+c
|
rospy.init_node('autotest_aruco', disable_signals=True) # disable signals to allow interrupting with ctrl+c
|
||||||
|
|
||||||
try:
|
flow_client = dynamic_reconfigure.client.Client('optical_flow')
|
||||||
flow_client = dynamic_reconfigure.client.Client('optical_flow', timeout=2)
|
|
||||||
except rospy.ROSException:
|
|
||||||
flow_client = None
|
|
||||||
print('Cannot configure optical flow, skip')
|
|
||||||
|
|
||||||
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
|
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
|
||||||
navigate = handle_response(rospy.ServiceProxy('navigate', srv.Navigate))
|
navigate = handle_response(rospy.ServiceProxy('navigate', srv.Navigate))
|
||||||
land = handle_response(rospy.ServiceProxy('land', Trigger))
|
land = handle_response(rospy.ServiceProxy('land', Trigger))
|
||||||
@@ -72,13 +67,12 @@ input('Go to center %g %g 1.5 speed 5 [enter] ' % (center_x, center_y))
|
|||||||
navigate_wait(x=center_x, y=center_y, z=1.5, speed=5, frame_id='aruco_map')
|
navigate_wait(x=center_x, y=center_y, z=1.5, speed=5, frame_id='aruco_map')
|
||||||
print_current_map_position()
|
print_current_map_position()
|
||||||
|
|
||||||
if flow_client:
|
input('Disable optical flow and keep hovering [enter] ')
|
||||||
input('Disable optical flow and keep hovering [enter] ')
|
flow_client.update_configuration({'enabled': False})
|
||||||
flow_client.update_configuration({'enabled': False})
|
rospy.sleep(5)
|
||||||
rospy.sleep(5)
|
|
||||||
|
|
||||||
input('Enable optical flow back [enter] ')
|
input('Enable optical flow back [enter] ')
|
||||||
flow_client.update_configuration({'enabled': True})
|
flow_client.update_configuration({'enabled': True})
|
||||||
|
|
||||||
input('Go to side 1 %g 2 heading top [enter] ' % (center_y))
|
input('Go to side 1 %g 2 heading top [enter] ' % (center_y))
|
||||||
navigate_wait(x=1, y=center_y, z=2, yaw=1.57, frame_id='aruco_map')
|
navigate_wait(x=1, y=center_y, z=2, yaw=1.57, frame_id='aruco_map')
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import rospy
|
|
||||||
from threading import Thread, Event
|
|
||||||
|
|
||||||
def long_callback(fn):
|
|
||||||
"""
|
|
||||||
Decorator fixing a rospy issue for long-running topic callbacks, primarily
|
|
||||||
for image processing.
|
|
||||||
|
|
||||||
See: https://github.com/ros/ros_comm/issues/1901.
|
|
||||||
|
|
||||||
Usage example:
|
|
||||||
|
|
||||||
@long_callback
|
|
||||||
def image_callback(msg):
|
|
||||||
# perform image processing
|
|
||||||
# ...
|
|
||||||
|
|
||||||
rospy.Subscriber('main_camera/image_raw', Image, image_callback, queue_size=1)
|
|
||||||
"""
|
|
||||||
e = Event()
|
|
||||||
|
|
||||||
def thread():
|
|
||||||
while not rospy.is_shutdown():
|
|
||||||
e.wait()
|
|
||||||
e.clear()
|
|
||||||
fn(thread.current_msg)
|
|
||||||
|
|
||||||
thread.current_msg = None
|
|
||||||
Thread(target=thread, daemon=True).start()
|
|
||||||
|
|
||||||
def wrapper(msg):
|
|
||||||
thread.current_msg = msg
|
|
||||||
e.set()
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
@@ -319,8 +319,8 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
auto set_effect = nh.advertiseService("set_effect", &setEffect);
|
auto set_effect = nh.advertiseService("set_effect", &setEffect);
|
||||||
|
|
||||||
auto mavros_state_sub = nh.subscribe("mavros/state", 1, &handleMavrosState);
|
auto mavros_state_sub = nh.subscribe("/mavros/state", 1, &handleMavrosState);
|
||||||
auto battery_sub = nh.subscribe("mavros/battery", 1, &handleBattery);
|
auto battery_sub = nh.subscribe("/mavros/battery", 1, &handleBattery);
|
||||||
auto rosout_sub = nh.subscribe("/rosout_agg", 1, &handleLog);
|
auto rosout_sub = nh.subscribe("/rosout_agg", 1, &handleLog);
|
||||||
|
|
||||||
timer = nh.createTimer(ros::Duration(0), &proceed, false, false);
|
timer = nh.createTimer(ros::Duration(0), &proceed, false, false);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <dynamic_reconfigure/server.h>
|
#include <dynamic_reconfigure/server.h>
|
||||||
#include <mavros_msgs/OpticalFlowRad.h>
|
#include <mavros_msgs/OpticalFlowRad.h>
|
||||||
#include <sensor_msgs/Imu.h>
|
#include <sensor_msgs/Imu.h>
|
||||||
#include <geometry_msgs/PoseStamped.h>
|
|
||||||
#include <geometry_msgs/Vector3Stamped.h>
|
#include <geometry_msgs/Vector3Stamped.h>
|
||||||
#include <geometry_msgs/PointStamped.h>
|
#include <geometry_msgs/PointStamped.h>
|
||||||
#include <geometry_msgs/TwistStamped.h>
|
#include <geometry_msgs/TwistStamped.h>
|
||||||
@@ -58,9 +57,6 @@ private:
|
|||||||
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
std::unique_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||||
bool calc_flow_gyro_;
|
bool calc_flow_gyro_;
|
||||||
float flow_gyro_default_;
|
float flow_gyro_default_;
|
||||||
bool disable_on_vpe_;
|
|
||||||
ros::Subscriber vpe_sub_;
|
|
||||||
ros::Time last_vpe_time_;
|
|
||||||
std::shared_ptr<dynamic_reconfigure::Server<clover::FlowConfig>> dyn_srv_;
|
std::shared_ptr<dynamic_reconfigure::Server<clover::FlowConfig>> dyn_srv_;
|
||||||
|
|
||||||
void onInit()
|
void onInit()
|
||||||
@@ -91,11 +87,6 @@ private:
|
|||||||
|
|
||||||
img_sub_ = it.subscribeCamera("image_raw", 1, &OpticalFlow::flow, this);
|
img_sub_ = it.subscribeCamera("image_raw", 1, &OpticalFlow::flow, this);
|
||||||
|
|
||||||
disable_on_vpe_ = nh_priv.param("disable_on_vpe", false);
|
|
||||||
if (disable_on_vpe_) {
|
|
||||||
vpe_sub_ = nh.subscribe("mavros/vision_pose/pose", 1, &OpticalFlow::vpeCallback, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_srv_ = std::make_shared<dynamic_reconfigure::Server<clover::FlowConfig>>(nh_priv);
|
dyn_srv_ = std::make_shared<dynamic_reconfigure::Server<clover::FlowConfig>>(nh_priv);
|
||||||
dynamic_reconfigure::Server<clover::FlowConfig>::CallbackType cb;
|
dynamic_reconfigure::Server<clover::FlowConfig>::CallbackType cb;
|
||||||
|
|
||||||
@@ -130,12 +121,6 @@ private:
|
|||||||
{
|
{
|
||||||
if (!enabled_) return;
|
if (!enabled_) return;
|
||||||
|
|
||||||
if (disable_on_vpe_ &&
|
|
||||||
!last_vpe_time_.isZero() &&
|
|
||||||
(msg->header.stamp - last_vpe_time_).toSec() < 0.1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseCameraInfo(cinfo);
|
parseCameraInfo(cinfo);
|
||||||
|
|
||||||
auto img = cv_bridge::toCvShare(msg, "mono8")->image;
|
auto img = cv_bridge::toCvShare(msg, "mono8")->image;
|
||||||
@@ -251,14 +236,6 @@ private:
|
|||||||
prev_ = curr_.clone();
|
prev_ = curr_.clone();
|
||||||
prev_stamp_ = msg->header.stamp;
|
prev_stamp_ = msg->header.stamp;
|
||||||
|
|
||||||
// Publish estimated angular velocity
|
|
||||||
geometry_msgs::TwistStamped velo;
|
|
||||||
velo.header.stamp = msg->header.stamp;
|
|
||||||
velo.header.frame_id = fcu_frame_id_;
|
|
||||||
velo.twist.angular.x = flow_fcu.vector.x / integration_time.toSec();
|
|
||||||
velo.twist.angular.y = flow_fcu.vector.y / integration_time.toSec();
|
|
||||||
velo_pub_.publish(velo);
|
|
||||||
|
|
||||||
publish_debug:
|
publish_debug:
|
||||||
// Publish debug image
|
// Publish debug image
|
||||||
if (img_pub_.getNumSubscribers() > 0) {
|
if (img_pub_.getNumSubscribers() > 0) {
|
||||||
@@ -271,6 +248,14 @@ publish_debug:
|
|||||||
out_msg.image = img;
|
out_msg.image = img;
|
||||||
img_pub_.publish(out_msg.toImageMsg());
|
img_pub_.publish(out_msg.toImageMsg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Publish estimated angular velocity
|
||||||
|
geometry_msgs::TwistStamped velo;
|
||||||
|
velo.header.stamp = msg->header.stamp;
|
||||||
|
velo.header.frame_id = fcu_frame_id_;
|
||||||
|
velo.twist.angular.x = flow_fcu.vector.x / integration_time.toSec();
|
||||||
|
velo.twist.angular.y = flow_fcu.vector.y / integration_time.toSec();
|
||||||
|
velo_pub_.publish(velo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,10 +284,6 @@ publish_debug:
|
|||||||
prev_ = Mat(); // clear previous frame
|
prev_ = Mat(); // clear previous frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vpeCallback(const geometry_msgs::PoseStamped& vpe) {
|
|
||||||
last_vpe_time_ = vpe.header.stamp;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGINLIB_EXPORT_CLASS(OpticalFlow, nodelet::Nodelet)
|
PLUGINLIB_EXPORT_CLASS(OpticalFlow, nodelet::Nodelet)
|
||||||
|
|||||||
@@ -9,14 +9,13 @@
|
|||||||
# The above copyright notice and this permission notice shall be included in all
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
# copies or substantial portions of the Software.
|
# copies or substantial portions of the Software.
|
||||||
|
|
||||||
import os, sys
|
import os
|
||||||
import math
|
import math
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import traceback
|
import traceback
|
||||||
import threading
|
from threading import Event
|
||||||
from threading import Event, Thread, Lock
|
|
||||||
import numpy
|
import numpy
|
||||||
import rospy
|
import rospy
|
||||||
import tf2_ros
|
import tf2_ros
|
||||||
@@ -28,16 +27,24 @@ from mavros_msgs.msg import State, OpticalFlowRad, Mavlink
|
|||||||
from mavros_msgs.srv import ParamGet
|
from mavros_msgs.srv import ParamGet
|
||||||
from geometry_msgs.msg import PoseStamped, TwistStamped, PoseWithCovarianceStamped, Vector3Stamped
|
from geometry_msgs.msg import PoseStamped, TwistStamped, PoseWithCovarianceStamped, Vector3Stamped
|
||||||
from visualization_msgs.msg import MarkerArray as VisualizationMarkerArray
|
from visualization_msgs.msg import MarkerArray as VisualizationMarkerArray
|
||||||
from diagnostic_msgs.msg import DiagnosticArray
|
|
||||||
import tf.transformations as t
|
import tf.transformations as t
|
||||||
from aruco_pose.msg import MarkerArray
|
from aruco_pose.msg import MarkerArray
|
||||||
from mavros import mavlink
|
from mavros import mavlink
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: check attitude is present
|
||||||
|
# TODO: disk free space
|
||||||
|
# TODO: map, base_link, body
|
||||||
|
# TODO: rc service
|
||||||
|
# TODO: perform commander check, ekf2 status on PX4
|
||||||
|
# TODO: check if FCU params setter succeed
|
||||||
|
# TODO: selfcheck ROS service (with blacklists for checks)
|
||||||
|
|
||||||
|
|
||||||
rospy.init_node('selfcheck')
|
rospy.init_node('selfcheck')
|
||||||
|
|
||||||
os.environ['ROSCONSOLE_FORMAT']='${message}'
|
os.environ['ROSCONSOLE_FORMAT']='[${severity}]: ${message}'
|
||||||
|
|
||||||
# use user's locale to convert numbers, etc
|
# use user's locale to convert numbers, etc
|
||||||
locale.setlocale(locale.LC_ALL, '')
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
@@ -46,68 +53,46 @@ tf_buffer = tf2_ros.Buffer()
|
|||||||
tf_listener = tf2_ros.TransformListener(tf_buffer)
|
tf_listener = tf2_ros.TransformListener(tf_buffer)
|
||||||
|
|
||||||
|
|
||||||
thread_local = threading.local()
|
failures = []
|
||||||
reports_lock = Lock()
|
infos = []
|
||||||
|
current_check = None
|
||||||
|
|
||||||
# formatting colors
|
|
||||||
if sys.stdout.isatty():
|
|
||||||
GREY = '\033[90m'
|
|
||||||
GREEN = '\033[92m'
|
|
||||||
RED = '\033[31m'
|
|
||||||
END = '\033[0m'
|
|
||||||
else:
|
|
||||||
GREY = GREEN = RED = END = ''
|
|
||||||
|
|
||||||
|
|
||||||
def failure(text, *args):
|
def failure(text, *args):
|
||||||
msg = text % args
|
msg = text % args
|
||||||
thread_local.reports += [{'failure': msg}]
|
rospy.logwarn('%s: %s', current_check, msg)
|
||||||
|
failures.append(msg)
|
||||||
|
|
||||||
|
|
||||||
def info(text, *args):
|
def info(text, *args):
|
||||||
msg = text % args
|
msg = text % args
|
||||||
thread_local.reports += [{'info': msg}]
|
rospy.loginfo('%s: %s', current_check, msg)
|
||||||
|
infos.append(msg)
|
||||||
|
|
||||||
|
|
||||||
def check(name):
|
def check(name):
|
||||||
def inner(fn):
|
def inner(fn):
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
start = rospy.get_time()
|
failures[:] = []
|
||||||
thread_local.reports = []
|
infos[:] = []
|
||||||
|
global current_check
|
||||||
|
current_check = name
|
||||||
try:
|
try:
|
||||||
fn(*args, **kwargs)
|
fn(*args, **kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
rospy.logerr('%s: exception occurred', name)
|
rospy.logerr('%s: exception occurred', name)
|
||||||
with reports_lock:
|
return
|
||||||
for report in thread_local.reports:
|
if not failures and not infos:
|
||||||
if 'failure' in report:
|
rospy.loginfo('%s: OK', name)
|
||||||
rospy.logerr('%s: %s', name, report['failure'])
|
|
||||||
elif 'info' in report:
|
|
||||||
rospy.loginfo(GREY + name + END + ': ' + report['info'])
|
|
||||||
if not thread_local.reports:
|
|
||||||
rospy.loginfo(GREY + name + END + ': ' + GREEN + 'OK' + END)
|
|
||||||
if rospy.get_param('~time', False):
|
|
||||||
rospy.loginfo('%s: %.1f sec', name, rospy.get_time() - start)
|
|
||||||
return wrapper
|
return wrapper
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
def ff(value, precision=2):
|
|
||||||
# safely format float or int
|
|
||||||
if value is None:
|
|
||||||
return RED + '???' + END
|
|
||||||
if isinstance(value, float):
|
|
||||||
return ('{:.' + str(precision + 1) + '}').format(value)
|
|
||||||
elif isinstance(value, int):
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
|
|
||||||
param_get = rospy.ServiceProxy('mavros/param/get', ParamGet)
|
param_get = rospy.ServiceProxy('mavros/param/get', ParamGet)
|
||||||
|
|
||||||
|
|
||||||
def get_param(name, default=None):
|
def get_param(name):
|
||||||
try:
|
try:
|
||||||
res = param_get(param_id=name)
|
res = param_get(param_id=name)
|
||||||
except rospy.ServiceException as e:
|
except rospy.ServiceException as e:
|
||||||
@@ -116,17 +101,12 @@ def get_param(name, default=None):
|
|||||||
|
|
||||||
if not res.success:
|
if not res.success:
|
||||||
failure('unable to retrieve PX4 parameter %s', name)
|
failure('unable to retrieve PX4 parameter %s', name)
|
||||||
return default
|
|
||||||
else:
|
else:
|
||||||
if res.value.integer != 0:
|
if res.value.integer != 0:
|
||||||
return res.value.integer
|
return res.value.integer
|
||||||
return res.value.real
|
return res.value.real
|
||||||
|
|
||||||
|
|
||||||
def get_paramf(name, precision=2):
|
|
||||||
return ff(get_param(name), precision)
|
|
||||||
|
|
||||||
|
|
||||||
recv_event = Event()
|
recv_event = Event()
|
||||||
link = mavutil.mavlink.MAVLink('', 255, 1)
|
link = mavutil.mavlink.MAVLink('', 255, 1)
|
||||||
mavlink_pub = rospy.Publisher('mavlink/to', Mavlink, queue_size=1)
|
mavlink_pub = rospy.Publisher('mavlink/to', Mavlink, queue_size=1)
|
||||||
@@ -171,24 +151,6 @@ def mavlink_exec(cmd, timeout=3.0):
|
|||||||
return mavlink_recv
|
return mavlink_recv
|
||||||
|
|
||||||
|
|
||||||
def read_diagnostics(name, key):
|
|
||||||
e = Event()
|
|
||||||
def cb(msg):
|
|
||||||
for status in msg.status:
|
|
||||||
if status.name.lower() == name.lower():
|
|
||||||
for value in status.values:
|
|
||||||
if value.key.lower() == key.lower():
|
|
||||||
cb.value = value.value
|
|
||||||
e.set()
|
|
||||||
return
|
|
||||||
|
|
||||||
cb.value = None
|
|
||||||
sub = rospy.Subscriber('/diagnostics', DiagnosticArray, cb)
|
|
||||||
e.wait(1.0) # wait to read all the diagnostics from nodes publishing them
|
|
||||||
sub.unregister()
|
|
||||||
return cb.value
|
|
||||||
|
|
||||||
|
|
||||||
BOARD_ROTATIONS = {
|
BOARD_ROTATIONS = {
|
||||||
0: 'no rotation',
|
0: 'no rotation',
|
||||||
1: 'yaw 45°',
|
1: 'yaw 45°',
|
||||||
@@ -234,31 +196,29 @@ def check_fcu():
|
|||||||
state = rospy.wait_for_message('mavros/state', State, timeout=3)
|
state = rospy.wait_for_message('mavros/state', State, timeout=3)
|
||||||
if not state.connected:
|
if not state.connected:
|
||||||
failure('no connection to the FCU (check wiring)')
|
failure('no connection to the FCU (check wiring)')
|
||||||
info('fcu_url = %s', rospy.get_param('mavros/fcu_url', '?'))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if not is_process_running('px4', exact=True): # can't use px4 console in SITL
|
clover_tag = re.compile(r'-cl[oe]ver\.\d+$')
|
||||||
clover_tag = re.compile(r'-cl[oe]ver\.\d+$')
|
clover_fw = False
|
||||||
clover_fw = False
|
|
||||||
|
|
||||||
# Make sure the console is available to us
|
# Make sure the console is available to us
|
||||||
mavlink_exec('\n')
|
mavlink_exec('\n')
|
||||||
version_str = mavlink_exec('ver all')
|
version_str = mavlink_exec('ver all')
|
||||||
if version_str == '':
|
if version_str == '':
|
||||||
info('no version data available from SITL')
|
info('no version data available from SITL')
|
||||||
|
|
||||||
for line in version_str.split('\n'):
|
for line in version_str.split('\n'):
|
||||||
if line.startswith('FW version: '):
|
if line.startswith('FW version: '):
|
||||||
info(line[len('FW version: '):])
|
info(line[len('FW version: '):])
|
||||||
elif line.startswith('FW git tag: '): # only Clover's firmware
|
elif line.startswith('FW git tag: '): # only Clover's firmware
|
||||||
tag = line[len('FW git tag: '):]
|
tag = line[len('FW git tag: '):]
|
||||||
clover_fw = clover_tag.search(tag)
|
clover_fw = clover_tag.search(tag)
|
||||||
info(tag)
|
info(tag)
|
||||||
elif line.startswith('HW arch: '):
|
elif line.startswith('HW arch: '):
|
||||||
info(line[len('HW arch: '):])
|
info(line[len('HW arch: '):])
|
||||||
|
|
||||||
if not clover_fw:
|
if not clover_fw:
|
||||||
info('not Clover PX4 firmware, check https://clover.coex.tech/firmware')
|
info('not Clover PX4 firmware, check https://clover.coex.tech/firmware')
|
||||||
|
|
||||||
est = get_param('SYS_MC_EST_GROUP')
|
est = get_param('SYS_MC_EST_GROUP')
|
||||||
if est == 1:
|
if est == 1:
|
||||||
@@ -295,29 +255,21 @@ def check_fcu():
|
|||||||
if cbrk_usb_chk != 197848:
|
if cbrk_usb_chk != 197848:
|
||||||
failure('set parameter CBRK_USB_CHK to 197848 for flying with USB connected')
|
failure('set parameter CBRK_USB_CHK to 197848 for flying with USB connected')
|
||||||
|
|
||||||
if not is_process_running('px4', exact=True): # skip battery check in SITL
|
|
||||||
try:
|
|
||||||
battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3)
|
|
||||||
if not battery.cell_voltage:
|
|
||||||
failure('cell voltage is not available, https://clover.coex.tech/power')
|
|
||||||
else:
|
|
||||||
cell = battery.cell_voltage[0]
|
|
||||||
if cell > 4.3 or cell < 3.0:
|
|
||||||
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell)
|
|
||||||
elif cell < 3.7:
|
|
||||||
failure('critically low cell voltage: %.2f V, recharge battery', cell)
|
|
||||||
except rospy.ROSException:
|
|
||||||
failure('no battery state')
|
|
||||||
|
|
||||||
# time sync check
|
|
||||||
try:
|
try:
|
||||||
info('time sync offset: %.2f s', float(read_diagnostics('mavros: Time Sync', 'Estimated time offset (s)')))
|
battery = rospy.wait_for_message('mavros/battery', BatteryState, timeout=3)
|
||||||
except:
|
if not battery.cell_voltage:
|
||||||
failure('cannot read time sync offset')
|
failure('cell voltage is not available, https://clover.coex.tech/power')
|
||||||
|
else:
|
||||||
|
cell = battery.cell_voltage[0]
|
||||||
|
if cell > 4.3 or cell < 3.0:
|
||||||
|
failure('incorrect cell voltage: %.2f V, https://clover.coex.tech/power', cell)
|
||||||
|
elif cell < 3.7:
|
||||||
|
failure('critically low cell voltage: %.2f V, recharge battery', cell)
|
||||||
|
except rospy.ROSException:
|
||||||
|
failure('no battery state')
|
||||||
|
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
failure('no MAVROS state (check wiring)')
|
failure('no MAVROS state (check wiring)')
|
||||||
info('fcu_url = %s', rospy.get_param('mavros/fcu_url', '?'))
|
|
||||||
|
|
||||||
|
|
||||||
def describe_direction(v):
|
def describe_direction(v):
|
||||||
@@ -394,24 +346,19 @@ def is_process_running(binary, exact=False, full=False):
|
|||||||
|
|
||||||
@check('ArUco markers')
|
@check('ArUco markers')
|
||||||
def check_aruco():
|
def check_aruco():
|
||||||
markers = None
|
|
||||||
|
|
||||||
if is_process_running('aruco_detect', full=True):
|
if is_process_running('aruco_detect', full=True):
|
||||||
try:
|
try:
|
||||||
info('aruco_detect/length = %g m', rospy.get_param('aruco_detect/length', '?'))
|
info('aruco_detect/length = %g m', rospy.get_param('aruco_detect/length'))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
failure('aruco_detect/length parameter is not set')
|
failure('aruco_detect/length parameter is not set')
|
||||||
known_vertical = rospy.get_param('aruco_detect/known_vertical', '')
|
known_tilt = rospy.get_param('aruco_detect/known_tilt', '')
|
||||||
flip_vertical = rospy.get_param('aruco_detect/flip_vertical', False)
|
if known_tilt == 'map':
|
||||||
description = ''
|
known_tilt += ' (ALL markers are on the floor)'
|
||||||
if known_vertical == 'map' and not flip_vertical:
|
elif known_tilt == 'map_flipped':
|
||||||
description = ' (all markers are on the floor)'
|
known_tilt += ' (ALL markers are on the ceiling)'
|
||||||
elif known_vertical == 'map' and flip_vertical:
|
info('aruco_detector/known_tilt = %s', known_tilt)
|
||||||
description = ' (all markers are on the ceiling)'
|
|
||||||
info('aruco_detect/known_vertical = %s', known_vertical)
|
|
||||||
info('aruco_detect/flip_vertical = %s%s', flip_vertical, description)
|
|
||||||
try:
|
try:
|
||||||
markers = rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=0.8)
|
rospy.wait_for_message('aruco_detect/markers', MarkerArray, timeout=1)
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
failure('no markers detection')
|
failure('no markers detection')
|
||||||
return
|
return
|
||||||
@@ -420,61 +367,42 @@ def check_aruco():
|
|||||||
return
|
return
|
||||||
|
|
||||||
if is_process_running('aruco_map', full=True):
|
if is_process_running('aruco_map', full=True):
|
||||||
known_vertical = rospy.get_param('aruco_map/known_vertical', '')
|
known_tilt = rospy.get_param('aruco_map/known_tilt', '')
|
||||||
flip_vertical = rospy.get_param('aruco_map/flip_vertical', False)
|
if known_tilt == 'map':
|
||||||
description = ''
|
known_tilt += ' (marker\'s map is on the floor)'
|
||||||
if known_vertical == 'map' and not flip_vertical:
|
elif known_tilt == 'map_flipped':
|
||||||
description += ' (markers map is on the floor)'
|
known_tilt += ' (marker\'s map is on the ceiling)'
|
||||||
elif known_vertical == 'map' and flip_vertical:
|
info('aruco_map/known_tilt = %s', known_tilt)
|
||||||
description += ' (markers map is on the ceiling)'
|
|
||||||
info('aruco_map/known_vertical = %s', known_vertical)
|
|
||||||
info('aruco_map/flip_vertical = %s%s', flip_vertical, description)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
visualization = rospy.wait_for_message('aruco_map/visualization', VisualizationMarkerArray, timeout=0.8)
|
visualization = rospy.wait_for_message('aruco_map/visualization', VisualizationMarkerArray, timeout=1)
|
||||||
info('map has %s markers', len(visualization.markers))
|
info('map has %s markers', len(visualization.markers))
|
||||||
except:
|
except:
|
||||||
failure('cannot read aruco_map/visualization topic')
|
failure('cannot read aruco_map/visualization topic')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=0.8)
|
rospy.wait_for_message('aruco_map/pose', PoseWithCovarianceStamped, timeout=1)
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
if not markers:
|
failure('no map detection')
|
||||||
info('no map detection as no markers detection')
|
|
||||||
elif not markers.markers:
|
|
||||||
info('no map detection as no markers detected')
|
|
||||||
else:
|
|
||||||
failure('no map detection')
|
|
||||||
else:
|
else:
|
||||||
info('aruco_map is not running')
|
info('aruco_map is not running')
|
||||||
|
|
||||||
|
|
||||||
def is_on_the_floor():
|
|
||||||
try:
|
|
||||||
dist = rospy.wait_for_message('rangefinder/range', Range, timeout=1)
|
|
||||||
return dist.range < 0.3
|
|
||||||
except rospy.ROSException:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
@check('Vision position estimate')
|
@check('Vision position estimate')
|
||||||
def check_vpe():
|
def check_vpe():
|
||||||
vis = None
|
vis = None
|
||||||
try:
|
try:
|
||||||
vis = rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=0.8)
|
vis = rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=1)
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
try:
|
try:
|
||||||
vis = rospy.wait_for_message('mavros/mocap/pose', PoseStamped, timeout=0.8)
|
vis = rospy.wait_for_message('mavros/mocap/pose', PoseStamped, timeout=1)
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
if not is_process_running('vpe_publisher', full=True):
|
failure('no VPE or MoCap messages')
|
||||||
info('no vision position estimate, vpe_publisher is not running')
|
# check if vpe_publisher is running
|
||||||
elif rospy.get_param('aruco_map/known_vertical', '') == 'map' \
|
try:
|
||||||
and rospy.get_param('aruco_map/flip_vertical', False):
|
subprocess.check_output(['pgrep', '-x', 'vpe_publisher'])
|
||||||
failure('no vision position estimate, markers are on the ceiling')
|
except subprocess.CalledProcessError:
|
||||||
elif is_on_the_floor():
|
return # it's not running, skip following checks
|
||||||
info('no vision position estimate, the drone is on the floor')
|
|
||||||
else:
|
|
||||||
failure('no vision position estimate')
|
|
||||||
|
|
||||||
# check PX4 settings
|
# check PX4 settings
|
||||||
est = get_param('SYS_MC_EST_GROUP')
|
est = get_param('SYS_MC_EST_GROUP')
|
||||||
@@ -486,14 +414,14 @@ def check_vpe():
|
|||||||
if vision_yaw_w == 0:
|
if vision_yaw_w == 0:
|
||||||
failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter')
|
failure('vision yaw weight is zero, change ATT_W_EXT_HDG parameter')
|
||||||
else:
|
else:
|
||||||
info('vision yaw weight: %s', ff(vision_yaw_w))
|
info('Vision yaw weight: %.2f', vision_yaw_w)
|
||||||
fuse = get_param('LPE_FUSION')
|
fuse = get_param('LPE_FUSION')
|
||||||
if not fuse & (1 << 2):
|
if not fuse & (1 << 2):
|
||||||
failure('vision position fusion is disabled, change LPE_FUSION parameter')
|
failure('vision position fusion is disabled, change LPE_FUSION parameter')
|
||||||
delay = get_param('LPE_VIS_DELAY')
|
delay = get_param('LPE_VIS_DELAY')
|
||||||
if delay != 0:
|
if delay != 0:
|
||||||
failure('LPE_VIS_DELAY = %s, but it should be zero', delay)
|
failure('LPE_VIS_DELAY parameter is %s, but it should be zero', delay)
|
||||||
info('LPE_VIS_XY = %s m, LPE_VIS_Z = %s m', get_paramf('LPE_VIS_XY'), get_paramf('LPE_VIS_Z'))
|
info('LPE_VIS_XY is %.2f m, LPE_VIS_Z is %.2f m', get_param('LPE_VIS_XY'), get_param('LPE_VIS_Z'))
|
||||||
elif est == 2:
|
elif est == 2:
|
||||||
fuse = get_param('EKF2_AID_MASK')
|
fuse = get_param('EKF2_AID_MASK')
|
||||||
if not fuse & (1 << 3):
|
if not fuse & (1 << 3):
|
||||||
@@ -502,10 +430,10 @@ def check_vpe():
|
|||||||
failure('vision yaw fusion is disabled, change EKF2_AID_MASK parameter')
|
failure('vision yaw fusion is disabled, change EKF2_AID_MASK parameter')
|
||||||
delay = get_param('EKF2_EV_DELAY')
|
delay = get_param('EKF2_EV_DELAY')
|
||||||
if delay != 0:
|
if delay != 0:
|
||||||
failure('EKF2_EV_DELAY = %.2f, but it should be zero', delay)
|
failure('EKF2_EV_DELAY is %.2f, but it should be zero', delay)
|
||||||
info('EKF2_EVA_NOISE = %s, EKF2_EVP_NOISE = %s',
|
info('EKF2_EVA_NOISE is %.3f, EKF2_EVP_NOISE is %.3f',
|
||||||
get_paramf('EKF2_EVA_NOISE', 3),
|
get_param('EKF2_EVA_NOISE'),
|
||||||
get_paramf('EKF2_EVP_NOISE', 3))
|
get_param('EKF2_EVP_NOISE'))
|
||||||
|
|
||||||
if not vis:
|
if not vis:
|
||||||
return
|
return
|
||||||
@@ -603,19 +531,15 @@ def check_velocity():
|
|||||||
@check('Global position (GPS)')
|
@check('Global position (GPS)')
|
||||||
def check_global_position():
|
def check_global_position():
|
||||||
try:
|
try:
|
||||||
rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=0.8)
|
rospy.wait_for_message('mavros/global_position/global', NavSatFix, timeout=1)
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
info('no global position')
|
info('no global position')
|
||||||
if get_param('SYS_MC_EST_GROUP') == 2 and (get_param('EKF2_AID_MASK', 0) & (1 << 0)):
|
if get_param('SYS_MC_EST_GROUP') == 2 and (get_param('EKF2_AID_MASK') & (1 << 0)):
|
||||||
failure('enabled GPS fusion may suppress vision position aiding')
|
failure('enabled GPS fusion may suppress vision position aiding')
|
||||||
|
|
||||||
|
|
||||||
@check('Optical flow')
|
@check('Optical flow')
|
||||||
def check_optical_flow():
|
def check_optical_flow():
|
||||||
if not is_process_running('optical_flow', full=True):
|
|
||||||
info('optical_flow is not running')
|
|
||||||
return
|
|
||||||
|
|
||||||
# TODO:check FPS!
|
# TODO:check FPS!
|
||||||
try:
|
try:
|
||||||
rospy.wait_for_message('mavros/px4flow/raw/send', OpticalFlowRad, timeout=0.5)
|
rospy.wait_for_message('mavros/px4flow/raw/send', OpticalFlowRad, timeout=0.5)
|
||||||
@@ -623,7 +547,7 @@ def check_optical_flow():
|
|||||||
# check PX4 settings
|
# check PX4 settings
|
||||||
rot = get_param('SENS_FLOW_ROT')
|
rot = get_param('SENS_FLOW_ROT')
|
||||||
if rot != 0:
|
if rot != 0:
|
||||||
failure('SENS_FLOW_ROT = %s, but it should be zero', rot)
|
failure('SENS_FLOW_ROT parameter is %s, but it should be zero', rot)
|
||||||
est = get_param('SYS_MC_EST_GROUP')
|
est = get_param('SYS_MC_EST_GROUP')
|
||||||
if est == 1:
|
if est == 1:
|
||||||
fuse = get_param('LPE_FUSION')
|
fuse = get_param('LPE_FUSION')
|
||||||
@@ -631,36 +555,32 @@ def check_optical_flow():
|
|||||||
failure('optical flow fusion is disabled, change LPE_FUSION parameter')
|
failure('optical flow fusion is disabled, change LPE_FUSION parameter')
|
||||||
if not fuse & (1 << 1):
|
if not fuse & (1 << 1):
|
||||||
failure('flow gyro compensation is disabled, change LPE_FUSION parameter')
|
failure('flow gyro compensation is disabled, change LPE_FUSION parameter')
|
||||||
scale = get_param('LPE_FLW_SCALE', 1)
|
scale = get_param('LPE_FLW_SCALE')
|
||||||
if not numpy.isclose(scale, 1.0):
|
if not numpy.isclose(scale, 1.0):
|
||||||
failure('LPE_FLW_SCALE = %.2f, but it should be 1.0', scale)
|
failure('LPE_FLW_SCALE parameter is %.2f, but it should be 1.0', scale)
|
||||||
|
|
||||||
info('LPE_FLW_QMIN = %s, LPE_FLW_R = %s, LPE_FLW_RR = %s',
|
info('LPE_FLW_QMIN is %s, LPE_FLW_R is %.4f, LPE_FLW_RR is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f',
|
||||||
get_paramf('LPE_FLW_QMIN'),
|
get_param('LPE_FLW_QMIN'),
|
||||||
get_paramf('LPE_FLW_R', 4),
|
get_param('LPE_FLW_R'),
|
||||||
get_paramf('LPE_FLW_RR', 4))
|
get_param('LPE_FLW_RR'),
|
||||||
|
get_param('SENS_FLOW_MINHGT'),
|
||||||
|
get_param('SENS_FLOW_MAXHGT'))
|
||||||
elif est == 2:
|
elif est == 2:
|
||||||
fuse = get_param('EKF2_AID_MASK', 0)
|
fuse = get_param('EKF2_AID_MASK')
|
||||||
if not fuse & (1 << 1):
|
if not fuse & (1 << 1):
|
||||||
failure('optical flow fusion is disabled, change EKF2_AID_MASK parameter')
|
failure('optical flow fusion is disabled, change EKF2_AID_MASK parameter')
|
||||||
delay = get_param('EKF2_OF_DELAY', 0)
|
delay = get_param('EKF2_OF_DELAY')
|
||||||
if delay != 0:
|
if delay != 0:
|
||||||
failure('EKF2_OF_DELAY = %.2f, but it should be zero', delay)
|
failure('EKF2_OF_DELAY is %.2f, but it should be zero', delay)
|
||||||
info('EKF2_OF_QMIN = %s, EKF2_OF_N_MIN = %s, EKF2_OF_N_MAX = %s',
|
info('EKF2_OF_QMIN is %s, EKF2_OF_N_MIN is %.4f, EKF2_OF_N_MAX is %.4f, SENS_FLOW_MINHGT is %.3f, SENS_FLOW_MAXHGT is %.3f',
|
||||||
get_paramf('EKF2_OF_QMIN'),
|
get_param('EKF2_OF_QMIN'),
|
||||||
get_paramf('EKF2_OF_N_MIN', 4),
|
get_param('EKF2_OF_N_MIN'),
|
||||||
get_paramf('EKF2_OF_N_MAX', 4))
|
get_param('EKF2_OF_N_MAX'),
|
||||||
info('SENS_FLOW_MINHGT = %s, SENS_FLOW_MAXHGT = %s', get_paramf('SENS_FLOW_MINHGT', 3), get_paramf('SENS_FLOW_MAXHGT', 3))
|
get_param('SENS_FLOW_MINHGT'),
|
||||||
|
get_param('SENS_FLOW_MAXHGT'))
|
||||||
|
|
||||||
except rospy.ROSException:
|
except rospy.ROSException:
|
||||||
if rospy.get_param('optical_flow/disable_on_vpe', False):
|
failure('no optical flow data (from Raspberry)')
|
||||||
try:
|
|
||||||
rospy.wait_for_message('mavros/vision_pose/pose', PoseStamped, timeout=1)
|
|
||||||
info('no optical flow as disable_on_vpe is true')
|
|
||||||
except:
|
|
||||||
failure('no optical flow on RPi, disable_on_vpe is true, but no vision pose also')
|
|
||||||
else:
|
|
||||||
failure('no optical flow on RPi')
|
|
||||||
|
|
||||||
|
|
||||||
@check('Rangefinder')
|
@check('Rangefinder')
|
||||||
@@ -684,7 +604,7 @@ def check_rangefinder():
|
|||||||
|
|
||||||
est = get_param('SYS_MC_EST_GROUP')
|
est = get_param('SYS_MC_EST_GROUP')
|
||||||
if est == 1:
|
if est == 1:
|
||||||
fuse = get_param('LPE_FUSION', 0)
|
fuse = get_param('LPE_FUSION')
|
||||||
if not fuse & (1 << 5):
|
if not fuse & (1 << 5):
|
||||||
info('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface')
|
info('"pub agl as lpos down" in LPE_FUSION is disabled, NOT operating over flat surface')
|
||||||
else:
|
else:
|
||||||
@@ -718,7 +638,7 @@ def check_boot_duration():
|
|||||||
|
|
||||||
@check('CPU usage')
|
@check('CPU usage')
|
||||||
def check_cpu_usage():
|
def check_cpu_usage():
|
||||||
WHITELIST = 'nodelet', 'gzclient', 'gzserver', 'selfcheck.py'
|
WHITELIST = 'nodelet', 'gzclient', 'gzserver'
|
||||||
CMD = "top -n 1 -b -i | tail -n +8 | awk '{ printf(\"%-8s\\t%-8s\\t%-8s\\n\", $1, $9, $12); }'"
|
CMD = "top -n 1 -b -i | tail -n +8 | awk '{ printf(\"%-8s\\t%-8s\\t%-8s\\n\", $1, $9, $12); }'"
|
||||||
output = subprocess.check_output(CMD, shell=True).decode()
|
output = subprocess.check_output(CMD, shell=True).decode()
|
||||||
processes = output.split('\n')
|
processes = output.split('\n')
|
||||||
@@ -787,10 +707,7 @@ def check_image():
|
|||||||
try:
|
try:
|
||||||
info('version: %s', open('/etc/clover_version').read().strip())
|
info('version: %s', open('/etc/clover_version').read().strip())
|
||||||
except IOError:
|
except IOError:
|
||||||
try:
|
info('no /etc/clover_version file, not the Clover image?')
|
||||||
info('VM version: %s', open('/etc/clover_vm_version').read().strip())
|
|
||||||
except IOError:
|
|
||||||
info('no /etc/clover_version file, not the Clover image?')
|
|
||||||
|
|
||||||
|
|
||||||
@check('Preflight status')
|
@check('Preflight status')
|
||||||
@@ -901,47 +818,26 @@ def check_board():
|
|||||||
info('could not open /proc/device-tree/model, not a Raspberry Pi?')
|
info('could not open /proc/device-tree/model, not a Raspberry Pi?')
|
||||||
|
|
||||||
|
|
||||||
def parallel_for(fns):
|
|
||||||
threads = []
|
|
||||||
for fn in fns:
|
|
||||||
thread = Thread(target=fn)
|
|
||||||
thread.start()
|
|
||||||
threads.append(thread)
|
|
||||||
for thread in threads:
|
|
||||||
thread.join()
|
|
||||||
|
|
||||||
|
|
||||||
def consequentially_for(fns):
|
|
||||||
for fn in fns:
|
|
||||||
fn()
|
|
||||||
|
|
||||||
|
|
||||||
def selfcheck():
|
def selfcheck():
|
||||||
checks = [
|
check_image()
|
||||||
check_image,
|
check_board()
|
||||||
check_board,
|
check_clover_service()
|
||||||
check_clover_service,
|
check_network()
|
||||||
check_network,
|
check_fcu()
|
||||||
check_fcu,
|
check_imu()
|
||||||
check_imu,
|
check_local_position()
|
||||||
check_local_position,
|
check_velocity()
|
||||||
check_velocity,
|
check_global_position()
|
||||||
check_global_position,
|
check_preflight_status()
|
||||||
check_preflight_status,
|
check_main_camera()
|
||||||
check_main_camera,
|
check_aruco()
|
||||||
check_aruco,
|
check_simpleoffboard()
|
||||||
check_simpleoffboard,
|
check_optical_flow()
|
||||||
check_optical_flow,
|
check_vpe()
|
||||||
check_vpe,
|
check_rangefinder()
|
||||||
check_rangefinder,
|
check_rpi_health()
|
||||||
check_rpi_health,
|
check_cpu_usage()
|
||||||
check_cpu_usage,
|
check_boot_duration()
|
||||||
check_boot_duration,
|
|
||||||
]
|
|
||||||
if rospy.get_param('~parallel', False):
|
|
||||||
parallel_for(checks)
|
|
||||||
else:
|
|
||||||
consequentially_for(checks)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -860,13 +860,6 @@ bool land(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool release(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res)
|
|
||||||
{
|
|
||||||
setpoint_timer.stop();
|
|
||||||
res.success = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
ros::init(argc, argv, "simple_offboard");
|
ros::init(argc, argv, "simple_offboard");
|
||||||
@@ -940,7 +933,6 @@ int main(int argc, char **argv)
|
|||||||
auto sa_serv = nh.advertiseService("set_attitude", &setAttitude);
|
auto sa_serv = nh.advertiseService("set_attitude", &setAttitude);
|
||||||
auto sr_serv = nh.advertiseService("set_rates", &setRates);
|
auto sr_serv = nh.advertiseService("set_rates", &setRates);
|
||||||
auto ld_serv = nh.advertiseService("land", &land);
|
auto ld_serv = nh.advertiseService("land", &land);
|
||||||
auto rl_serv = nh_priv.advertiseService("release", &release);
|
|
||||||
|
|
||||||
// Setpoint timer
|
// Setpoint timer
|
||||||
setpoint_timer = nh.createTimer(ros::Duration(1 / nh_priv.param("setpoint_rate", 30.0)), &publishSetpoint, false, false);
|
setpoint_timer = nh.createTimer(ros::Duration(1 / nh_priv.param("setpoint_rate", 30.0)), &publishSetpoint, false, false);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
using std::string;
|
using std::string;
|
||||||
using namespace geometry_msgs;
|
using namespace geometry_msgs;
|
||||||
|
|
||||||
bool reset_flag = true; // offset should be reset on the start
|
bool reset_flag = false;
|
||||||
string local_frame_id, frame_id, child_frame_id, offset_frame_id;
|
string local_frame_id, frame_id, child_frame_id, offset_frame_id;
|
||||||
tf2_ros::Buffer tf_buffer;
|
tf2_ros::Buffer tf_buffer;
|
||||||
ros::Publisher vpe_pub;
|
ros::Publisher vpe_pub;
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
export ROSWWW_DEFAULT=clover
|
|
||||||
rosrun roswww_static update
|
|
||||||
@@ -3,7 +3,6 @@ import rospy
|
|||||||
import pytest
|
import pytest
|
||||||
from mavros_msgs.msg import State
|
from mavros_msgs.msg import State
|
||||||
from clover import srv
|
from clover import srv
|
||||||
import time
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def node():
|
def node():
|
||||||
@@ -25,7 +24,6 @@ def test_simple_offboard_services_available():
|
|||||||
rospy.wait_for_service('set_attitude', timeout=5)
|
rospy.wait_for_service('set_attitude', timeout=5)
|
||||||
rospy.wait_for_service('set_rates', timeout=5)
|
rospy.wait_for_service('set_rates', timeout=5)
|
||||||
rospy.wait_for_service('land', timeout=5)
|
rospy.wait_for_service('land', timeout=5)
|
||||||
rospy.wait_for_service('simple_offboard/release', timeout=5)
|
|
||||||
|
|
||||||
def test_web_video_server(node):
|
def test_web_video_server(node):
|
||||||
try:
|
try:
|
||||||
@@ -61,18 +59,3 @@ def test_blocks(node):
|
|||||||
|
|
||||||
t.join()
|
t.join()
|
||||||
assert wait_print.result == 'test'
|
assert wait_print.result == 'test'
|
||||||
|
|
||||||
def test_long_callback():
|
|
||||||
from clover import long_callback
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
# very basic test for long_callback
|
|
||||||
@long_callback
|
|
||||||
def cb(i):
|
|
||||||
cb.counter += i
|
|
||||||
cb.counter = 0
|
|
||||||
cb(2)
|
|
||||||
sleep(0.1)
|
|
||||||
cb(3)
|
|
||||||
sleep(1)
|
|
||||||
assert cb.counter == 5
|
|
||||||
|
|||||||
@@ -37,9 +37,6 @@
|
|||||||
|
|
||||||
<node name="clover_blocks" pkg="clover_blocks" type="clover_blocks" output="screen" required="true"/>
|
<node name="clover_blocks" pkg="clover_blocks" type="clover_blocks" output="screen" required="true"/>
|
||||||
|
|
||||||
<node pkg="topic_tools" name="main_camera_throttle" type="throttle" ns="main_camera"
|
|
||||||
args="messages image_raw 5.0 image_raw_throttled" required="true"/>
|
|
||||||
|
|
||||||
<param name="test_module" value="$(find clover)/test/basic.py"/>
|
<param name="test_module" value="$(find clover)/test/basic.py"/>
|
||||||
<test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner"/>
|
<test test-name="basic_test" pkg="ros_pytest" type="ros_pytest_runner"/>
|
||||||
</launch>
|
</launch>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<robot name="rpi_camera" xmlns:xacro="http://ros.org/wiki/xacro">
|
<robot name="rpi_camera" xmlns:xacro="http://ros.org/wiki/xacro">
|
||||||
<xacro:include filename="../camera_sensor.urdf.xacro"/>
|
<xacro:include filename="../camera_sensor.urdf.xacro"/>
|
||||||
|
|
||||||
<xacro:macro name="distance_sensor" params="name:=lidar_vl53l1x parent x:=0 y:=0 z:=0 roll:=0 pitch:=0 yaw:=0 range_min:=0.01 range_max:=4.0 resolution:=0.01 rate:=10 fov:=0.471239">
|
<xacro:macro name="distance_sensor" params="name:=lidar_vl53l1x parent x:=0 y:=0 z:=0 roll:=0 pitch:=0 yaw:=0 range_min:=0.01 range_max:=4.0 resolution:=0.01 rate:=10">
|
||||||
<joint name="${name}_joint" type="fixed">
|
<joint name="${name}_joint" type="fixed">
|
||||||
<origin xyz="${x} ${y} ${z}"
|
<origin xyz="${x} ${y} ${z}"
|
||||||
rpy="${roll} ${pitch} ${yaw}"/>
|
rpy="${roll} ${pitch} ${yaw}"/>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<topicName>/rangefinder/range</topicName>
|
<topicName>/rangefinder/range</topicName>
|
||||||
<frameName>rangefinder</frameName>
|
<frameName>rangefinder</frameName>
|
||||||
<radiation>infrared</radiation>
|
<radiation>infrared</radiation>
|
||||||
<fov>${fov}</fov>
|
<fov>0.01</fov>
|
||||||
<gaussianNoise>0.001</gaussianNoise>
|
<gaussianNoise>0.001</gaussianNoise>
|
||||||
<updateRate>${rate}</updateRate>
|
<updateRate>${rate}</updateRate>
|
||||||
<min_distance>${range_min}</min_distance>
|
<min_distance>${range_min}</min_distance>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<package format="3">
|
<package format="2">
|
||||||
<name>clover_simulation</name>
|
<name>clover_simulation</name>
|
||||||
<version>0.23.0</version>
|
<version>0.23.0</version>
|
||||||
<description>The clover_simulation package provides worlds and launch files for Gazebo.</description>
|
<description>The clover_simulation package provides worlds and launch files for Gazebo.</description>
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
<depend>gazebo_ros</depend>
|
<depend>gazebo_ros</depend>
|
||||||
<depend>gazebo_plugins</depend>
|
<depend>gazebo_plugins</depend>
|
||||||
<depend>rospy</depend>
|
<depend>rospy</depend>
|
||||||
<depend condition="$ROS_PYTHON_VERSION == 2">python-docopt</depend>
|
|
||||||
<depend condition="$ROS_PYTHON_VERSION == 3">python3-docopt</depend>
|
|
||||||
|
|
||||||
<export>
|
<export>
|
||||||
<gazebo_ros gazebo_media_path="${prefix}"/>
|
<gazebo_ros gazebo_media_path="${prefix}"/>
|
||||||
|
|||||||
@@ -65,8 +65,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
role = (ros::this_node::getName() == "/gazebo") ? Role::Server : Role::Client;
|
role = (ros::this_node::getName() == "/gazebo") ? Role::Server : Role::Client;
|
||||||
ROS_INFO_NAMED(("LedController_" + robotNamespace).c_str(), "LedController has started (as %s) in namespace '%s'",
|
ROS_INFO_NAMED(("LedController_" + robotNamespace).c_str(), "LedController has started (as %s)", role == Role::Client ? "client" : "server");
|
||||||
role == Role::Client ? "client" : "server", robotNamespace.c_str());
|
|
||||||
|
|
||||||
nh.reset(new ros::NodeHandle(robotNamespace));
|
nh.reset(new ros::NodeHandle(robotNamespace));
|
||||||
|
|
||||||
@@ -110,6 +109,7 @@ LedController& get(std::string robotNamespace)
|
|||||||
std::lock_guard<std::mutex> lock(controllerMutex);
|
std::lock_guard<std::mutex> lock(controllerMutex);
|
||||||
auto it = controllers.find(robotNamespace);
|
auto it = controllers.find(robotNamespace);
|
||||||
if (it == controllers.end()) {
|
if (it == controllers.end()) {
|
||||||
|
gzwarn << "Creating new LED controller for namespace " << robotNamespace << "\n";
|
||||||
controllers[robotNamespace].reset(new LedController(robotNamespace));
|
controllers[robotNamespace].reset(new LedController(robotNamespace));
|
||||||
return *controllers[robotNamespace];
|
return *controllers[robotNamespace];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,8 +145,6 @@ rospy.spin()
|
|||||||
|
|
||||||
The script will take up to 100% CPU capacity. To slow down the script artificially, you can use [throttling](http://wiki.ros.org/topic_tools/throttle) of frames from the camera, for example, at 5 Hz (`main_camera.launch`):
|
The script will take up to 100% CPU capacity. To slow down the script artificially, you can use [throttling](http://wiki.ros.org/topic_tools/throttle) of frames from the camera, for example, at 5 Hz (`main_camera.launch`):
|
||||||
|
|
||||||
> **Note** Starting from [image](image.md) version **0.24** `image_raw_throttled` topic is available without addition configuration.
|
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<node pkg="topic_tools" name="cam_throttle" type="throttle"
|
<node pkg="topic_tools" name="cam_throttle" type="throttle"
|
||||||
args="messages main_camera/image_raw 5.0 main_camera/image_raw_throttled"/>
|
args="messages main_camera/image_raw 5.0 main_camera/image_raw_throttled"/>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ The main goal of the contest is aerial robotics popularization and community de
|
|||||||
* Third parties can provide technical support for recording a lecture.
|
* Third parties can provide technical support for recording a lecture.
|
||||||
* The status of the participant is unlimited (student, representative of a general education institution, representative of the industry, amateur).
|
* The status of the participant is unlimited (student, representative of a general education institution, representative of the industry, amateur).
|
||||||
|
|
||||||
Applications deadline: November 30, 2022.
|
Applications deadline: September 1, 2022.
|
||||||
|
|
||||||
### How to apply?
|
### How to apply?
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ The main goal of the contest is aerial robotics popularization and community de
|
|||||||
|
|
||||||
The application to the contest is performed via the [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSdelVy6yQ1iN6u88KeiEIKGj7gGaM0xccSt2tiYKB46ICmjkQ/viewform).
|
The application to the contest is performed via the [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSdelVy6yQ1iN6u88KeiEIKGj7gGaM0xccSt2tiYKB46ICmjkQ/viewform).
|
||||||
|
|
||||||
Applications deadline: November 30, 2022.
|
Applications deadline: September 1, 2022.
|
||||||
|
|
||||||
### Prizes
|
### Prizes
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ The course is evaluated according to a separate, publicly available lesson submi
|
|||||||
|
|
||||||
The application to the contest is performed via the [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSdf2Q68X4hPnFE9f3EP95AxPNnzHKqIsFHtTRT6EBKiH93wzg/viewform) where the link to the video course should be attached.
|
The application to the contest is performed via the [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSdf2Q68X4hPnFE9f3EP95AxPNnzHKqIsFHtTRT6EBKiH93wzg/viewform) where the link to the video course should be attached.
|
||||||
|
|
||||||
Applications deadline: November 30, 2022.
|
Applications deadline: September 1, 2022.
|
||||||
|
|
||||||
### Prizes
|
### Prizes
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ Parameters:
|
|||||||
* `yaw_rate` – angular yaw velocity (will be used if yaw is set to `NaN`) *(rad/s)*;
|
* `yaw_rate` – angular yaw velocity (will be used if yaw is set to `NaN`) *(rad/s)*;
|
||||||
* `speed` – flight speed (setpoint speed) *(m/s)*;
|
* `speed` – flight speed (setpoint speed) *(m/s)*;
|
||||||
* `auto_arm` – switch the drone to `OFFBOARD` mode and arm automatically (**the drone will take off**);
|
* `auto_arm` – switch the drone to `OFFBOARD` mode and arm automatically (**the drone will take off**);
|
||||||
* `frame_id` – [coordinate system](frames.md) for values `x`, `y`, `z` and `yaw`. Example: `map`, `body`, `aruco_map`. Default value: `map`.
|
* `frame_id` – [coordinate system](frames.md) for values `x`, `y`, `z`, `vx`, `vy`, `vz`. Example: `map`, `body`, `aruco_map`. Default value: `map`.
|
||||||
|
|
||||||
> **Note** If you don't want to change your current yaw set the `yaw` parameter to `NaN` (angular velocity by default is 0).
|
> **Note** If you don't want to change your current yaw set the `yaw` parameter to `NaN` (angular velocity by default is 0).
|
||||||
|
|
||||||
@@ -305,16 +305,6 @@ rosservice call /land "{}"
|
|||||||
|
|
||||||
> **Caution** In recent PX4 versions, the vehicle will be switched out of LAND mode to manual mode, if the remote control sticks are moved significantly.
|
> **Caution** In recent PX4 versions, the vehicle will be switched out of LAND mode to manual mode, if the remote control sticks are moved significantly.
|
||||||
|
|
||||||
### release
|
|
||||||
|
|
||||||
If it's necessary to pause sending setpoint messages, use the `simple_offboard/release` service:
|
|
||||||
|
|
||||||
```python
|
|
||||||
release = rospy.ServiceProxy('simple_offboard/release', Trigger)
|
|
||||||
|
|
||||||
release()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Additional materials
|
## Additional materials
|
||||||
|
|
||||||
* [ArUco-based position estimation and navigation](aruco.md).
|
* [ArUco-based position estimation and navigation](aruco.md).
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ sudo systemctl enable roscore
|
|||||||
sudo systemctl start roscore
|
sudo systemctl start roscore
|
||||||
```
|
```
|
||||||
|
|
||||||
### Web tools setup
|
|
||||||
|
|
||||||
Install any web server to serve Clover's web tools (`~/.ros/www` directory), e. g. Monkey:
|
Install any web server to serve Clover's web tools (`~/.ros/www` directory), e. g. Monkey:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -160,11 +158,3 @@ sudo cp ~/catkin_ws/src/clover/builder/assets/monkey.service /etc/systemd/system
|
|||||||
sudo systemctl enable monkey
|
sudo systemctl enable monkey
|
||||||
sudo systemctl start monkey
|
sudo systemctl start monkey
|
||||||
```
|
```
|
||||||
|
|
||||||
Create `~/.ros/www` using the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rosrun clover www
|
|
||||||
```
|
|
||||||
|
|
||||||
If the set of packages containing a web part (through `www` directory) is changed, the above command also must be run.
|
|
||||||
|
|||||||
@@ -207,9 +207,9 @@ def pose_update(pose):
|
|||||||
# Processing new data of copter's position
|
# Processing new data of copter's position
|
||||||
pass
|
pass
|
||||||
|
|
||||||
rospy.Subscriber('mavros/local_position/pose', PoseStamped, pose_update)
|
rospy.Subscriber('/mavros/local_position/pose', PoseStamped, pose_update)
|
||||||
rospy.Subscriber('mavros/local_position/velocity', TwistStamped, velocity_update)
|
rospy.Subscriber('/mavros/local_position/velocity', TwistStamped, velocity_update)
|
||||||
rospy.Subscriber('mavros/battery', BatteryState, battery_update)
|
rospy.Subscriber('/mavros/battery', BatteryState, battery_update)
|
||||||
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
|
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
|
||||||
|
|
||||||
rospy.spin()
|
rospy.spin()
|
||||||
@@ -349,7 +349,7 @@ from pymavlink import mavutil
|
|||||||
from mavros_msgs.srv import CommandLong
|
from mavros_msgs.srv import CommandLong
|
||||||
from mavros_msgs.msg import State
|
from mavros_msgs.msg import State
|
||||||
|
|
||||||
send_command = rospy.ServiceProxy('mavros/cmd/command', CommandLong)
|
send_command = rospy.ServiceProxy('/mavros/cmd/command', CommandLong)
|
||||||
|
|
||||||
def calibrate_gyro():
|
def calibrate_gyro():
|
||||||
rospy.loginfo('Calibrate gyro')
|
rospy.loginfo('Calibrate gyro')
|
||||||
@@ -480,11 +480,3 @@ param_set(param_id='COM_FLTMODE1', value=ParamValue(integer=8))
|
|||||||
# Set parameter of type FLOAT:
|
# Set parameter of type FLOAT:
|
||||||
param_set(param_id='MPC_Z_P', value=ParamValue(real=1.5))
|
param_set(param_id='MPC_Z_P', value=ParamValue(real=1.5))
|
||||||
```
|
```
|
||||||
|
|
||||||
### # {#is-simulation}
|
|
||||||
|
|
||||||
Check, if the code is running inside a [Gazebo simulation](simulation.md):
|
|
||||||
|
|
||||||
```python
|
|
||||||
is_simulation = rospy.get_param('/use_sim_time', False)
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ If you are using the marker map, where the markers have equal distances along th
|
|||||||
|
|
||||||
After you fill out the map, you need to apply it. To do it, edit the file `aruco.launch`, located in `~/catkin_ws/src/clover/clover/launch/`. Change the line `<param name="map" value="$(find aruco_pose)/map/map_name.txt"/>`, where `map_name.txt` is the name of your map file.
|
After you fill out the map, you need to apply it. To do it, edit the file `aruco.launch`, located in `~/catkin_ws/src/clover/clover/launch/`. Change the line `<param name="map" value="$(find aruco_pose)/map/map_name.txt"/>`, where `map_name.txt` is the name of your map file.
|
||||||
|
|
||||||
If you are using markers that are not linked to horizontal surfaces (floor, ceiling), you must blank the `placement` argument in the same file:
|
If you are using markers that are not linked to horizontal surfaces (floor, ceiling), you must disable the parameter `known_tilt` both in the module `aruco_detect` and `aruco_map` in the same file. To do it automatically, enter:
|
||||||
|
|
||||||
```xml
|
```bash
|
||||||
<arg name="placement" default=""/>
|
sed -i "/known_tilt/s/value=\".*\"/value=\"\"/" /home/pi/catkin_ws/src/clover/clover/launch/aruco.launch
|
||||||
```
|
```
|
||||||
|
|
||||||
After all the settings, call `sudo systemctl restart clover` to restart the `clover` service.
|
After all the settings, call `sudo systemctl restart clover` to restart the `clover` service.
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ rospy.spin()
|
|||||||
|
|
||||||
Скрипт будет занимать 100% процессора. Для искусственного замедления работы скрипта можно запустить [throttling](http://wiki.ros.org/topic_tools/throttle) кадров с камеры, например, в 5 Гц (`main_camera.launch`):
|
Скрипт будет занимать 100% процессора. Для искусственного замедления работы скрипта можно запустить [throttling](http://wiki.ros.org/topic_tools/throttle) кадров с камеры, например, в 5 Гц (`main_camera.launch`):
|
||||||
|
|
||||||
> **Note** Начиная с версии [образа](image.md) **0.24** топик `image_raw_throttled` доступен без дополнительной конфигурации.
|
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<node pkg="topic_tools" name="cam_throttle" type="throttle"
|
<node pkg="topic_tools" name="cam_throttle" type="throttle"
|
||||||
args="messages main_camera/image_raw 5.0 main_camera/image_raw_throttled"/>
|
args="messages main_camera/image_raw 5.0 main_camera/image_raw_throttled"/>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLScE2kN5dO2OYNSM8hOYzOa5Qvh2uDdd9Fjx8OnL1W93bfEBgw/viewform).
|
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLScE2kN5dO2OYNSM8hOYzOa5Qvh2uDdd9Fjx8OnL1W93bfEBgw/viewform).
|
||||||
|
|
||||||
Дедлайн подачи заявок: 30 ноября 2022 года.
|
Дедлайн подачи заявок: 1 сентября 2022 года.
|
||||||
|
|
||||||
### Призы
|
### Призы
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLSdelVy6yQ1iN6u88KeiEIKGj7gGaM0xccSt2tiYKB46ICmjkQ/viewform).
|
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLSdelVy6yQ1iN6u88KeiEIKGj7gGaM0xccSt2tiYKB46ICmjkQ/viewform).
|
||||||
|
|
||||||
Дедлайн подачи заявок: 30 ноября 2022 года.
|
Дедлайн подачи заявок: 1 сентября 2022 года.
|
||||||
|
|
||||||
### Призы
|
### Призы
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
|
|
||||||
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLSdf2Q68X4hPnFE9f3EP95AxPNnzHKqIsFHtTRT6EBKiH93wzg/viewform).
|
Прием заявок осуществляется через [Google Форму](https://docs.google.com/forms/d/e/1FAIpQLSdf2Q68X4hPnFE9f3EP95AxPNnzHKqIsFHtTRT6EBKiH93wzg/viewform).
|
||||||
|
|
||||||
Дедлайн подачи заявок: 30 ноября 2022 года
|
Дедлайн подачи заявок: 1 сентября 2022 года
|
||||||
|
|
||||||
### Призы
|
### Призы
|
||||||
|
|
||||||
|
|||||||
@@ -305,16 +305,6 @@ rosservice call /land "{}"
|
|||||||
|
|
||||||
> **Caution** В более новых версиях PX4 коптер выйдет из режима LAND в ручной режим, если сильно перемещать стики.
|
> **Caution** В более новых версиях PX4 коптер выйдет из режима LAND в ручной режим, если сильно перемещать стики.
|
||||||
|
|
||||||
### release
|
|
||||||
|
|
||||||
В случае необходимости приостановки отправки setpoint-сообщений, используйте сервис `simple_offboard/release`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
release = rospy.ServiceProxy('simple_offboard/release', Trigger)
|
|
||||||
|
|
||||||
release()
|
|
||||||
```
|
|
||||||
|
|
||||||
## Дополнительные материалы
|
## Дополнительные материалы
|
||||||
|
|
||||||
* [Полеты в поле ArUco-маркеров](aruco.md).
|
* [Полеты в поле ArUco-маркеров](aruco.md).
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ sudo systemctl enable roscore
|
|||||||
sudo systemctl start roscore
|
sudo systemctl start roscore
|
||||||
```
|
```
|
||||||
|
|
||||||
### Конфигурация веб-инструментов
|
|
||||||
|
|
||||||
Установите любой веб-сервер, чтобы раздавать веб-инструменты Клевера (директория `~/.ros/www`), например, Monkey:
|
Установите любой веб-сервер, чтобы раздавать веб-инструменты Клевера (директория `~/.ros/www`), например, Monkey:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -160,11 +158,3 @@ sudo cp ~/catkin_ws/src/clover/builder/assets/monkey.service /etc/systemd/system
|
|||||||
sudo systemctl enable monkey
|
sudo systemctl enable monkey
|
||||||
sudo systemctl start monkey
|
sudo systemctl start monkey
|
||||||
```
|
```
|
||||||
|
|
||||||
Создайте директорию `~/.ros/www` следующей командой:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rosrun clover www
|
|
||||||
```
|
|
||||||
|
|
||||||
При обновлении набора пакетов, содержащих веб-часть (через каталог `www`), также необходимо выполнение данной команды.
|
|
||||||
|
|||||||
@@ -217,9 +217,9 @@ def pose_update(pose):
|
|||||||
# Обработка новых данных о позиции коптера
|
# Обработка новых данных о позиции коптера
|
||||||
pass
|
pass
|
||||||
|
|
||||||
rospy.Subscriber('mavros/local_position/pose', PoseStamped, pose_update)
|
rospy.Subscriber('/mavros/local_position/pose', PoseStamped, pose_update)
|
||||||
rospy.Subscriber('mavros/local_position/velocity', TwistStamped, velocity_update)
|
rospy.Subscriber('/mavros/local_position/velocity', TwistStamped, velocity_update)
|
||||||
rospy.Subscriber('mavros/battery', BatteryState, battery_update)
|
rospy.Subscriber('/mavros/battery', BatteryState, battery_update)
|
||||||
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
|
rospy.Subscriber('mavros/rc/in', RCIn, rc_callback)
|
||||||
|
|
||||||
rospy.spin()
|
rospy.spin()
|
||||||
@@ -360,7 +360,7 @@ from pymavlink import mavutil
|
|||||||
from mavros_msgs.srv import CommandLong
|
from mavros_msgs.srv import CommandLong
|
||||||
from mavros_msgs.msg import State
|
from mavros_msgs.msg import State
|
||||||
|
|
||||||
send_command = rospy.ServiceProxy('mavros/cmd/command', CommandLong)
|
send_command = rospy.ServiceProxy('/mavros/cmd/command', CommandLong)
|
||||||
|
|
||||||
def calibrate_gyro():
|
def calibrate_gyro():
|
||||||
rospy.loginfo('Calibrate gyro')
|
rospy.loginfo('Calibrate gyro')
|
||||||
@@ -491,11 +491,3 @@ param_set(param_id='COM_FLTMODE1', value=ParamValue(integer=8))
|
|||||||
# Изменить параметр типа FLOAT:
|
# Изменить параметр типа FLOAT:
|
||||||
param_set(param_id='MPC_Z_P', value=ParamValue(real=1.5))
|
param_set(param_id='MPC_Z_P', value=ParamValue(real=1.5))
|
||||||
```
|
```
|
||||||
|
|
||||||
### # {#is-simulation}
|
|
||||||
|
|
||||||
Проверить, что код запущен в [симуляции Gazebo](simulation.md):
|
|
||||||
|
|
||||||
```python
|
|
||||||
is_simulation = rospy.get_param('/use_sim_time', False)
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ sed -i "/direction_y/s/default=\".*\"/default=\"\"/" /home/pi/catkin_ws/src/clov
|
|||||||
|
|
||||||
После того, как вы заполните карту, необходимо применить ее — для этого отредактируйте файл `aruco.launch`, расположенный в `~/catkin_ws/src/clover/clover/launch/`. Измените в нем строку `<param name="map" value="$(find aruco_pose)/map/map_name.txt"/>`, где `map_name.txt` название вашего файла с картой.
|
После того, как вы заполните карту, необходимо применить ее — для этого отредактируйте файл `aruco.launch`, расположенный в `~/catkin_ws/src/clover/clover/launch/`. Измените в нем строку `<param name="map" value="$(find aruco_pose)/map/map_name.txt"/>`, где `map_name.txt` название вашего файла с картой.
|
||||||
|
|
||||||
При использовании маркеров, не привязанных к горизонтальным плоскостям (пол, потолок), необходимо также сделать пустым значение аргумента `placement` в том же файле:
|
При использовании маркеров, не привязанных к горизонтальным плоскостям(пол, потолок), необходимо отключить параметр `known_tilt` как в модуле `aruco_detect`, так и в модуле `aruco_map` в том же файле. Для того, чтобы сделать это автоматически, введите:
|
||||||
|
|
||||||
```xml
|
```bash
|
||||||
<arg name="placement" default=""/>
|
sed -i "/known_tilt/s/value=\".*\"/value=\"\"/" /home/pi/catkin_ws/src/clover/clover/launch/aruco.launch
|
||||||
```
|
```
|
||||||
|
|
||||||
После всех настроек вызовите `sudo systemctl restart clover` для перезагрузки сервиса `clover`.
|
После всех настроек вызовите `sudo systemctl restart clover` для перезагрузки сервиса `clover`.
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
{ "from": "snippets.html", "to": "ru/snippets.html" },
|
{ "from": "snippets.html", "to": "ru/snippets.html" },
|
||||||
{ "from": "camera_frame.html", "to": "ru/camera_setup.html" },
|
{ "from": "camera_frame.html", "to": "ru/camera_setup.html" },
|
||||||
{ "from": "ru/camera_frame.html", "to": "camera_setup.html" },
|
{ "from": "ru/camera_frame.html", "to": "camera_setup.html" },
|
||||||
{ "from": "camera.html", "to": "en/camera.html" },
|
{ "from": "camera.html", "to": "ru/camera.html" },
|
||||||
{ "from": "led.html", "to": "en/leds.html" },
|
{ "from": "led.html", "to": "en/leds.html" },
|
||||||
{ "from": "leds.html", "to": "ru/leds.html" },
|
{ "from": "leds.html", "to": "ru/leds.html" },
|
||||||
{ "from": "rviz.html", "to": "ru/rviz.html" },
|
{ "from": "rviz.html", "to": "ru/rviz.html" },
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
{ "from": "firmware/", "to": "en/firmware.html" },
|
{ "from": "firmware/", "to": "en/firmware.html" },
|
||||||
{ "from": "simple_offboard/", "to": "en/simple_offboard.html" },
|
{ "from": "simple_offboard/", "to": "en/simple_offboard.html" },
|
||||||
{ "from": "offboard/", "to": "en/simple_offboard.html" },
|
{ "from": "offboard/", "to": "en/simple_offboard.html" },
|
||||||
{ "from": "camera/", "to": "en/camera.html" },
|
{ "from": "camera/", "to": "ru/camera.html" },
|
||||||
{ "from": "snippets/", "to": "ru/snippets.html" },
|
{ "from": "snippets/", "to": "ru/snippets.html" },
|
||||||
{ "from": "optical_flow/", "to": "ru/optical_flow.html" },
|
{ "from": "optical_flow/", "to": "ru/optical_flow.html" },
|
||||||
{ "from": "laser/", "to": "ru/laser.html" },
|
{ "from": "laser/", "to": "ru/laser.html" },
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ find_package(catkin REQUIRED)
|
|||||||
|
|
||||||
catkin_package()
|
catkin_package()
|
||||||
|
|
||||||
catkin_install_python(PROGRAMS src/update
|
install(DIRECTORY launch DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})
|
||||||
|
|
||||||
|
catkin_install_python(PROGRAMS main.py
|
||||||
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ Note: you should configure your web server to make it follow symlinks.
|
|||||||
|
|
||||||
## Instructions
|
## Instructions
|
||||||
|
|
||||||
* Run `update` script and it will generate the symlinks and index file: `rosrun roswww_static update`.
|
* Run `main.py` node and it will generate the symlinks and index file.
|
||||||
* Point your static web server path to `~/.ros/www`.
|
* Point your static web server path to `~/.ros/www`.
|
||||||
|
|
||||||
You can rerun `update` if the list of installed packages changes.
|
You can rerun `main.py` if the list of installed packages changes.
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
Parameters are passed through environment variables:
|
* `index` – path for index page, otherwise packages list would be generated.
|
||||||
|
* `default_package` – if set then the index page would redirect to this package's page.
|
||||||
* `ROSWWW_INDEX` – path for index page, otherwise packages list would be generated.
|
|
||||||
* `ROSWWW_DEFAULT` – if set then the index page would redirect to this package's page.
|
|
||||||
|
|||||||
6
roswww_static/launch/example.launch
Normal file
6
roswww_static/launch/example.launch
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<launch>
|
||||||
|
<node pkg="roswww_static" name="roswww_static" type="main.py" clear_params="true" output="screen">
|
||||||
|
<!-- <param name="index" value="$(find my_package)/www/index.html"/> -->
|
||||||
|
<!-- <param name="default_package" value="my_package"/> -->
|
||||||
|
</node>
|
||||||
|
</launch>
|
||||||
@@ -13,15 +13,17 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import rospy
|
||||||
import rospkg
|
import rospkg
|
||||||
|
|
||||||
|
rospy.init_node('roswww_static')
|
||||||
|
|
||||||
rospack = rospkg.RosPack()
|
rospack = rospkg.RosPack()
|
||||||
|
|
||||||
www = rospkg.get_ros_home() + '/www'
|
www = rospkg.get_ros_home() + '/www'
|
||||||
index_file = os.environ.get('ROSWWW_INDEX')
|
index_file = rospy.get_param('~index_file', None)
|
||||||
default_package = os.environ.get('ROSWWW_DEFAULT')
|
default_package = rospy.get_param('~default_package', None)
|
||||||
|
|
||||||
print('using www dir: ' + www)
|
|
||||||
shutil.rmtree(www, ignore_errors=True) # reset www directory content
|
shutil.rmtree(www, ignore_errors=True) # reset www directory content
|
||||||
os.mkdir(www)
|
os.mkdir(www)
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ index = '<h1>Packages list</h1>\n<ul>\n'
|
|||||||
for name in packages:
|
for name in packages:
|
||||||
path = rospack.get_path(name)
|
path = rospack.get_path(name)
|
||||||
if os.path.exists(path + '/www'):
|
if os.path.exists(path + '/www'):
|
||||||
print('found www path for %s package' % name)
|
rospy.loginfo('found www path for %s package', name)
|
||||||
os.symlink(path + '/www', www + '/' + name)
|
os.symlink(path + '/www', www + '/' + name)
|
||||||
index += '<li><a href="{name}/">{name}</a></li>'.format(name=name)
|
index += '<li><a href="{name}/">{name}</a></li>'.format(name=name)
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ if default_package is not None:
|
|||||||
redirect_html = '<meta http-equiv=refresh content="0; url={name}/">'.format(name=default_package)
|
redirect_html = '<meta http-equiv=refresh content="0; url={name}/">'.format(name=default_package)
|
||||||
open(www + '/index.html', 'w').write(redirect_html)
|
open(www + '/index.html', 'w').write(redirect_html)
|
||||||
elif index_file is not None:
|
elif index_file is not None:
|
||||||
print('symlinking index file')
|
rospy.loginfo('symlinking index file')
|
||||||
os.symlink(index_file, www + '/index.html')
|
os.symlink(index_file, www + '/index.html')
|
||||||
else:
|
else:
|
||||||
open(www + '/index.html', 'w').write(index)
|
open(www + '/index.html', 'w').write(index)
|
||||||
Reference in New Issue
Block a user